1import type {
2 AtomCommand,
3 AtomCommandOptions,
4 AtomCommandResult,
5} from "@t3tools/client-runtime/state/runtime";
6import {
7 AuthOrchestrationOperateScope,
8 EnvironmentAuthorizationError,
9 type EnvironmentId,
10} from "@t3tools/contracts";
11import * as Cause from "effect/Cause";
12import { AsyncResult } from "effect/reactivity";
13import { useCallback } from "react";
14
15import { readEnvironmentScope, readThreadOrganizationPermission } from "./session";
16import { useAtomCommand } from "./use-atom-command";
17
18export const ORCHESTRATION_OPERATE_DENIED_MESSAGE =
19 "This connection cannot change threads or projects.";
20
21/** Recheck the target grant for every step of a thread or project mutation. */
22export function useOrchestrationCommand<W extends { readonly environmentId: EnvironmentId }, A, E>(
23 command: AtomCommand<W, A, E>,
24 options?: string | (AtomCommandOptions & { readonly organization?: true }),
25): (value: W) => Promise<AtomCommandResult<A, E | EnvironmentAuthorizationError>> {
26 const run = useAtomCommand(command, options);
27 const organization = typeof options === "object" && options.organization === true;
28 return useCallback(
29 async (value: W): Promise<AtomCommandResult<A, E | EnvironmentAuthorizationError>> => {
30 const permitted = organization
31 ? readThreadOrganizationPermission(value.environmentId)
32 : readEnvironmentScope(value.environmentId, AuthOrchestrationOperateScope);
33 if (!permitted) {
34 return AsyncResult.failure(
35 Cause.fail(
36 new EnvironmentAuthorizationError({
37 requiredScope: AuthOrchestrationOperateScope,
38 message: ORCHESTRATION_OPERATE_DENIED_MESSAGE,
39 }),
40 ),
41 );
42 }
43 return run(value);
44 },
45 [run, organization],
46 );
47}