Generating with tanstackPlugin against a real schema (~60 collections) produces a tanstack.gen.ts that fails tsc, plus a few design gaps that block real adoption once it compiles.
Compile blockers — root cause: type declarations split across files
types.gen.ts should be the single home for all generated types; sdk.gen.ts / tanstack.gen.ts should import types from it and contain only runtime code. Today they're scattered:
tanstack.gen.ts(4,15): error TS2305: Module './types.gen' has no exported member 'ListParams'.
tanstack.gen.ts(4,27): error TS2305: Module './types.gen' has no exported member 'RequestOptions'.
tanstack.gen.ts(54,24): error TS2304: Cannot find name 'MfasCreate'.
tanstack.gen.ts(60,52): error TS2304: Cannot find name 'MfasUpdate'.
… (×~120, every XxxCreate/XxxUpdate)
tanstack.gen.ts(3,47): error TS2307: Cannot find module '@tanstack/query-core'.
ListParams / RequestOptions are declared in sdk.gen.ts, but tanstack.gen.ts does import { ListParams, RequestOptions } from "./types.gen" → TS2305. (The import path shows the intended home is types.gen — the declarations are just in the wrong file.)
- The
PbClient type is declared in client.gen.ts.
tanstack.gen.ts references XxxCreate / XxxUpdate (~120×, e.g. mutationFn: (data: MfasCreate) => …) but never imports them → TS2304.
- It imports
{ queryOptions, mutationOptions } from "@tanstack/query-core", but consumers usually have @tanstack/react-query (which re-exports both) → TS2307.
Fix: move ListParams, RequestOptions, and the PbClient type into types.gen.ts (the runtime client singleton stays in client.gen.ts); have sdk.gen.ts and tanstack.gen.ts import all types from types.gen.ts and runtime fns from sdk.gen.ts. This resolves TS2305 + TS2304 at the root. For TS2307, import from @tanstack/react-query or document @tanstack/query-core as a required peer install.
Repro: add tanstackPlugin to pbkit.config.ts → pbkit generate → tsc --noEmit on the output.
Design gaps (block real adoption even after it compiles)
4. Query factories accept no client override. xOptions(id, options?: RequestOptions) → queryFn: () => getX(id, options) always uses the default client.gen.ts singleton (new PocketBase("")). Apps with a cookie-authed browser client (or a per-request SSR client) can't inject it. Mutation factories already take opts?: { client } — queries should be symmetric.
5. Expand generic not preserved. options?: RequestOptions is non-generic, so the <const S> expand inference from the raw SDK fns is lost — useQuery(listingOptions(id, { expand: 'user' })).data.expand.user is untyped.
Both #4 and #5 are fixed by making the factory generic + client-aware:
export function listingOptions<const S extends string | undefined = undefined>(
id: string,
options?: Omit<RequestOptions, 'expand'> & { expand?: S },
opts?: { client?: PbClient },
) {
return queryOptions({
queryKey: ['listings', id, options?.expand], // see #6
queryFn: () => getListing(id, options, opts),
});
}
6. Single-record query key ignores options → cache collisions. listingOptions(id) keys as ['listings', id], so getListing(id, { expand: 'user' }) and getListing(id) share a cache entry — one variant's payload is served for the other. Include options (expand/fields) in the key, the way the list factory already includes params.
Acceptance
- Generated
tanstack.gen.ts passes tsc --noEmit against a multi-collection schema.
useQuery(listingOptions(id, { expand: 'user' }, { client: pb })) uses pb and types .data.expand.user.
- Distinct expand/fields produce distinct query keys.
Generating with
tanstackPluginagainst a real schema (~60 collections) produces atanstack.gen.tsthat failstsc, plus a few design gaps that block real adoption once it compiles.Compile blockers — root cause: type declarations split across files
types.gen.tsshould be the single home for all generated types;sdk.gen.ts/tanstack.gen.tsshould import types from it and contain only runtime code. Today they're scattered:ListParams/RequestOptionsare declared insdk.gen.ts, buttanstack.gen.tsdoesimport { ListParams, RequestOptions } from "./types.gen"→ TS2305. (The import path shows the intended home istypes.gen— the declarations are just in the wrong file.)PbClienttype is declared inclient.gen.ts.tanstack.gen.tsreferencesXxxCreate/XxxUpdate(~120×, e.g.mutationFn: (data: MfasCreate) => …) but never imports them → TS2304.{ queryOptions, mutationOptions } from "@tanstack/query-core", but consumers usually have@tanstack/react-query(which re-exports both) → TS2307.Fix: move
ListParams,RequestOptions, and thePbClienttype intotypes.gen.ts(the runtimeclientsingleton stays inclient.gen.ts); havesdk.gen.tsandtanstack.gen.tsimport all types fromtypes.gen.tsand runtime fns fromsdk.gen.ts. This resolves TS2305 + TS2304 at the root. For TS2307, import from@tanstack/react-queryor document@tanstack/query-coreas a required peer install.Repro: add
tanstackPlugintopbkit.config.ts→pbkit generate→tsc --noEmiton the output.Design gaps (block real adoption even after it compiles)
4. Query factories accept no client override.
xOptions(id, options?: RequestOptions)→queryFn: () => getX(id, options)always uses the defaultclient.gen.tssingleton (new PocketBase("")). Apps with a cookie-authed browser client (or a per-request SSR client) can't inject it. Mutation factories already takeopts?: { client }— queries should be symmetric.5. Expand generic not preserved.
options?: RequestOptionsis non-generic, so the<const S>expand inference from the raw SDK fns is lost —useQuery(listingOptions(id, { expand: 'user' })).data.expand.useris untyped.Both #4 and #5 are fixed by making the factory generic + client-aware:
6. Single-record query key ignores
options→ cache collisions.listingOptions(id)keys as['listings', id], sogetListing(id, { expand: 'user' })andgetListing(id)share a cache entry — one variant's payload is served for the other. Includeoptions(expand/fields) in the key, the way the list factory already includesparams.Acceptance
tanstack.gen.tspassestsc --noEmitagainst a multi-collection schema.useQuery(listingOptions(id, { expand: 'user' }, { client: pb }))usespband types.data.expand.user.