Optional replyId on send (API + MCP) — protocol-level threaded replies (#31)
CI / build + unit (push) Successful in 33s
CI / build + unit (push) Successful in 33s
This commit was merged in pull request #31.
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
ApiResponse,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { BROADCAST_ADDR } from './codec.js';
|
||||
import type { DeviceInfo } from './mesh.service.js';
|
||||
import { MeshService } from './mesh.service.js';
|
||||
|
||||
@@ -38,6 +39,13 @@ export class SendTextDto {
|
||||
example: '!b',
|
||||
})
|
||||
to?: string | number;
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
description:
|
||||
'Packet id of an earlier message (from GET /api/messages) that this one replies to — the recipient app renders it as a threaded reply/quote. Integer in 1..0xffffffff.',
|
||||
example: 456789,
|
||||
})
|
||||
replyId?: number;
|
||||
}
|
||||
|
||||
// tag description is set via DocumentBuilder.addTag in main.ts (v12 ApiTagOptions has no description)
|
||||
@@ -70,7 +78,7 @@ export class MeshController {
|
||||
@ApiOperation({
|
||||
summary: 'Send a text message over the mesh',
|
||||
description:
|
||||
'Queues a TEXT_MESSAGE_APP packet to the resolved target (node number, node name, or broadcast). DMs are unicast and wantAck-tracked via GET /api/messages; broadcasts stay pending because firmware strips want_ack. All sends ride the pinned test channel (index 3, "test" — never the primary channel) regardless of DM or broadcast, since modern firmware PKI handles unicast encryption/channel anyway. Returns the Meshtastic packet id.',
|
||||
'Queues a TEXT_MESSAGE_APP packet to the resolved target (node number, node name, or broadcast). Optional replyId (integer in 1..0xffffffff) references an earlier message\'s packet id from GET /api/messages — when set, the recipient app renders this message as a threaded reply/quote of that packet. DMs are unicast and wantAck-tracked via GET /api/messages; broadcasts stay pending because firmware strips want_ack. All sends ride the pinned test channel (index 3, "test" — never the primary channel) regardless of DM or broadcast, since modern firmware PKI handles unicast encryption/channel anyway. Returns the Meshtastic packet id.',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
@@ -83,6 +91,15 @@ export class MeshController {
|
||||
if (typeof body?.text !== 'string' || body.text.length === 0) {
|
||||
throw new BadRequestException('text must be a non-empty string');
|
||||
}
|
||||
const replyId = body.replyId;
|
||||
if (
|
||||
replyId !== undefined &&
|
||||
(!Number.isInteger(replyId) || replyId < 1 || replyId > BROADCAST_ADDR)
|
||||
) {
|
||||
throw new BadRequestException(
|
||||
'replyId must be an integer in 1..0xffffffff',
|
||||
);
|
||||
}
|
||||
let to: number;
|
||||
try {
|
||||
to = await this.mesh.resolveDest(body.to);
|
||||
@@ -91,7 +108,7 @@ export class MeshController {
|
||||
err instanceof Error ? err.message : String(err),
|
||||
);
|
||||
}
|
||||
return { id: await this.mesh.sendText(to, body.text) };
|
||||
return { id: await this.mesh.sendText(to, body.text, replyId) };
|
||||
}
|
||||
|
||||
@Get('channels')
|
||||
|
||||
Reference in New Issue
Block a user