refactor(orpc): shared error mapping, workspace-access gate, /api-internal router - #1068
Open
realcodesiman wants to merge 4 commits into
Open
refactor(orpc): shared error mapping, workspace-access gate, /api-internal router#1068realcodesiman wants to merge 4 commits into
realcodesiman wants to merge 4 commits into
Conversation
…s to api/private.ts Pure mechanical rename across ~61 feature directories, extracted fresh off main instead of cherry-picked from the migration branch since many of those paths also carry unrelated logic changes there. Excludes ads-campaign, which no longer exists on the source branch.
Adds a tokenHash column and moves workspace bearer-token lookup to hash-first with a plaintext fallback for the deploy-to-migration gap. The fallback and the token column removal are deliberately deferred to a follow-up once the legacy-plaintext warning log has been silent for a release. Also generalizes channel-api-rate-limit.ts into api-rate-limit.ts (adds a scope param) and pulls authorize-workspace-access.ts forward as shared owner-quota/trial-gate infrastructure, since the token-auth middleware needs both.
…ernal router Consolidates the three oRPC auth-stack exports onto one instanceof-based error mapper (was three duplicated error.name checks), adding an ActionValidationError -> 422 mapping. Wires the owner-quota/trial gate from authorize-workspace-access.ts into workspaceAuthorizedMidddleware so an oRPC mutation can't bypass the gate a server action already enforces for the same operation (invariant #14: read/delete stays open on an expired workspace). Splits the OpenAPI REST surface so /api/[[...rest]] only ever serves publicRouter (workspace-token / channel-token authed procedures) instead of the full session-authed router. A procedure missing from publicRouter now 404s instead of silently answering to a session cookie. A dev-only /api-internal mirrors the old full-router behavior for local Scalar debugging and 404s in production; the builder UI is unaffected since it calls the untouched /rpc route, not /api.
This was referenced Aug 30, 2026
feat(api-contract): add @chatbotx.io/api-contract package and implement public routers from it
#1069
Open
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.
Summary
authorizedAPI,workspaceTokenAuthAPI,channelApiTokenAPI) onto one sharedinstanceof-based error mapper, replacing three duplicatederror.name ===checks. Adds anActionValidationError→ 422 mapping.checkWorkspaceOwnerAccess, fromauthorize-workspace-access.ts) intoworkspaceAuthorizedMidddlewareso an oRPC mutation can't bypass the same gate a server action already enforces for the identical operation. Mutations only — GET/HEAD/DELETE stay open so an expired workspace keeps its read/delete-only mode (invariant [Settings] General setting page #14)./api/[[...rest]]now serves onlypublicRouter(workspace-token / channel-token authed procedures) instead of the full session-authed router. A procedure missing frompublicRouternow 404s instead of silently answering to a session cookie. A dev-only/api-internalmirrors the old full-router behavior for local Scalar debugging and 404s in production.externalWebhooksWorkspaceTokenAPIs,refLinksWorkspaceTokenAPIs) intopublicRouter.This branch is stacked on #1065 (PR-1, rename) and #1066 (PR-2, token hash) — it needs
authorize-workspace-access.tsfrom PR-2 and theapi/private.tsnaming from PR-1. Merge #1065 and #1066 first, then this PR's diff againstmainwill shrink to just its own ~550 lines. Until then the diff shown here includes their changes too.Notes for reviewers
mainhad independently evolvedorpc.tsandsafe-action.tssince the source migration branch diverged — both gainedSdkException/toPublicErrorMessagechannel-error-message handling from an already-merged, unrelated PR. A naive copy of the migration branch's version of these two files would have silently deleted that feature. Both files were hand-merged to preserve it;orpc-error-mapping.test.tsdoesn't exercise theSdkExceptionpath (it predates that feature), so I verified it manually —toKnownOrpcErrorstill mapsSdkException→BAD_REQUESTwith the provider's own message./api→publicRouterrestriction: it calls the untouched/rpc/[[...rest]]/route.ts, which still serves the full router./apiis the external-integration/OpenAPI surface (MCP, CLI, third-party tools).apps/builder/__tests__/public-router-boundary.test.tsdynamically scans the filesystem for everyfeatures/**/api/workspace-token.tsand fails if any aren't wired intorouters/public.ts— this is a regression guard the branch introduces, not something I hand-verified once and hoped stays true.@/features/tags/api/token-auth.ts— the source branch'stags/api/workspace-token.tsreplacement depends on@chatbotx.io/api-contract, a package that doesn't exist until PR-4. Renaming/rewriting it here would break the build.Test plan
pnpm lint— cleanpnpm --filter builder check-types— cleanpnpm --filter builder test— 2028/2028 passing (2020 carried over from PR-1/PR-2 + 8 new)pnpm check:circular— no new circular deps (69 pre-existing, unchanged)invariant-guardagent review — PASS (specifically verified theSdkExceptionmerge survived correctly in both files)/api-internal's production gate, the public/private router boundary, and that/api-internalinproxy.ts's allowlist only bypasses the middleware redirect, not per-procedure auth)