pyRPC's type wiring depends on a single alias: "@pyrpc/types" pointing at your generated __pyrpc.ts. For TypeScript and some bundlers, a tsconfig.json paths entry is enough. For Vite, SvelteKit, and Next.js Turbopack it is not, and the reason is where the import comes from.
The setting
The adapters live in node_modules/@pyrpc/react (etc.), and inside them the import is import { procedureKinds } from "@pyrpc/types". At build time the bundler must resolve that specifier to a concrete file. The tsconfig paths alias lives in your project's tsconfig and says "when you see @pyrpc/types, use ./__pyrpc.ts".
Who honors paths for node_modules imports
TypeScript itself applies paths to every import it compiles, wherever it originates, the type channel was never in doubt. Webpack-based bundlers (Next.js in webpack mode, Create React App) resolve paths through tsconfig-paths-webpack-plugin semantics and apply it uniformly, including for imports issued from inside node_modules.
Who does not
Vite, SvelteKit, and Next.js Turbopack resolve paths for your own source files, but deliberately skip tsconfig path rewriting for imports that originate inside node_modules. The rationale is performance and predictability: node_modules is treated as opaque, pre-resolved dependency code. The result is that the adapter's @pyrpc/types import falls through to the real npm package (the placeholder) instead of your generated module.
Why the runtime channel exposed it
Before v0.12.0 the adapter was type-only: import type { Types } is erased before the bundler ever sees it, so resolution of @pyrpc/types in node_modules-internal imports simply never mattered. The moment the adapter gained a value import (procedureKinds), the bundler had to resolve that specifier, and the gap became visible as a runtime bug: your app got the placeholder instead of the generated kinds.
The two-layer solution
The fix is a second, bundler-specific alias. Instead of relying on tsconfig paths to cover every bundler, the bundler gets its own alias configured in its own config file:
// Vite
resolve: { alias: { "@pyrpc/types": "./__pyrpc.ts" } }
// Next.js Turbopack
turbopack: { resolveAlias: { "@pyrpc/types": "./__pyrpc.ts" } }The compiler keeps the tsconfig path; the bundler gets a native alias. Two tools, two configuration surfaces, one contract. This is what pyrpc_core.bundlers automates, and why the alias must live in vite.config.* / next.config.* rather than in tsconfig alone.
The lesson
When an import crosses the node_modules boundary at runtime, you cannot assume tsconfig paths reaches it. The gap between "the compiler honors paths" and "the bundler honors paths" is precisely where your dependency's dependency stops resolving to your local file, and the fix is a native alias in the bundler that actually runs your code.

pyRPC