@@ -134,41 +134,89 @@ export function defineAuthorizedKnowledgeUseCase<
134134 }
135135 )
136136
137+ /**
138+ * Resolves and authorizes the context every branch below shares, so `authorize`
139+ * and `execute` cannot drift apart. An organization base is fully authorized
140+ * here; a workspace base still owes the workspace funnel, which the returned
141+ * scope tells the caller to run.
142+ */
143+ async function resolveAuthorizedContext ( {
144+ principal,
145+ input,
146+ } : {
147+ principal : Principal
148+ input : I
149+ } ) : Promise <
150+ | { scope : 'organization' ; principal : KnowledgePrincipalForOperation < O > ; context : C }
151+ | {
152+ scope : 'workspace'
153+ principal : KnowledgePrincipalForOperation < O >
154+ context : WorkspaceContext
155+ }
156+ > {
157+ requireKnowledgePrincipal ( principal , definition . operation )
158+ const context = await definition . resolveContext ( { principal, input } )
159+ if ( context . organizationId ) {
160+ await authorizeOrganizationOperation (
161+ principal ,
162+ definition . operation . organizationOperation ,
163+ context
164+ )
165+ return { scope : 'organization' , principal, context }
166+ }
167+ if ( principal . kind === 'organization_delegated' )
168+ throw new OrchestrationError ( 'not_found' , 'Knowledge base not found' )
169+ assertWorkspaceKnowledgeContext ( context )
170+ return { scope : 'workspace' , principal, context }
171+ }
172+
173+ function recordAudit ( resultContext : AuthorizedKnowledgeUseCaseResultContext < O , I , C , R > ) : void {
174+ const projectedAudit = definition . projectAudit ?.( resultContext )
175+ if ( projectedAudit === undefined ) return
176+ const auditEntries = Array . isArray ( projectedAudit ) ? projectedAudit : [ projectedAudit ]
177+ if ( auditEntries . length === 0 ) return
178+ const organizationId = resultContext . context . organizationId ?? undefined
179+ recordProjectedUseCaseAuditEntries (
180+ definition . operation ,
181+ organizationId ? undefined : resultContext . context . workspaceId ,
182+ resultContext . principal ,
183+ resultContext . request ,
184+ auditEntries ,
185+ organizationId
186+ )
187+ }
188+
137189 return {
138190 operation : definition . operation ,
191+ async authorize ( { principal, input, request } ) {
192+ const resolved = await resolveAuthorizedContext ( { principal, input } )
193+ if ( resolved . scope !== 'workspace' ) return
194+ await workspaceUseCase . authorize ( {
195+ principal : resolved . principal ,
196+ input : { originalInput : input , context : resolved . context } ,
197+ request,
198+ } )
199+ } ,
139200 async execute ( { principal, input, request } ) {
140- requireKnowledgePrincipal ( principal , definition . operation )
141- const context = await definition . resolveContext ( { principal, input } )
142- if ( context . organizationId ) {
143- await authorizeOrganizationOperation (
144- principal ,
145- definition . operation . organizationOperation ,
146- context
147- )
148- const result = await definition . execute ( { principal, input, context, request } )
149- const resultContext = { principal, input, context, request, result }
150- const projectedAudit = definition . projectAudit ?.( resultContext )
151- if ( projectedAudit !== undefined ) {
152- recordProjectedUseCaseAuditEntries (
153- definition . operation ,
154- undefined ,
155- principal ,
156- request ,
157- Array . isArray ( projectedAudit ) ? projectedAudit : [ projectedAudit ] ,
158- context . organizationId
159- )
160- }
161- await definition . afterSuccess ?.( resultContext )
162- return result
201+ const resolved = await resolveAuthorizedContext ( { principal, input } )
202+ if ( resolved . scope === 'workspace' ) {
203+ return workspaceUseCase . execute ( {
204+ principal : resolved . principal ,
205+ input : { originalInput : input , context : resolved . context } ,
206+ request,
207+ } )
163208 }
164- if ( principal . kind === 'organization_delegated' )
165- throw new OrchestrationError ( 'not_found' , 'Knowledge base not found' )
166- assertWorkspaceKnowledgeContext ( context )
167- return workspaceUseCase . execute ( {
168- principal,
169- input : { originalInput : input , context } ,
209+ const executionContext = {
210+ principal : resolved . principal ,
211+ input,
212+ context : resolved . context ,
170213 request,
171- } )
214+ }
215+ const result = await definition . execute ( executionContext )
216+ const resultContext = { ...executionContext , result }
217+ recordAudit ( resultContext )
218+ await definition . afterSuccess ?.( resultContext )
219+ return result
172220 } ,
173221 }
174222}
0 commit comments