Skip to content

Allow specifying type-safe meta values#3996

Merged
mrlubos merged 8 commits into
hey-api:mainfrom
matthewjamesadam:matt/TypesafeMetaValues
Jun 8, 2026
Merged

Allow specifying type-safe meta values#3996
mrlubos merged 8 commits into
hey-api:mainfrom
matthewjamesadam:matt/TypesafeMetaValues

Conversation

@matthewjamesadam

@matthewjamesadam matthewjamesadam commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Closes #3997

Motivation

The @hey-api/sdk plugin generates a meta field on Options hardcoded to
Record<string, unknown>, which can be used as a side-channel for data to
interceptors/middleware. However this value is in effect untyped which can lead to
bugs:

await getFoo({ meta: { retryy: false } }); // typo'd key — compiles
await getFoo({ meta: { timeout: '30s' } }); // wrong type — compiles

This issue has been previously reported here: #2425 (comment)

Solution

hey-api defines the meta property to be of type ClientMeta, which by default is Record<string, unknown>. Client applications can define this type to a concrete value via ambient declarations — the canonical
TypeScript extension-point pattern (same as vue-router's RouteMeta):

declare module '@hey-api/client-fetch' {
  interface ClientMeta {
    timeout?: number;
  }
}

Unaugmented → Meta resolves to Record<string, unknown> — identical to today's behavior, fully backward compatible.
Augmented → meta becomes strict: unknown keys, wrong types, and primitives are all rejected at the call site.

@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. feature 🚀 Feature request. labels Jun 5, 2026
@vercel

vercel Bot commented Jun 5, 2026

Copy link
Copy Markdown

@matthewjamesadam is attempting to deploy a commit to the Hey API Team on Vercel.

A member of the Team first needs to authorize it.

@changeset-bot

changeset-bot Bot commented Jun 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a75c5a6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@hey-api/openapi-ts Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 39.06%. Comparing base (174e42f) to head (b7ee3fd).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3996      +/-   ##
==========================================
- Coverage   39.07%   39.06%   -0.02%     
==========================================
  Files         610      610              
  Lines       21561    21561              
  Branches     6348     6348              
==========================================
- Hits         8426     8423       -3     
- Misses      10697    10700       +3     
  Partials     2438     2438              
Flag Coverage Δ
unittests 39.06% <ø> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pullfrog pullfrog Bot 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.

ℹ️ Minor suggestion — one inline note about the generated JSDoc.

Reviewed changes — introduces an augmentable ClientMeta interface and Meta conditional type so the SDK's meta option becomes type-safe at the call site while remaining fully backward compatible.

  • Add ClientMeta and Meta to client-core/bundle/types.ts — the single source of truth; Meta resolves to Record<string, unknown> when unaugmented and the augmented ClientMeta otherwise.
  • Add ClientMeta and Meta to custom-client/src/core/types.ts — same pattern for the standalone @hey-api/custom-client package.
  • Re-export from all 7 client bundle indexesclient-fetch, client-axios, client-ofetch, client-ky, client-nuxt, client-next, client-angular.
  • Add Meta symbol to the SDK plugin and wire it into typeOptions.ts — the meta property on the generated Options type changes from meta?: Record<string, unknown> to meta?: Meta.
  • Add type-level regression test (clientMeta.type-test.ts) — covers augmented (strict typing) and unaugmented (backward-compatible) cases.
  • Document the feature under a new "Metadata" section in the SDK plugin docs.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Comment thread packages/openapi-ts/src/plugins/@hey-api/client-core/bundle/types.ts Outdated
@mrlubos

mrlubos commented Jun 6, 2026

Copy link
Copy Markdown
Member

@matthewjamesadam any thoughts on inlining the Meta type instead of defining it as a separate export?

@matthewjamesadam

matthewjamesadam commented Jun 7, 2026

Copy link
Copy Markdown
Contributor Author

@matthewjamesadam any thoughts on inlining the Meta type instead of defining it as a separate export?

@mrlubos I'm definitely open to changing this -- just so I make sure I understand, are you proposing that instead of exporting Meta in the types file:

export type Meta = keyof ClientMeta extends never ? Record<string, unknown> : ClientMeta;

and using it in the sdk file:

export type Options<...> {
  ...
  meta?: Meta;
}

we instead inline it in the sdk file:

export type Options<...> {
  ...
  meta?: keyof ClientMeta extends never ? Record<string, unknown> : ClientMeta;
}

If that's what you're saying then I think that makes sense!

@mrlubos

mrlubos commented Jun 7, 2026

Copy link
Copy Markdown
Member

@matthewjamesadam yes. Is there any other use case for this type beyond Options.meta?

@mrlubos

mrlubos commented Jun 8, 2026

Copy link
Copy Markdown
Member

@pullfrog can you perform the discussed change above? After you're done, update snapshots (pnpm test:update) and examples (pnpm examples:generate)

@pullfrog

pullfrog Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Done! Inlined the Meta type directly into Options.meta as a conditional type expression instead of exporting it separately.

Changes:

  • Removed Meta type export from client-core/bundle/types.ts, custom-client/src/types.ts, and all 8 client bundle index.ts files
  • Replaced Meta symbol in sdk/symbols.ts with ClientMeta symbol
  • Updated sdk/shared/typeOptions.ts to generate the conditional type inline: meta?: keyof ClientMeta extends never ? Record&lt;string, unknown&gt; : ClientMeta
  • Updated all snapshots and regenerated all 15 examples — all tests pass, ESLint clean
Task list (5/5 completed)
  • Read PR comments and diff to understand the discussed change
  • Implement the discussed change - inline Meta type
  • Update snapshots (pnpm test:update)
  • Generate examples (pnpm examples:generate)
  • Commit and push changes

Pullfrog  | View workflow run | via Pullfrog | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jun 8, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jun 8, 2026

Copy link
Copy Markdown

Open in StackBlitz

@hey-api/codegen-core

npm i https://pkg.pr.new/@hey-api/codegen-core@3996

@hey-api/json-schema-ref-parser

npm i https://pkg.pr.new/@hey-api/json-schema-ref-parser@3996

@hey-api/nuxt

npm i https://pkg.pr.new/@hey-api/nuxt@3996

@hey-api/openapi-ts

npm i https://pkg.pr.new/@hey-api/openapi-ts@3996

@hey-api/shared

npm i https://pkg.pr.new/@hey-api/shared@3996

@hey-api/spec-types

npm i https://pkg.pr.new/@hey-api/spec-types@3996

@hey-api/types

npm i https://pkg.pr.new/@hey-api/types@3996

@hey-api/vite-plugin

npm i https://pkg.pr.new/@hey-api/vite-plugin@3996

commit: a75c5a6

@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
web Ready Ready Preview, Comment Jun 8, 2026 4:04am

Request Review

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jun 8, 2026
@mrlubos mrlubos merged commit dc70734 into hey-api:main Jun 8, 2026
7 of 9 checks passed
@hey-api hey-api Bot mentioned this pull request Jun 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature 🚀 Feature request. lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow specifying type-safe meta values

2 participants