1- import type { Principal } from '@sim/auth/principal'
1+ import { type Principal , requirePrincipalSubjectUserId } from '@sim/auth/principal'
22import { db } from '@sim/db'
33import { acquireOrganizationMutationLock } from '@/lib/billing/organizations/membership'
44import {
@@ -13,14 +13,17 @@ import {
1313 type AccessRequestContext ,
1414 authorizeAccessRequestScope ,
1515} from '@/ee/access-requests/lib/application/authorization'
16- import type {
17- AccessRequestOperation ,
18- AccessRequestPrincipal ,
16+ import {
17+ ACCESS_REQUEST_DELEGATION_AUDIENCE ,
18+ type AccessRequestOperation ,
19+ type AccessRequestPrincipal ,
1920} from '@/ee/access-requests/lib/application/operations'
2021import type { AccessRequestScope } from '@/ee/access-requests/lib/targets'
2122
2223interface AccessRequestPreparationArgs < I > {
2324 principal : AccessRequestPrincipal
25+ /** The person acting: the caller, or the member Chat acts for. */
26+ actorUserId : string
2427 input : I
2528 context : AccessRequestContext
2629}
@@ -107,7 +110,8 @@ export function defineAuthorizedAccessRequestUseCase<I, R, P = undefined>(
107110 const scope = definition . scope ( input )
108111 const initial = await authorizeAccessRequestScope ( principal , definition . operation , scope )
109112 return runWithOutboundOrganization ( initial . organizationId , async ( ) => {
110- const preparation = { principal, input, context : initial }
113+ const actorUserId = requirePrincipalSubjectUserId ( principal )
114+ const preparation = { principal, actorUserId, input, context : initial }
111115 let context = initial
112116 let result : R
113117 if ( definition . mutation ) {
@@ -124,19 +128,26 @@ export function defineAuthorizedAccessRequestUseCase<I, R, P = undefined>(
124128 true ,
125129 initial
126130 )
127- return execute ( { principal, input, context, executor } )
131+ return execute ( { principal, actorUserId , input, context, executor } )
128132 } )
129133 } else {
130134 const execute = await prepareExecution ( definition , preparation )
131- result = await execute ( { principal, input, context, executor : db } )
135+ result = await execute ( { principal, actorUserId , input, context, executor : db } )
132136 }
133137 if ( definition . projectAudit ) {
134138 recordProjectedUseCaseAuditEntries (
135139 definition . operation ,
136140 context . workspaceId ,
137141 principal ,
138142 request ,
139- definition . projectAudit ( { principal, input, context, executor : db , result } ) ,
143+ definition . projectAudit ( {
144+ principal,
145+ actorUserId,
146+ input,
147+ context,
148+ executor : db ,
149+ result,
150+ } ) ,
140151 context . organizationId ?? undefined
141152 )
142153 }
@@ -145,3 +156,14 @@ export function defineAuthorizedAccessRequestUseCase<I, R, P = undefined>(
145156 } ,
146157 }
147158}
159+
160+ /**
161+ * The workspace routes' copy of a member use case. Declaring the audience admits Chat acting for
162+ * the requester, pinned to its own workspace; the organization routes keep the shared use case,
163+ * so Chat never reaches them.
164+ */
165+ export function admitWorkspaceDelegation < I , R > (
166+ useCase : OperationUseCase < AccessRequestOperation , I , R >
167+ ) : OperationUseCase < AccessRequestOperation , I , R > {
168+ return Object . freeze ( { ...useCase , delegationAudience : ACCESS_REQUEST_DELEGATION_AUDIENCE } )
169+ }
0 commit comments