What to build
Build RpcMethodRegistry in packages/contracts/src/ that wraps Effect RpcGroup.make() but accepts individual method registrations. Each register() call provides the method name string, its schema (the Rpc.make() result), its auth scope, and its handler. The registry lazily builds the WsRpcGroup and exposes a scope lookup map.
Wire the registry into apps/server/src/ws.ts so the RPC handler dispatch reads from the registry. Old static maps (WS_METHODS, RPC_REQUIRED_SCOPE, the handler switch) remain as fallback during migration — the server should handle methods registered either way.
Acceptance criteria
Blocked by
What to build
Build
RpcMethodRegistryinpackages/contracts/src/that wraps EffectRpcGroup.make()but accepts individual method registrations. Eachregister()call provides the method name string, its schema (theRpc.make()result), its auth scope, and its handler. The registry lazily builds theWsRpcGroupand exposes a scope lookup map.Wire the registry into
apps/server/src/ws.tsso the RPC handler dispatch reads from the registry. Old static maps (WS_METHODS,RPC_REQUIRED_SCOPE, the handler switch) remain as fallback during migration — the server should handle methods registered either way.Acceptance criteria
RpcMethodRegistryacceptsregister(methodName, schema, scope, handler)usingMethodRegistryfrom Pre-factor: MethodRegistry generic utility #132WsRpcGroupfrom all registered schemasgetScopeMap()— aMap<string, AuthEnvironmentScope>for auth middlewarews.tshandler dispatch checks registry first, falls back to old static mapswsRpcScopes.test.tsstill passes (old map still present as fallback)vp checkandvp run typecheckpassBlocked by