feat(studio-server): implement effect-orpc router, mount /rpc, and add typed client with TanStack Query utils - #1609
Merged
Merged
Conversation
This was referenced Jun 12, 2026
Owner
Author
|
Railway preview (MapGen Studio): not provisioned for this PR. Policy (Graphite stacks): previews are created only for the top-of-stack PR by default.
Debug: |
This was referenced Jun 12, 2026
refactor(studio): decompose App.tsx non-React corpus into feature modules and shared utilities
#1608
Merged
Merged
This was referenced Jun 12, 2026
Merged
mateicanavra
force-pushed
the
design/server-orpc
branch
from
June 12, 2026 20:44
316c96c to
79404c6
Compare
mateicanavra
force-pushed
the
design/app-decompose
branch
from
June 12, 2026 20:44
62008f3 to
5af226e
Compare
Owner
Author
Merge activity
|
mateicanavra
changed the base branch from
design/app-decompose
to
graphite-base/1609
June 12, 2026 20:57
Implement the studio's own effect-orpc server for all 16 @civ7/studio-server
contract procedures and mount an oRPC RPCHandler at /rpc inside the existing Vite
dev middleware, keeping the legacy /api/* handlers alive (coexistence; cutover is
a later supervised step). EVERYTHING talks oRPC (FRAME §4.7).
Package (@civ7/studio-server):
- services/Civ7TunerClient (direct-control reads), services/StudioConfig (host seam)
- runtime.ts (ManagedRuntime + Layer), router/index.ts (implementEffect, the only
effect-orpc import site), errors.ts (non-uniform ORPCError status mapping),
handler.ts (RPCHandler factory), context.ts (StudioServerContext seam)
- bundle effect-orpc into dist (it ships raw TS Node cannot type-strip)
- depend on @civ7/direct-control
App:
- vite.config.ts: lift autoplay/run-in-game/save-deploy handler bodies VERBATIM
into shared engines; BOTH /api and /rpc call them (one serialized queue + dual
store mutex, no state divergence); mount /rpc (Connect originalUrl prefix fix)
- src/lib/orpc.ts: typed oRPC client (RPCLink -> /rpc) + createTanstackQueryUtils
(call sites NOT switched yet — next slice)
- wire @civ7/studio-server + @orpc/* + @tanstack/react-query deps
Parity registry preserved + verified live through /rpc: non-uniform status codes
(gameInfo/live 400, setupConfig 503, most 500); live.status 200-with-embedded
{error}; run-in-game 404 echoes serverInstanceId/serverStartedAt while map-config
404 does not; assertNoRawControlFields rejects raw-control keys (400); shared
serialized queue + dual mutex. Contract refinement: civ7.gameInfo.rows and
civ7.live.gameInfo.tables hold the opaque result record (the A1 array shape did
not match /api). Deferred: standalone Bun server, prod /api parity, removing /api,
switching client call sites.
OpenSpec: mapgen-studio-server-orpc (validated --strict).
Verify: studio-server tsc clean; app tsc + vite build + worker-bundle pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mateicanavra
force-pushed
the
design/server-orpc
branch
from
June 12, 2026 20:59
79404c6 to
4146cc0
Compare
This was referenced Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Implement the studio's own effect-orpc server (
/rpc) alongside the existing/apihandlers, giving the app a typed end-to-end RPC surface without changing any current behavior.What this does
Stands up
@civ7/studio-server's effect-orpc router for all 16 contract procedures and mounts it at/rpcinside the existing Vite dev middleware. The legacy/api/*handlers remain fully alive (coexistence); both transports share the same serialized operation queue, dual-store 409 mutex, and process singletons so state never diverges.The stateful surface (autoplay, run-in-game, save/deploy) is backed by a host-injected
StudioServerContextseam — the engine bodies are lifted verbatim out ofvite.config.tsinto shared functions that both/apiand/rpccall. The read surface (status, mapSummary, gameInfo, live.*, setupConfig, savedConfigs, setupCatalog) is backed by aCiv7TunerClientEffect service wrapping@civ7/direct-control.Parity preserved
civ7.gameInfo/civ7.live.*→ 400,civ7.setupConfig→ 503, most others → 500, mapped viaorpcErrorper procedure.civ7.live.status200-with-embedded-{error}: four reads run underEffect.either; a rejected read becomes{ error: String(reason) }on that field rather than a transport error.serverInstanceId/serverStartedAt; map-config status 404 does not (asymmetry reproduced on the oRPCdatapayload).assertNoRawControlFieldssecurity scan, fingerprint dedup → 202, sha256 proof identity,finallycleanup +gen:mapsregen, and write-then-deploy rollback all preserved by construction (shared engine functions).Contract refinements
civ7.gameInfo.rowsandciv7.live.gameInfo.tables[*]are refined from bare row arrays to the opaqueCiv7GameInfoRowsResultrecord — the A1 contract did not match what the/apihandlers actually returned.Client wiring
Adds
apps/mapgen-studio/src/lib/orpc.ts: anRPCLink → /rpcclient typed offStudioContractviaContractRouterClient, pluscreateTanstackQueryUtils-derived query utils. Existing/apifetch call sites are not touched; switching them is the next slice.Infrastructure fixes
/rpcprefix fromreq.url;nodeRequestToWebRequestnow readsreq.originalUrlso the oRPC handler'sprefixmatch works correctly.effect-orpcships raw TypeScript viaexportsthat Node cannot type-strip undernode_modules;@civ7/studio-serverbundles it into itsdistvia tsupnoExternalso any Node runtime consumer loads a self-contained module.tsconfig.jsonforstudio-serverswitches tomoduleResolution: bundlerto match how tsup and Vite consume the package.deployfunctions are simplified:buildSwooperMapsStudioDeployPlan→buildSwooperMapsStudioDeployCommand, withtargetDirparsed from stdout rather than returned by a separatedeployModcall, removing the@civ7/plugin-modsand@civ7/map-policydependencies from the app.