Repository: honojs/hono (TypeScript)

Issue:
In Hono client, removeIndexString should also be applied when calling $url
### What version of Hono are you using?

4.8.3

### What runtime/platform is your app running on? (with version if possible)

Node 24

### What steps can reproduce the bug?

I'm suing the Hono client's `$url` to generate my URL. For the most part, its working perfectly but the generation of the `index` URL omits to remove the "index".

For example:
```ts
 hc<MyApp>("http://fake/").index.$url().href
```
generates `http://fake/index` where it should be `http://fake/`.

On the other side:
```ts
 hc<MyApp>("http://fake/").index.$get(...)
```
will properly fetch the `http://fake` URL.

I think I identified the issue. While for the "fetch" methods (like `$get`), the `index` string is removed:
https://github.com/honojs/hono/blob/407d1bdf64048c4876b883bc1b5cf270e12791e7/src/client/client.ts#L102

it is omitted for the `$url` method:
https://github.com/honojs/hono/blob/407d1bdf64048c4876b883bc1b5cf270e12791e7/src/client/client.ts#L159-L169

### What is the expected behavior?

_No response_

### What do you see instead?

_No response_

### Additional information

_No response_


Discussion:
Hi @jraoult 

Thank you for the issue. This is a bug! I created PR #4267. Can you review it? I've added you as a co-author since I refer to your comment.



Patch:
diff --git a/src/client/client.ts b/src/client/client.ts
index 17bd6b1ac..cd858347a 100644
--- a/src/client/client.ts
+++ b/src/client/client.ts
@@ -166,6 +166,7 @@ export const hc = <T extends Hono<any, any, any>>(
           result = result + '?' + buildSearchParams(opts.args[0].query).toString()
         }
       }
+      result = removeIndexString(result)
       return new URL(result)
     }
     if (method === 'ws') {


Test patch:
diff --git a/src/client/client.test.ts b/src/client/client.test.ts
index 69f59ca18..6537fdb02 100644
--- a/src/client/client.test.ts
+++ b/src/client/client.test.ts
@@ -339,6 +339,42 @@ describe('Basic - query, queries, form, path params, header and cookie', () => {
   })
 })
 
+describe('Basic - $url()', () => {
+  const api = new Hono().get('/', (c) => c.text('API')).get('/posts/:id', (c) => c.text('Post'))
+  const content = new Hono().get(
+    '/search',
+    validator('query', () => {
+      return { page: '1', limit: '10' }
+    }),
+    (c) => c.text('Search')
+  )
+  const app = new Hono()
+    .get('/', (c) => c.text('Index'))
+    .route('/api', api)
+    .route('/content', content)
+
+  it('Should return a correct url via $url().href', async () => {
+    const client = hc<typeof app>('http://fake')
+    expect(client.index.$url().href).toBe('http://fake/')
+    expect(client.api.$url().href).toBe('http://fake/api')
+    expect(
+      client.api.posts[':id'].$url({
+        param: {
+          id: '123',
+        },
+      }).href
+    ).toBe('http://fake/api/posts/123')
+    expect(
+      client.content.search.$url({
+        query: {
+          page: '123',
+          limit: '20',
+        },
+      }).href
+    ).toBe('http://fake/content/search?page=123&limit=20')
+  })
+})
+
 describe('Form - Multiple Values', () => {
   const server = setupServer(
     http.post('http://localhost/multiple-values', async ({ request }) => {