feat(service): P2.4 REST fallback POST /v1/threads/:id/messages (session-auth)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 01:13:45 +05:30
parent 50ef34dd90
commit 3165a5bb59
3 changed files with 48 additions and 3 deletions
@@ -0,0 +1,6 @@
import { IsOptional, IsString } from 'class-validator';
export class SendMessageDto {
@IsString() content!: string;
@IsOptional() @IsString() contentRef?: string;
}
@@ -1,12 +1,49 @@
import { Controller, Get, Param } from '@nestjs/common'; import { randomUUID } from 'node:crypto';
import {
BadRequestException,
Body,
Controller,
Get,
Headers,
HttpCode,
Param,
Post,
} from '@nestjs/common';
import { ThreadsService } from './threads.service'; import { ThreadsService } from './threads.service';
import { MessageService } from '../messaging/message.service';
import { SessionVerifier } from '../platform/session.verifier';
import { SendMessageDto } from './send-message.dto';
@Controller('v1/threads') @Controller('v1/threads')
export class ThreadsController { export class ThreadsController {
constructor(private readonly threads: ThreadsService) {} constructor(
private readonly threads: ThreadsService,
private readonly messages: MessageService,
private readonly session: SessionVerifier,
) {}
@Get(':id/messages') @Get(':id/messages')
async messages(@Param('id') id: string) { async listMessages(@Param('id') id: string) {
return this.threads.getMessages(id); return this.threads.getMessages(id);
} }
/** REST/polling fallback for native send (same write as the socket path). */
@Post(':id/messages')
@HttpCode(201)
async send(
@Param('id') id: string,
@Body() body: SendMessageDto,
@Headers('authorization') authorization?: string,
@Headers('idempotency-key') idempotencyKey?: string,
) {
const token = (authorization ?? '').replace(/^Bearer\s+/i, '');
if (!token) throw new BadRequestException('Authorization bearer token is required');
const principal = this.session.verify(token);
return this.messages.send(
id,
principal,
{ content: body.content, contentRef: body.contentRef },
idempotencyKey ?? randomUUID(),
);
}
} }
@@ -1,8 +1,10 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { ThreadsController } from './threads.controller'; import { ThreadsController } from './threads.controller';
import { ThreadsService } from './threads.service'; import { ThreadsService } from './threads.service';
import { MessageModule } from '../messaging/message.module';
@Module({ @Module({
imports: [MessageModule],
controllers: [ThreadsController], controllers: [ThreadsController],
providers: [ThreadsService], providers: [ThreadsService],
exports: [ThreadsService], exports: [ThreadsService],