Files
stack-mos-dt-0/apps/gateway/src/coord/mos-coordination.controller.ts
T

74 lines
2.4 KiB
TypeScript

import {
Body,
Controller,
ForbiddenException,
Get,
Headers,
Inject,
Param,
Post,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard.js';
import { CurrentUser } from '../auth/current-user.decorator.js';
import { scopeFromUser, type AuthenticatedUserLike } from '../auth/session-scope.js';
import type { RuntimeProviderRequestContext } from '../agent/runtime-provider-registry.service.js';
import type {
MosCoordinationObservationDto,
MosCoordinationResponseDto,
MosCoordinationResultDto,
CreateMosHandoffDto,
} from './mos-coordination.dto.js';
import { MosCoordinationService } from './mos-coordination.service.js';
/** Authenticated interaction-plane boundary for the handoff/observe/result-only Mos contract. */
@Controller('api/coord/mos')
@UseGuards(AuthGuard)
export class MosCoordinationController {
constructor(
@Inject(MosCoordinationService) private readonly coordination: MosCoordinationService,
) {}
@Post('handoff')
async handoff(
@Body() request: CreateMosHandoffDto,
@CurrentUser() user: AuthenticatedUserLike,
@Headers('x-correlation-id') correlationId?: string,
): Promise<MosCoordinationResponseDto> {
return { receipt: await this.coordination.handoff(request, this.context(user, correlationId)) };
}
@Get(':handoffId/observe')
async observe(
@Param('handoffId') handoffId: string,
@CurrentUser() user: AuthenticatedUserLike,
@Headers('x-correlation-id') correlationId?: string,
): Promise<MosCoordinationObservationDto> {
return {
observation: await this.coordination.observe(handoffId, this.context(user, correlationId)),
};
}
@Get(':handoffId/result')
async result(
@Param('handoffId') handoffId: string,
@CurrentUser() user: AuthenticatedUserLike,
@Headers('x-correlation-id') correlationId?: string,
): Promise<MosCoordinationResultDto> {
return { result: await this.coordination.result(handoffId, this.context(user, correlationId)) };
}
private context(
user: AuthenticatedUserLike,
correlationId?: string,
): RuntimeProviderRequestContext {
const requestCorrelationId = correlationId?.trim();
if (!requestCorrelationId) throw new ForbiddenException('X-Correlation-Id is required');
return {
actorScope: scopeFromUser(user),
channelId: 'cli',
correlationId: requestCorrelationId,
};
}
}