|
| 1 | +import type { Principal } from '@sim/auth/principal' |
| 2 | +import type { ComputerUseOwner } from '@/lib/api/contracts/computer-use' |
1 | 3 | import { isComputerUseAvailable } from '@/lib/computer-use/availability.server' |
| 4 | +import { defineAuthorizedWorkspaceUseCase, defineWorkspaceOperation } from '@/lib/core/application' |
| 5 | +import { defineAuthorizedOrganizationUseCase } from '@/lib/core/application/authorized-organization-use-case' |
2 | 6 | import { |
3 | 7 | assertOperationPrincipal, |
4 | 8 | defineOperation, |
5 | 9 | type OperationUseCase, |
6 | 10 | } from '@/lib/core/application/operation' |
| 11 | +import { defineOrganizationOperation } from '@/lib/core/application/organization-operation' |
| 12 | +import { resolveActiveWorkspaceApplicationContext } from '@/lib/workspaces/application/context' |
7 | 13 |
|
8 | | -/** permission-group-exempt: reports only the deployment-wide rollout switch; actions require chat authorization. */ |
| 14 | +/** permission-group-exempt: reports the rollout for a workspace the caller can read; actions require chat authorization. */ |
| 15 | +const workspaceAvailabilityOperation = defineWorkspaceOperation({ |
| 16 | + id: 'desktop.computer.availability', |
| 17 | + minimumRole: 'read', |
| 18 | + workspaceApiKey: 'deny', |
| 19 | + capability: 'none', |
| 20 | + principalKinds: ['session'], |
| 21 | +}) |
| 22 | + |
| 23 | +/** permission-group-exempt: reports the rollout for an organization the caller belongs to; actions require chat authorization. */ |
| 24 | +const organizationAvailabilityOperation = defineOrganizationOperation({ |
| 25 | + id: 'desktop.computer.availability', |
| 26 | + minimumRole: 'member', |
| 27 | + capability: 'none', |
| 28 | + principalKinds: ['session'], |
| 29 | +}) |
| 30 | + |
| 31 | +const workspaceAvailability = defineAuthorizedWorkspaceUseCase({ |
| 32 | + operation: workspaceAvailabilityOperation, |
| 33 | + resolveContext: ({ input }: { input: { workspaceId: string } }) => |
| 34 | + resolveActiveWorkspaceApplicationContext(input.workspaceId), |
| 35 | + authorizationOptions: {}, |
| 36 | + execute: ({ context }) => isComputerUseAvailable(context.workspaceOrganizationId), |
| 37 | +}) |
| 38 | + |
| 39 | +const organizationAvailability = defineAuthorizedOrganizationUseCase({ |
| 40 | + operation: organizationAvailabilityOperation, |
| 41 | + execute: ({ input }: { input: { organizationId: string } }) => |
| 42 | + isComputerUseAvailable(input.organizationId), |
| 43 | +}) |
| 44 | + |
| 45 | +/** |
| 46 | + * Whether computer use is rolled out for a chat's owner: an organization chat follows its |
| 47 | + * organization, a workspace chat its workspace's organization, and a personal workspace the |
| 48 | + * global switch. |
| 49 | + */ |
| 50 | +export function isComputerUseAvailableFor( |
| 51 | + principal: Principal, |
| 52 | + owner: ComputerUseOwner |
| 53 | +): Promise<boolean> { |
| 54 | + return 'organizationId' in owner |
| 55 | + ? organizationAvailability.execute({ principal, input: owner }) |
| 56 | + : workspaceAvailability.execute({ principal, input: owner }) |
| 57 | +} |
| 58 | + |
| 59 | +/** permission-group-exempt: dispatches to the owner's authorized rollout read above. */ |
9 | 60 | const availabilityOperation = defineOperation({ |
10 | 61 | id: 'desktop.computer.availability', |
11 | 62 | capability: 'none', |
12 | 63 | principalKinds: ['session'], |
13 | 64 | }) |
14 | 65 |
|
15 | | -/** The authenticated settings and capability read; no device or app data leaves the desktop. */ |
| 66 | +/** The desktop's rollout read before it touches the native helper; no device or app data leaves the desktop. */ |
16 | 67 | export const readComputerUseAvailability: OperationUseCase< |
17 | 68 | typeof availabilityOperation, |
18 | | - undefined, |
| 69 | + ComputerUseOwner, |
19 | 70 | { enabled: boolean } |
20 | 71 | > = { |
21 | 72 | operation: availabilityOperation, |
22 | | - async execute({ principal }) { |
| 73 | + async execute({ principal, input }) { |
23 | 74 | assertOperationPrincipal(principal, availabilityOperation) |
24 | | - return { enabled: await isComputerUseAvailable() } |
| 75 | + return { enabled: await isComputerUseAvailableFor(principal, input) } |
25 | 76 | }, |
26 | 77 | } |
0 commit comments