Skip to content

fix(client-nuxt): preserve AbortSignal, FormData, and ReadableStream in unwrapRefs#3614

Merged
mrlubos merged 3 commits intomainfrom
copilot/fix-unwrap-refs-abortsignal
Mar 18, 2026
Merged

fix(client-nuxt): preserve AbortSignal, FormData, and ReadableStream in unwrapRefs#3614
mrlubos merged 3 commits intomainfrom
copilot/fix-unwrap-refs-abortsignal

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 18, 2026

unwrapRefs only special-cased Blob and Headers, causing browser built-ins like AbortSignal to fall through to the object-iteration path and get copied into a plain {}. This broke TanStack Vue Query integration — the signal injected by queryFn was silently destroyed before reaching fetch, resulting in a TypeError.

Changes

  • bundle/utils.ts: Extend the pass-through guard to cover AbortSignal, FormData, and ReadableStream
// before
if (value instanceof Blob) {
  return value as UnwrapRefs<T>;
}

// after
if (
  value instanceof Blob ||
  value instanceof FormData ||
  value instanceof ReadableStream ||
  value instanceof AbortSignal
) {
  return value as UnwrapRefs<T>;
}
  • __tests__/utils.test.ts: Add test cases asserting identity preservation for AbortSignal (standalone and nested in object), FormData, and ReadableStream
  • Snapshots: Updated 12 generated snapshot files across all client-nuxt and sse-nuxt variants
Original prompt

This section details on the original issue you should resolve

<issue_title>client-nuxt: unwrapRefs destroys AbortSignal, breaking TanStack Vue Query</issue_title>
<issue_description>## Description

The unwrapRefs utility in the generated @hey-api/client-nuxt client handles Blob and Headers as pass-through cases, but does not handle AbortSignal. This causes all TanStack Vue Query requests to fail because the signal passed from queryFn gets destructured into a plain {} object, which native fetch rejects.

Reproduction

  1. Generate a client with @hey-api/client-nuxt and @tanstack/vue-query plugin
  2. Use any generated query options function with useQuery:
const { data } = useQuery(deskControllerFindAllApiV1Options({}));
  1. The request fails with:
TypeError: Failed to execute 'fetch' on 'Window':
Failed to read the 'signal' property from 'RequestInit':
Failed to convert value to 'AbortSignal'.

Root cause

In the generated client/utils.gen.ts, unwrapRefs has special cases for Blob and Headers but not AbortSignal:

export const unwrapRefs = <T>(value: T): UnwrapRefs<T> => {
  if (value === null || typeof value !== "object" || value instanceof Headers) {
    return (isRef(value) ? unref(value) : value) as UnwrapRefs<T>;
  }

  if (value instanceof Blob) {
    return value as UnwrapRefs<T>;
  }

  // ... falls through to:
  const result: Record<string, unknown> = {};
  for (const key in value) {
    result[key] = unwrapRefs(value[key] as T);
  }
  return result as UnwrapRefs<T>;
};

When AbortSignal reaches the fallthrough case, its properties are copied into a plain object. Native fetch then rejects it because it's no longer an AbortSignal instance.

Flow

  1. TanStack Vue Query calls queryFn with { queryKey, signal }
  2. Generated queryFn passes signal to the SDK client method
  3. executeFetchFn calls unwrapRefs(opts) — this recurses into opts.signal
  4. unwrapRefs(signal) copies AbortSignal properties into {} → no longer an AbortSignal
  5. ofetch passes the plain object to native fetchTypeError

Suggested fix

Add AbortSignal to the pass-through checks, alongside Blob:

if (value instanceof Blob || value instanceof AbortSignal) {
  return value as UnwrapRefs<T>;
}

There may be other browser built-in objects that should also be passed through (e.g., FormData, ReadableStream).</issue_description>

Comments on the Issue (you are @copilot in this section)


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

@bolt-new-by-stackblitz
Copy link
Copy Markdown

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

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 18, 2026

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

Project Deployment Actions Updated (UTC)
hey-api-docs Ready Ready Preview, Comment Mar 18, 2026 1:34am

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: 129afa0

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

…hrough in unwrapRefs

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copilot AI changed the title [WIP] [CLIENT-123] Fix unwrapRefs to handle AbortSignal correctly fix(client-nuxt): preserve AbortSignal, FormData, and ReadableStream in unwrapRefs Mar 18, 2026
Copilot AI requested a review from mrlubos March 18, 2026 01:19
@mrlubos mrlubos marked this pull request as ready for review March 18, 2026 01:33
@pullfrog
Copy link
Copy Markdown
Contributor

pullfrog Bot commented Mar 18, 2026

Error

agent completed without reporting progress

Pullfrog  | Rerun failed job ➔View workflow run | Triggered by Pullfrogpullfrog.com𝕏

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Mar 18, 2026

Open in StackBlitz

@hey-api/codegen-core

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

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

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

@hey-api/nuxt

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

@hey-api/openapi-ts

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

@hey-api/shared

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

@hey-api/types

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

@hey-api/vite-plugin

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

commit: 129afa0

@mrlubos mrlubos merged commit 5f3a5a0 into main Mar 18, 2026
10 checks passed
@mrlubos mrlubos deleted the copilot/fix-unwrap-refs-abortsignal branch March 18, 2026 01:40
@hey-api hey-api Bot mentioned this pull request Mar 17, 2026
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. bug 🔥 Broken or incorrect behavior. labels Mar 18, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 18, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 39.08%. Comparing base (c77746e) to head (129afa0).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3614      +/-   ##
==========================================
+ Coverage   39.07%   39.08%   +0.01%     
==========================================
  Files         495      495              
  Lines       18450    18454       +4     
  Branches     5479     5477       -2     
==========================================
+ Hits         7209     7213       +4     
  Misses       9073     9073              
  Partials     2168     2168              
Flag Coverage Δ
unittests 39.08% <100.00%> (+0.01%) ⬆️

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

☔ View full report in Codecov by Sentry.
📢 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug 🔥 Broken or incorrect behavior. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

client-nuxt: unwrapRefs destroys AbortSignal, breaking TanStack Vue Query

2 participants