Context
@microsoft/vscode-ext-webview supports either one shared tRPC instance for all webviews or one instance per webview (initWebviewTrpc<ViewContext>()). The DocumentDB extension currently uses a single shared instance bound to the framework BaseRouterContext:
// src/webviews/_integration/trpc.ts
const trpc = initWebviewTrpc<FrameworkBaseRouterContext>();
Because that one instance serves CollectionView, DocumentView, QueryInsights, IndexView, etc., two consumer-side patterns fall out of the design (surfaced during review of #795):
- Per-procedure narrowing cast — every procedure re-narrows
ctx to its view type:
const myCtx = ctx as RouterContext; // ~30 sites
Omit on the root context — controllers build the initial context, but actionContext is injected per-call by the telemetry runner, so the root object can't be a full RouterContext:
const trpcContext: Omit<RouterContext, 'actionContext'> = { ... };
Neither is a package limitation — both are how this extension wires the package. vscode-cosmosdb avoids the cast by building a separate instance per webview, each initTRPC.context<QueryEditorRouterContext>().
Proposal
Move DocumentDB to per-view tRPC instances — one initWebviewTrpc<ThisViewContext>() per webview — so ctx is already the precise per-view type inside procedures.
Pros
- Removes ~30
ctx as RouterContext casts. Procedures read ctx.sessionId, ctx.actionContext, etc. directly, fully typed.
- Type safety instead of casts. A wrong field access becomes a compile error rather than being masked by the
as cast.
- Matches the framework's intended usage and the
vscode-cosmosdb shape, making the two extensions' integration layers converge (easier shared learnings / future extraction).
- Clearer per-view boundaries — each view owns its context type end to end; no giant shared
BaseRouterContext union of concerns.
Cons
- More wiring / boilerplate. N instances instead of one: each needs its own
publicProcedure / router / createCallerFactory (and the telemetry middleware applied per instance). The framework note warns against hiding the .use() chain behind a generic helper (it collapses tRPC's ProcedureBuilder inference to any), so the wiring is repeated per instance by design.
- Circular-import care. The current single-leaf
trpc.ts deliberately breaks an appRouter -> per-view router -> appRouter cycle. Per-view instances need the same discipline replicated N times.
- Does not remove the
Omit (or optional) on the root context. actionContext is still injected per call, so the controller-built root context still lacks it regardless of instance count. This refactor fixes the cast, not the injected-field modelling.
- Churn for limited functional gain. It's an ergonomics/typing improvement, not a behavior change; touches every router + controller.
Decision needed
- Do we want per-view instances (remove casts) vs. keep the single instance (one cast pattern, less wiring)?
- Independently: how to model the injected
actionContext on the root context — keep Omit<RouterContext, 'actionContext'>, make it optional, or a WithActionContext<T> wrapper at read sites?
Follow-up to #795 (kept out of that PR to stay scoped to the package API change).
Context
@microsoft/vscode-ext-webviewsupports either one shared tRPC instance for all webviews or one instance per webview (initWebviewTrpc<ViewContext>()). The DocumentDB extension currently uses a single shared instance bound to the frameworkBaseRouterContext:Because that one instance serves CollectionView, DocumentView, QueryInsights, IndexView, etc., two consumer-side patterns fall out of the design (surfaced during review of #795):
ctxto its view type:Omiton the root context — controllers build the initial context, butactionContextis injected per-call by the telemetry runner, so the root object can't be a fullRouterContext:Neither is a package limitation — both are how this extension wires the package.
vscode-cosmosdbavoids the cast by building a separate instance per webview, eachinitTRPC.context<QueryEditorRouterContext>().Proposal
Move DocumentDB to per-view tRPC instances — one
initWebviewTrpc<ThisViewContext>()per webview — soctxis already the precise per-view type inside procedures.Pros
ctx as RouterContextcasts. Procedures readctx.sessionId,ctx.actionContext, etc. directly, fully typed.ascast.vscode-cosmosdbshape, making the two extensions' integration layers converge (easier shared learnings / future extraction).BaseRouterContextunion of concerns.Cons
publicProcedure/router/createCallerFactory(and the telemetry middleware applied per instance). The framework note warns against hiding the.use()chain behind a generic helper (it collapses tRPC'sProcedureBuilderinference toany), so the wiring is repeated per instance by design.trpc.tsdeliberately breaks anappRouter -> per-view router -> appRoutercycle. Per-view instances need the same discipline replicated N times.Omit(or optional) on the root context.actionContextis still injected per call, so the controller-built root context still lacks it regardless of instance count. This refactor fixes the cast, not the injected-field modelling.Decision needed
actionContexton the root context — keepOmit<RouterContext, 'actionContext'>, make it optional, or aWithActionContext<T>wrapper at read sites?Follow-up to #795 (kept out of that PR to stay scoped to the package API change).