import {
type DeviceListInput,
AuthAccessReadScope,
AuthOrchestrationOperateScope,
AuthOrchestrationReadScope,
AuthRelayReadScope,
AuthRelayWriteScope,
AuthReviewWriteScope,
AuthTerminalOperateScope,
ORCHESTRATION_WS_METHODS,
type AuthEnvironmentScope,
WS_METHODS,
WsRpcGroup,
} from "@t3tools/contracts";
import type * as RpcGroup from "effect/unstable/rpc/RpcGroup";
type WsRpcMethod = RpcGroup.Rpcs<typeof WsRpcGroup>["_tag"];
/**
* Keep authorization coverage coupled to the RPC group itself. Adding an RPC to
* `WsRpcGroup` without choosing a scope is a type error instead of a production
* runtime failure.
*/
export const RPC_REQUIRED_SCOPES = {
[ORCHESTRATION_WS_METHODS.dispatchCommand]: AuthOrchestrationOperateScope,
[ORCHESTRATION_WS_METHODS.getWorkflowScript]: AuthOrchestrationReadScope,
[ORCHESTRATION_WS_METHODS.getTurnDiff]: AuthOrchestrationReadScope,
[ORCHESTRATION_WS_METHODS.getFullThreadDiff]: AuthOrchestrationReadScope,
[ORCHESTRATION_WS_METHODS.searchThreads]: AuthOrchestrationReadScope,
[ORCHESTRATION_WS_METHODS.subscribeShell]: AuthOrchestrationReadScope,
[ORCHESTRATION_WS_METHODS.getArchivedShellSnapshot]: AuthOrchestrationReadScope,
[ORCHESTRATION_WS_METHODS.subscribeThread]: AuthOrchestrationReadScope,
[WS_METHODS.serverProbe]: AuthOrchestrationReadScope,
[WS_METHODS.serverGetConfig]: AuthOrchestrationReadScope,
[WS_METHODS.serverRefreshProviders]: AuthOrchestrationOperateScope,
[WS_METHODS.serverUpdateProvider]: AuthOrchestrationOperateScope,
[WS_METHODS.providerAuthStart]: AuthOrchestrationOperateScope,
[WS_METHODS.providerConsumeResetCredit]: AuthOrchestrationOperateScope,
[WS_METHODS.providerAuthComplete]: AuthOrchestrationOperateScope,
[WS_METHODS.providerAuthCancel]: AuthOrchestrationOperateScope,
[WS_METHODS.providerAuthLogout]: AuthOrchestrationOperateScope,
[WS_METHODS.providerAuthSubscribe]: AuthOrchestrationOperateScope,
[WS_METHODS.providerInstallStart]: AuthOrchestrationOperateScope,
[WS_METHODS.providerInstallCancel]: AuthOrchestrationOperateScope,
[WS_METHODS.providerInstallSubscribe]: AuthOrchestrationReadScope,
[WS_METHODS.providerInstallRemove]: AuthOrchestrationOperateScope,
[WS_METHODS.serverUpdateServer]: AuthOrchestrationOperateScope,
[WS_METHODS.serverUpdateServerWithProgress]: AuthOrchestrationOperateScope,
[WS_METHODS.serverCommitDesktopUpdate]: AuthOrchestrationOperateScope,
[WS_METHODS.serverUpsertKeybinding]: AuthOrchestrationOperateScope,
[WS_METHODS.serverRemoveKeybinding]: AuthOrchestrationOperateScope,
[WS_METHODS.serverGetSettings]: AuthOrchestrationReadScope,
[WS_METHODS.serverUpdateSettings]: AuthOrchestrationOperateScope,
[WS_METHODS.serverDiscoverSourceControl]: AuthOrchestrationReadScope,
[WS_METHODS.serverGetTraceDiagnostics]: AuthOrchestrationReadScope,
[WS_METHODS.serverGetProcessDiagnostics]: AuthOrchestrationReadScope,
[WS_METHODS.serverGetHostResources]: AuthOrchestrationReadScope,
[WS_METHODS.serverGetProcessResourceHistory]: AuthOrchestrationReadScope,
[WS_METHODS.serverGetResourceTelemetryHistory]: AuthOrchestrationReadScope,
[WS_METHODS.serverRetryResourceTelemetry]: AuthOrchestrationOperateScope,
[WS_METHODS.serverGetUsageSummary]: AuthOrchestrationReadScope,
[WS_METHODS.serverRefreshUsageRates]: AuthOrchestrationReadScope,
[WS_METHODS.serverSignalProcess]: AuthOrchestrationOperateScope,
[WS_METHODS.serverReportClientActivity]: AuthOrchestrationReadScope,
[WS_METHODS.serverReportHostPowerState]: AuthOrchestrationOperateScope,
[WS_METHODS.serverGetBackgroundPolicy]: AuthOrchestrationReadScope,
[WS_METHODS.cloudGetRelayClientStatus]: AuthRelayReadScope,
[WS_METHODS.cloudInstallRelayClient]: AuthRelayWriteScope,
[WS_METHODS.pullRequestsList]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsListStats]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsSummary]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsRouting]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsRoutingIdentity]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsStack]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsLinkedThreads]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsDetail]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsPreview]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsActivity]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsThreadComments]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsDiffFileContents]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsFilesViewed]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsRunAction]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsUpdate]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsComment]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsUpdateComment]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSubmitReview]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsReplyToThread]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetThreadResolution]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetReaction]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsSetFilesViewed]: AuthOrchestrationOperateScope,
// Read scope like the reads it un-caches: refreshing is part of reading, and a read-only
// client pressing refresh must not be told it may not look again.
[WS_METHODS.pullRequestsInvalidate]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsSubscribeRefreshes]: AuthOrchestrationReadScope,
// The candidate list is a read like the detail beside it; asking somebody for a review is a
// write like every other one.
[WS_METHODS.pullRequestsReviewerCandidates]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsRequestReviewers]: AuthOrchestrationOperateScope,
[WS_METHODS.pullRequestsLabelCandidates]: AuthOrchestrationReadScope,
[WS_METHODS.pullRequestsSetLabels]: AuthOrchestrationOperateScope,
[WS_METHODS.sourceControlLookupRepository]: AuthOrchestrationReadScope,
[WS_METHODS.sourceControlCloneRepository]: AuthOrchestrationOperateScope,
[WS_METHODS.sourceControlPublishRepository]: AuthOrchestrationOperateScope,
[WS_METHODS.projectCloneStart]: AuthOrchestrationOperateScope,
[WS_METHODS.projectCloneCancel]: AuthOrchestrationOperateScope,
[WS_METHODS.projectCloneRetry]: AuthOrchestrationOperateScope,
[WS_METHODS.subscribeProjectClones]: AuthOrchestrationReadScope,
[WS_METHODS.projectsListEntries]: AuthOrchestrationReadScope,
[WS_METHODS.projectsReadFile]: AuthOrchestrationReadScope,
[WS_METHODS.projectsSearchContents]: AuthOrchestrationReadScope,
[WS_METHODS.projectsSearchEntries]: AuthOrchestrationReadScope,
[WS_METHODS.projectsWriteFile]: AuthOrchestrationOperateScope,
[WS_METHODS.shellOpenInEditor]: AuthOrchestrationOperateScope,
[WS_METHODS.filesystemBrowse]: AuthOrchestrationReadScope,
[WS_METHODS.agentSessionsScan]: AuthOrchestrationReadScope,
[WS_METHODS.agentSessionsImport]: AuthOrchestrationOperateScope,
[WS_METHODS.assetsCreateUrl]: AuthOrchestrationReadScope,
[WS_METHODS.attachmentsCreateUploadUrl]: AuthOrchestrationOperateScope,
[WS_METHODS.attachmentsDelete]: AuthOrchestrationOperateScope,
[WS_METHODS.providerUploadFeedback]: AuthOrchestrationOperateScope,
[WS_METHODS.subscribeVcsStatus]: AuthOrchestrationReadScope,
[WS_METHODS.subscribeWorktreeSetup]: AuthOrchestrationReadScope,
[WS_METHODS.worktreeSetupCancel]: AuthOrchestrationOperateScope,
[WS_METHODS.subscribeResourceTelemetry]: AuthOrchestrationReadScope,
[WS_METHODS.vcsRefreshStatus]: AuthOrchestrationReadScope,
[WS_METHODS.vcsPull]: AuthOrchestrationOperateScope,
[WS_METHODS.gitRunStackedAction]: AuthOrchestrationOperateScope,
[WS_METHODS.gitResolvePullRequest]: AuthOrchestrationOperateScope,
[WS_METHODS.gitPreparePullRequestThread]: AuthOrchestrationOperateScope,
[WS_METHODS.vcsListRefs]: AuthOrchestrationReadScope,
[WS_METHODS.vcsCreateWorktree]: AuthOrchestrationOperateScope,
[WS_METHODS.vcsRemoveWorktree]: AuthOrchestrationOperateScope,
[WS_METHODS.vcsCreateRef]: AuthOrchestrationOperateScope,
[WS_METHODS.vcsSwitchRef]: AuthOrchestrationOperateScope,
[WS_METHODS.vcsInit]: AuthOrchestrationOperateScope,
[WS_METHODS.reviewGetDiffPreview]: AuthReviewWriteScope,
[WS_METHODS.reviewGetDiffFileContents]: AuthReviewWriteScope,
[WS_METHODS.terminalOpen]: AuthTerminalOperateScope,
[WS_METHODS.terminalAttach]: AuthTerminalOperateScope,
[WS_METHODS.terminalWrite]: AuthTerminalOperateScope,
[WS_METHODS.terminalResize]: AuthTerminalOperateScope,
[WS_METHODS.terminalClear]: AuthTerminalOperateScope,
[WS_METHODS.terminalRestart]: AuthTerminalOperateScope,
[WS_METHODS.terminalClose]: AuthTerminalOperateScope,
[WS_METHODS.subscribeTerminalEvents]: AuthTerminalOperateScope,
[WS_METHODS.subscribeTerminalMetadata]: AuthTerminalOperateScope,
[WS_METHODS.previewOpen]: AuthOrchestrationOperateScope,
[WS_METHODS.previewNavigate]: AuthOrchestrationOperateScope,
[WS_METHODS.previewResize]: AuthOrchestrationOperateScope,
[WS_METHODS.previewRefresh]: AuthOrchestrationOperateScope,
[WS_METHODS.previewClose]: AuthOrchestrationOperateScope,
[WS_METHODS.previewList]: AuthOrchestrationReadScope,
[WS_METHODS.previewReportStatus]: AuthOrchestrationOperateScope,
[WS_METHODS.previewAutomationConnect]: AuthOrchestrationOperateScope,
[WS_METHODS.previewAutomationRespond]: AuthOrchestrationOperateScope,
[WS_METHODS.previewAutomationFocusHost]: AuthOrchestrationOperateScope,
[WS_METHODS.subscribePreviewEvents]: AuthOrchestrationReadScope,
[WS_METHODS.subscribeDiscoveredLocalServers]: AuthOrchestrationReadScope,
[WS_METHODS.deviceConfigure]: AuthOrchestrationOperateScope,
[WS_METHODS.deviceTestHost]: AuthOrchestrationOperateScope,
[WS_METHODS.deviceList]: AuthOrchestrationReadScope,
[WS_METHODS.deviceOpen]: AuthOrchestrationOperateScope,
[WS_METHODS.deviceClose]: AuthOrchestrationOperateScope,
[WS_METHODS.deviceShutdown]: AuthOrchestrationOperateScope,
[WS_METHODS.deviceDetail]: AuthOrchestrationReadScope,
[WS_METHODS.deviceAction]: AuthOrchestrationOperateScope,
[WS_METHODS.subscribeDeviceState]: AuthOrchestrationReadScope,
[WS_METHODS.subscribeServerConfig]: AuthOrchestrationReadScope,
[WS_METHODS.subscribeServerLifecycle]: AuthOrchestrationReadScope,
[WS_METHODS.subscribeAuthAccess]: AuthAccessReadScope,
[WS_METHODS.subscribeBackgroundPolicy]: AuthOrchestrationReadScope,
} as const satisfies Readonly<Record<WsRpcMethod, AuthEnvironmentScope>>;
export function requiredScopeForRpcMethod(method: string): AuthEnvironmentScope {
if (!Object.hasOwn(RPC_REQUIRED_SCOPES, method)) {
throw new Error(`RPC method ${method} has no declared authorization scope.`);
}
const requiredScope = RPC_REQUIRED_SCOPES[method as WsRpcMethod];
if (requiredScope === undefined) {
throw new Error(`RPC method ${method} has no declared authorization scope.`);
}
return requiredScope;
}
/** Retrying can install or restart tools even though ordinary listing is readable. */
export const requiredScopeForDeviceList = (input: DeviceListInput): AuthEnvironmentScope =>
input.retryHostId || input.updateTool
? AuthOrchestrationOperateScope
: AuthOrchestrationReadScope;