Skip to content

fix(sdk): drop create-only fields from read types in TypeScript emitter#4605

Merged
tothandras merged 1 commit into
mainfrom
fix/sdk-emitter-visibility-output-types
Jun 30, 2026
Merged

fix(sdk): drop create-only fields from read types in TypeScript emitter#4605
tothandras merged 1 commit into
mainfrom
fix/sdk-emitter-visibility-output-types

Conversation

@tothandras

@tothandras tothandras commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Overview

Fixes #(issue)

Notes for reviewer

Summary by CodeRabbit

  • New Features

    • Improved generated TypeScript and schema outputs for billing-related APIs, including updated credit grants, subscription add-ons, and flat-fee charge details.
    • Added better handling for read-visible properties in generated models, so response shapes more accurately reflect what users can receive.
  • Bug Fixes

    • Removed outdated fields from several request and response types and replaced them with current values.
    • Updated API key and visibility-related fields to match the latest service behavior.

@tothandras
tothandras requested a review from a team as a code owner June 30, 2026 07:08
@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a response-reachability-based read-visibility filtering mechanism to the TypeSpec TypeScript emitter. A new visibility.ts module computes which models are reachable from operation success-response bodies and gates property inclusion on Visibility.Read. The bodyProperties helper, interface emitter, and divergence computation are updated to use this filtering. Generated client schemas and types are regenerated with updated API contracts across several models.

Changes

TypeSpec emitter: read-visibility filtering

Layer / File(s) Summary
Response-reachability core
api/spec/packages/typespec-typescript/src/visibility.ts
Introduces responseReachableByProgram WeakMap, setResponseReachableModels, isReadVisible predicate (gated on Visibility.Read), computeResponseReachableModels graph walk over success-response body types, and isSuccessStatus helper covering 2xx codes, ranges, and '*' wildcards.
Emitter wiring and bodyProperties update
api/spec/packages/typespec-typescript/src/emitter.tsx, src/utils.tsx, src/interface-types.ts, src/input-variants.ts
$onEmit calls computeResponseReachableModels and setResponseReachableModels before any model walk. bodyProperties gains the isReadVisible filter. interface-types.ts and input-variants.ts switch from manual property iteration to bodyProperties.

Generated client contract updates

Layer / File(s) Summary
Updated schemas and TypeScript interfaces
api/spec/packages/aip-client-javascript/src/models/schemas.ts, src/models/types.ts
Removes currency/amount from createCreditAdjustmentRequest; replaces secret_api_key with masked_api_key (plus livemode) in AppStripe; updates CreditGrant/CreditGrantInput to expires_at/voided_at/status; renames amount_before_prorationamount_after_proration in ChargeFlatFee; replaces timing with timeline/active_from/active_to in SubscriptionAddon/SubscriptionAddonInput.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

release-note/bug-fix

Suggested reviewers

  • turip
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: dropping create-only fields from read types in the TypeScript emitter.
Docstring Coverage ✅ Passed Docstring coverage is 83.33% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sdk-emitter-visibility-output-types

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tothandras
tothandras enabled auto-merge (squash) June 30, 2026 07:09
@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR updates the TypeScript SDK emitter to remove create-only fields from generated read shapes. The main changes are:

  • Adds response-reachable model tracking in the emitter.
  • Filters body properties by read visibility for response models.
  • Regenerates the JavaScript SDK schemas and public model types.

Confidence Score: 4/5

The generated request input path needs a fix before merging.

  • Read-shape filtering is now shared with input variant emission.
  • Valid create/update payload fields can disappear from generated SDK request types.
  • The response-reachability setup itself appears ordered correctly.

api/spec/packages/typespec-typescript/src/interface-types.ts, api/spec/packages/typespec-typescript/src/input-variants.ts, api/spec/packages/typespec-typescript/src/utils.tsx

Important Files Changed

Filename Overview
api/spec/packages/typespec-typescript/src/visibility.ts Adds per-program response reachability and read-visibility helpers for generated model shapes.
api/spec/packages/typespec-typescript/src/utils.tsx Expands bodyProperties() from payload-property filtering to read-shape filtering.
api/spec/packages/typespec-typescript/src/interface-types.ts Uses the new filtered body property helper for both output interfaces and input variants.
api/spec/packages/typespec-typescript/src/input-variants.ts Runs input divergence detection over the newly read-filtered body properties.
api/spec/packages/typespec-typescript/src/emitter.tsx Initializes response reachability before the SDK schema and type walkers run.
api/spec/packages/aip-client-javascript/src/models/types.ts Regenerated model types drop create-only read fields, but request input variants also lose valid request fields.
api/spec/packages/aip-client-javascript/src/models/schemas.ts Regenerated schemas remove create-only fields from read schemas.

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
api/spec/packages/typespec-typescript/src/interface-types.ts:50
**Input Fields Become Read Fields**

`interfaceBody` also emits `...Input` variants, but this call now uses `bodyProperties()`, which filters create/update-only properties from any response-reachable model. For models used in both responses and requests, such as `CreditGrant` and `SubscriptionAddon`, valid request fields like `expires_after`, `key`, and `timing` disappear from the generated input types, so SDK callers cannot type valid create/update payloads without casts.

Reviews (1): Last reviewed commit: "fix(sdk): drop create-only fields from r..." | Re-trigger Greptile

if (isHttpEnvelopeProperty(program, prop)) {
continue
}
for (const prop of bodyProperties(program, model)) {

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.

P1 Input Fields Become Read Fields

interfaceBody also emits ...Input variants, but this call now uses bodyProperties(), which filters create/update-only properties from any response-reachable model. For models used in both responses and requests, such as CreditGrant and SubscriptionAddon, valid request fields like expires_after, key, and timing disappear from the generated input types, so SDK callers cannot type valid create/update payloads without casts.

Context Used: api/spec/AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: api/spec/packages/typespec-typescript/src/interface-types.ts
Line: 50

Comment:
**Input Fields Become Read Fields**

`interfaceBody` also emits `...Input` variants, but this call now uses `bodyProperties()`, which filters create/update-only properties from any response-reachable model. For models used in both responses and requests, such as `CreditGrant` and `SubscriptionAddon`, valid request fields like `expires_after`, `key`, and `timing` disappear from the generated input types, so SDK callers cannot type valid create/update payloads without casts.

**Context Used:** api/spec/AGENTS.md ([source](https://app.greptile.com/openmeter/github/openmeterio/openmeter/-/custom-context?memory=28ba6068-00f9-4629-9b78-8e49cc802858))

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/spec/packages/typespec-typescript/src/utils.tsx`:
- Around line 110-114: The shared bodyProperties() helper is incorrectly
applying read-visibility filtering, which removes create-only properties from
input generation and can suppress ...Input variants. Update
bodyProperties(program, type) in utils.tsx to keep only the shared envelope
filtering, and move the isReadVisible logic to the response/output-specific call
sites instead. Make sure interface-types.ts and input-variants.ts continue to
use bodyProperties() for the common body shape, while any response-only
visibility filtering is applied separately where output models are produced.

In `@api/spec/packages/typespec-typescript/src/visibility.ts`:
- Around line 89-94: The recursive walk in visit is incorrectly traversing
type.derivedModels from every visited model, which pulls sibling discriminator
subtypes into the reachable read set. Update the traversal so it only follows
the actual returned subtype path (for example, by limiting derived-model descent
to the concrete response subtype or otherwise avoiding expanding all siblings
when visiting a base like Animal) while keeping the existing visibility
filtering logic in visibility.ts intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 05aa73be-c9df-414a-8912-489628bf67bd

📥 Commits

Reviewing files that changed from the base of the PR and between d10745e and efcae0e.

📒 Files selected for processing (7)
  • api/spec/packages/aip-client-javascript/src/models/schemas.ts
  • api/spec/packages/aip-client-javascript/src/models/types.ts
  • api/spec/packages/typespec-typescript/src/emitter.tsx
  • api/spec/packages/typespec-typescript/src/input-variants.ts
  • api/spec/packages/typespec-typescript/src/interface-types.ts
  • api/spec/packages/typespec-typescript/src/utils.tsx
  • api/spec/packages/typespec-typescript/src/visibility.ts
💤 Files with no reviewable changes (2)
  • api/spec/packages/aip-client-javascript/src/models/types.ts
  • api/spec/packages/aip-client-javascript/src/models/schemas.ts

Comment on lines 110 to +114
export function bodyProperties(program: Program, type: Model): ModelProperty[] {
return [...type.properties.values()].filter(
(prop) => !isHttpEnvelopeProperty(program, prop),
(prop) =>
!isHttpEnvelopeProperty(program, prop) &&
isReadVisible(program, type, prop),

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep read-visibility filtering out of the shared bodyProperties() helper.

This helper is still used by input-mode paths too: api/spec/packages/typespec-typescript/src/interface-types.ts, Line 175 builds ...Input bodies from it, and api/spec/packages/typespec-typescript/src/input-variants.ts, Line 62 uses it for divergence detection. Once a response-reachable model hides create-only props here, those props disappear from generated input types as well, and models whose only input/output difference is visibility can stop getting an ...Input variant. Splitting the read filter from the shared envelope filter would avoid that.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/spec/packages/typespec-typescript/src/utils.tsx` around lines 110 - 114,
The shared bodyProperties() helper is incorrectly applying read-visibility
filtering, which removes create-only properties from input generation and can
suppress ...Input variants. Update bodyProperties(program, type) in utils.tsx to
keep only the shared envelope filtering, and move the isReadVisible logic to the
response/output-specific call sites instead. Make sure interface-types.ts and
input-variants.ts continue to use bodyProperties() for the common body shape,
while any response-only visibility filtering is applied separately where output
models are produced.

Comment on lines +89 to +94
// Descend into subclasses too: a model-form `@discriminator` hierarchy
// returned as a response is reached through its base, and each concrete
// subtype carries its own read-side properties to filter.
for (const derived of type.derivedModels) {
visit(derived)
}

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Avoid pulling sibling subtypes into the reachable read set.

Returning one concrete subtype will currently mark its siblings reachable too. For example, visit(Dog) climbs to Animal, then Animal.derivedModels pulls in Cat, so Cat starts getting read-visibility filtering even though it never appears in a success response.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/spec/packages/typespec-typescript/src/visibility.ts` around lines 89 -
94, The recursive walk in visit is incorrectly traversing type.derivedModels
from every visited model, which pulls sibling discriminator subtypes into the
reachable read set. Update the traversal so it only follows the actual returned
subtype path (for example, by limiting derived-model descent to the concrete
response subtype or otherwise avoiding expanding all siblings when visiting a
base like Animal) while keeping the existing visibility filtering logic in
visibility.ts intact.

@tothandras
tothandras merged commit 1480f39 into main Jun 30, 2026
27 of 28 checks passed
@tothandras
tothandras deleted the fix/sdk-emitter-visibility-output-types branch June 30, 2026 07:16
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