Skip to content

bug: httpBatchLink's getFetch fails on bun runtime #3906

@j4orz

Description

@j4orz

Provide environment information

System:
    OS: macOS 13.2.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9980HK CPU @ 2.40GHz
    Memory: 5.96 GB / 32.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.14.2 - ~/.local/share/nvm/v18.14.2/bin/node
    npm: 9.5.0 - ~/.local/share/nvm/v18.14.2/bin/npm
  Browsers:
    Brave Browser: 110.1.48.171
    Safari: 16.3
  npmPackages:
    @trpc/client: ^10.13.2 => 10.13.2
    @trpc/server: ^10.13.2 => 10.13.2

Describe the bug

I was looking to set up a toy example of trpc on bun for #3458. The client is failing to run because trpc's internal getFetch is binding globalThis.fetch to globalThis0 (I'm assuming because the internal fetch implementation accesses other stuff off the globalThis object? Running the client with bun errors with

TypeError: globalThis.fetch.bind is not a function. (In 'globalThis.fetch.bind(globalThis)', 'globalThis.fetch.bind' is undefined)

I verified this by logging fetch.bind (expecting to see a function) and fetch.prototype (expecting to see Function.prototype) but both debug logs print undefined

I tried modifying trpc's source locally and not binding fetch to globalThis, but then the client fails with a generic "fetch failed" error.

18 |     }
19 |     constructor(message, opts){
20 |         const cause = opts?.cause;
21 |         // eslint-disable-next-line @typescript-eslint/ban-ts-comment
22 |         // @ts-ignore https://github.com/tc39/proposal-error-cause
23 |         super(message, {
            ^
TRPCClientError: fetch() failed
      at new TRPCClientError (/Users/jeff/Documents/repos/trpc/examples/bun/node_modules/@trpc/client/dist/transformResult-6fb67924.mjs:23:8)
      at from (/Users/jeff/Documents/repos/trpc/examples/bun/node_modules/@trpc/client/dist/transformResult-6fb67924.mjs:13:15)
      at /Users/jeff/Documents/repos/trpc/examples/bun/node_modules/@trpc/client/dist/links/httpBatchLink.mjs:200:63

Link to reproduction

#3905 (stackblitz does not provide support for bun runtimes)

To reproduce

  1. Run bun init to start a bun project
  2. Add the following three files are in src/
  3. Run client.ts with bun src/client.ts

client.ts (failing code)

import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './router.js';

const client = createTRPCProxyClient<AppRouter>({
  links: [
    httpBatchLink({ // ❌ httpBatchLink > resolveHTTPLinkOptions > getFetch is failing
      url: 'http://localhost:3000/trpc',
    }),
  ],
});

const bilbo = await client.getUserById.query('id_bilbo');
// => { id: 'id_bilbo', name: 'Bilbo' };
const frodo = await client.createUser.mutate({ name: 'Frodo' });
// => { id: 'id_frodo', name: 'Frodo' };

router.ts

import { initTRPC } from '@trpc/server';
import { z } from 'zod';

type User = {
  id: string;
  name: string;
  bio?: string;
};
const users: Record<string, User> = {};

users['id_bilbo'] =  {
  id: 'id_bilbo',
  name: 'Bilbo',
}

export const t = initTRPC.create();


export const appRouter = t.router({
  getUserById: t.procedure.input(z.string()).query(({ input }) => {
    return users[input]; // input type is string
  }),
  createUser: t.procedure
    // validate input with Zod
    .input(
      z.object({
        name: z.string().min(3),
        bio: z.string().max(142).optional(),
      }),
    )
    .mutation(({ input }) => {
      const id = Date.now().toString();
      const user: User = { id, ...input };
      users[user.id] = user;
      return user;
    }),
});

// export type definition of API
export type AppRouter = typeof appRouter;

router.ts

import { fetchRequestHandler } from '@trpc/server/adapters/fetch';
import { appRouter } from './router.js';

const server = Bun.serve({
  port: 3000,
  fetch(req) {

    return fetchRequestHandler({
      endpoint: '/trpc',
      req: req,
      router: appRouter,
          createContext: () => ({}),

    });
  },
});

console.log(`Listening on http://localhost:${server.port}...`);

Additional information

If the bug is confirmed and reproducible, and on trpc's side, we cannot indeed remove the .bind due to fetch's dependency on it, it might actually be an issue with the bun runtime itself. I can also follow up with @Jarred-Sumner on the bun-side, as I might be interested in contributing over there as well.

image

No response

👨‍👧‍👦 Contributing

  • 🙋‍♂️ Yes, I'd be down to file a PR fixing this bug!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions