npm package: @prometx/trpc-navigation-plugin
Description: TypeScript Language Service Plugin that fixes broken 'go to definition' for tRPC when using declaration emit
Latest version: 0.3.2

# tRPC Navigation Plugin

A TypeScript Language Service Plugin that fixes broken "go to definition" navigation for tRPC procedures when using TypeScript's declaration emit.

🚀 **[View Demo Repository](https://github.com/ebg1223/trpc-plugin-demo)** - See the plugin in action with a T3 Turbo monorepo

## Problem

When using tRPC with TypeScript's declaration emit (`declaration: true`), there's a TypeScript bug that completely breaks "go to definition" functionality. When you try to Cmd+Click on a tRPC procedure call like `api.users.getUser.useQuery()`, TypeScript only takes you to the root router definition - it can't navigate any deeper into nested routers or the actual procedure implementations.

This is caused by how TypeScript handles the complex type inference in tRPC's router chains when generating `.d.ts` files.

## Solution

This plugin bypasses TypeScript's broken type-based navigation by using a configured router location. When you Cmd+Click on a tRPC procedure, the plugin intercepts the navigation request and takes you directly to the procedure implementation in your source code.

## Features

- **Fixes Broken Navigation**: Restores "go to definition" functionality that TypeScript's declaration emit breaks
- **Direct Source Navigation**: Takes you to the actual implementation code, not type definitions
- **Simple Configuration**: Just specify your router location - no complex setup
- **Intelligent Client Detection**: Automatically detects any tRPC client variable (api, trpc, client, etc.)
- **useUtils Support**: Full navigation support for `useUtils()` variables
- **Cross-Package Support**: Works seamlessly in monorepos
- **Fast Performance**: Direct navigation without complex type resolution

## When You Need This Plugin

You need this plugin if:
- Your project uses tRPC
- You have `declaration: true` in your tsconfig.json (for generating .d.ts files)
- "Go to definition" on tRPC procedures doesn't work or takes you to the wrong place

You DON'T need this plugin if:
- You're not using TypeScript's declaration emit
- Your "go to definition" already works correctly

## Installation

> ⚠️ **IMPORTANT: VS Code & Editor Setup**
> 
> **You MUST use the workspace TypeScript version, not the built-in version!**
> 
> In VS Code, Cursor, or other VS Code-based editors:
> 1. Open any TypeScript file in your project
> 2. Click the TypeScript version number or `{}` in the bottom status bar
> 3. Select "Select TypeScript Version..."
> 4. Choose "Use Workspace Version" (NOT "Use VS Code's Version")
> 
> Without this step, the plugin will not be detected or loaded!

### Setup Steps

1. Install the plugin:
   ```bash
   npm install --save-dev trpc-navigation-plugin
   # or
   yarn add -D trpc-navigation-plugin
   # or
   bun add -D trpc-navigation-plugin
   ```

2. Configure in your `tsconfig.json` with your router location:
   ```json
   {
     "compilerOptions": {
       "plugins": [
         {
           "name": "trpc-navigation-plugin",
           "router": {
             "filePath": "./src/server/api/root.ts",
             "variableName": "appRouter"
           }
         }
       ]
     }
   }
   ```

3. **Switch to workspace TypeScript** (see important note above)
4. Restart the TypeScript server: `Cmd+Shift+P` → "TypeScript: Restart TS Server"

## Configuration

The plugin requires you to specify where your tRPC router is defined:

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/server/api/root.ts",  // Path to your router file
          "variableName": "appRouter"              // Name of your router variable
        }
      }
    ]
  }
}
```

### Configuration Options

- `router.filePath` (required): Path to the file containing your main tRPC router
  - Can be relative (resolved from project root) or absolute
  - Example: `"./src/server/api/root.ts"`

- `router.variableName` (required): Name of your router variable in that file
  - Example: `"appRouter"`, `"router"`, `"mainRouter"`

- `patterns` (optional): Customize pattern detection
  - `procedureTypes`: Procedure types to detect (default: `['query', 'mutation', 'subscription']`)
  - `routerFunctions`: Router function names (default: `['router', 'createTRPCRouter', 'createRouter', 't.router']`)
  - `clientInitializers`: Client initialization patterns (default: `['createTRPC', 'initTRPC', 'createTRPCClient']`)
  - `utilsMethod`: Name of the utils method (default: `'useUtils'`)

- `fileExtensions` (optional): File extensions to process
  - Default: `['.ts', '.tsx', '.js', '.jsx', '.mts', '.cts', '.mjs', '.cjs']`
  - Add custom extensions if needed

### Monorepo Setup

In monorepos, add the plugin to each package that uses tRPC:

```json
// packages/api/tsconfig.json - where router is defined
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/router/index.ts",
          "variableName": "appRouter"
        }
      }
    ]
  }
}

// packages/web/tsconfig.json - uses tRPC through @my/api package
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "../api/src/router/index.ts",
          "variableName": "appRouter"
        }
      }
    ]
  }
}
```

### Optional: Enable Verbose Logging

For debugging, you can enable verbose logging:

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/server/api/root.ts",
          "variableName": "appRouter"
        },
        "verbose": true  // Enable detailed logging
      }
    ]
  }
}
```

### Advanced Configuration

Customize detection patterns for non-standard tRPC setups:

```json
{
  "compilerOptions": {
    "plugins": [
      {
        "name": "trpc-navigation-plugin",
        "router": {
          "filePath": "./src/server/api/root.ts",
          "variableName": "appRouter"
        },
        "patterns": {
          "procedureTypes": ["query", "mutation", "subscription", "action"],
          "routerFunctions": ["router", "createTRPCRouter", "myCustomRouter"],
          "clientInitializers": ["createTRPC", "initTRPC", "setupTRPC"],
          "utilsMethod": "useUtils"  // or "useContext" for older tRPC versions
        },
        "fileExtensions": [".ts", ".tsx", ".mts", ".cts"]
      }
    ]
  }
}
```

## Automatic tRPC Client Detection

The plugin intelligently detects any tRPC client variable, regardless of naming:

```typescript
// All of these work automatically:
export const api = createTRPCReact<AppRouter>();
export const trpc = createTRPCNext<AppRouter>();
export const client = createTRPCProxyClient<AppRouter>();
export const myCustomName = initTRPC.create();

// In your components:
api.users.getUser.useQuery();      // ✓ Works
trpc.users.getUser.useQuery();     // ✓ Works
client.users.getUser.query();       // ✓ Works
myCustomName.users.getUser.query(); // ✓ Works

// useUtils variables also work:
const utils = api.useUtils();
const apiCtx = trpc.useUtils();
utils.users.getUser.fetch();       // ✓ Works
apiCtx.users.getUser.invalidate();  // ✓ Works
```

## How It Works

1. **Router Configuration**: You specify where your tRPC router is defined
2. **Client Detection**: The plugin detects when you click on a tRPC client call
3. **Direct Navigation**: Uses the configured router location to navigate directly to procedures
4. **Path Resolution**: Follows the navigation path through nested routers to find the target
5. **Contextual Navigation**: Click on different parts for different results:
   - `api.billing.claims` - clicking "billing" goes to billing router
   - `api.billing.claims` - clicking "claims" goes to claims procedure/router

## Troubleshooting

If navigation isn't working:

1. **Verify TypeScript Version**: Make sure you're using the workspace TypeScript version! (See installation section)
2. **Check Configuration**: Ensure your router config points to the correct file and variable name
3. **Verify Router Export**: Make sure your router is exported or declared in the specified file
4. **Check TS Server Logs**: Look for `[TRPC-Nav]` entries in the TypeScript Server logs
5. **Enable Verbose Logging**: Add `"verbose": true` to see detailed debug information
6. **Restart TS Server**: After configuration changes: `Cmd+Shift+P` → "TypeScript: Restart TS Server"

Common issues:
- **Plugin not loading**: You're using VS Code's built-in TypeScript instead of workspace version
- Wrong file path: Paths are resolved from the project root (where tsconfig.json is)
- Wrong variable name: The variable name must match exactly (case-sensitive)
- Router not found: Make sure the router is a top-level export or variable declaration

## Technical Details

- Uses TypeScript's Language Service API for navigation interception
- Directly navigates to configured router location without complex type resolution
- Works around TypeScript's navigation bug without modifying your build process
- Compatible with tRPC v10+ and v11 that use the standard router pattern
- Supports monorepo setups with relative or absolute paths
- Does not interfere with TypeScript's type checking or declaration emit