Skip to content

Commit 97b55e1

Browse files
committed
Addressed review comments related to hint message on message serial failure
1 parent b82baf4 commit 97b55e1

3 files changed

Lines changed: 78 additions & 3 deletions

File tree

src/commands/channels/annotations/get.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default class ChannelsAnnotationsGet extends AblyBaseCommand {
2727
};
2828

2929
static override description =
30-
"List individual annotation events for a channel message (paginated event stream, not the rolled-up summary)";
30+
"List individual annotation events published for a given channel message";
3131

3232
static override examples = [
3333
'$ ably channels annotations get my-channel "01234567890:0"',

src/commands/channels/get-message.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Args, Flags } from "@oclif/core";
22
import * as Ably from "ably";
33

44
import { AblyBaseCommand } from "../../base-command.js";
5+
import { CommandError } from "../../errors/command-error.js";
56
import { productApiFlags } from "../../flags.js";
67
import {
78
formatMessageTimestamp,
@@ -10,6 +11,9 @@ import {
1011
} from "../../utils/output.js";
1112
import type { MessageDisplayFields } from "../../utils/output.js";
1213

14+
const MUTABLE_MESSAGES_HINT =
15+
"The channel may not have mutableMessages enabled — without this rule, individual messages cannot be retrieved by serial. Please check the same using 'ably apps rules list'. If the 'Mutable Messages' rule is enabled, then make sure to enter correct message serial.";
16+
1317
export default class ChannelsGetMessage extends AblyBaseCommand {
1418
static override args = {
1519
channelName: Args.string({
@@ -23,7 +27,7 @@ export default class ChannelsGetMessage extends AblyBaseCommand {
2327
};
2428

2529
static override description =
26-
"Get the latest version of a message on an Ably channel";
30+
"Get the latest version of a message on an Ably channel. Requires `mutableMessages` enabled on the channel rule.";
2731

2832
static override examples = [
2933
'$ ably channels get-message my-channel "01234567890:0"',
@@ -125,7 +129,16 @@ export default class ChannelsGetMessage extends AblyBaseCommand {
125129
this.log(formatMessagesOutput([display]));
126130
}
127131
} catch (error) {
128-
this.fail(error, flags, "channelGetMessage", {
132+
const cmdError = CommandError.from(error);
133+
const enriched =
134+
cmdError.code === 40400
135+
? new CommandError(`${cmdError.message}\n${MUTABLE_MESSAGES_HINT}`, {
136+
code: cmdError.code,
137+
statusCode: cmdError.statusCode,
138+
context: cmdError.context,
139+
})
140+
: error;
141+
this.fail(enriched, flags, "channelGetMessage", {
129142
channel: channelName,
130143
serial,
131144
});

test/unit/commands/channels/get-message.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,5 +284,67 @@ describe("channels:get-message command", () => {
284284
expect(error).toBeDefined();
285285
expect(error?.message).toContain("Message not found");
286286
});
287+
288+
it("enriches 40400 errors with the mutableMessages hint", async () => {
289+
const mock = getMockAblyRest();
290+
const channel = mock.channels._getChannel("test-channel");
291+
const notFound = Object.assign(new Error("Message not found"), {
292+
code: 40400,
293+
statusCode: 404,
294+
});
295+
channel.getMessage.mockRejectedValue(notFound);
296+
297+
const { error } = await runCommand(
298+
[COMMAND, "test-channel", "serial-001"],
299+
import.meta.url,
300+
);
301+
302+
expect(error).toBeDefined();
303+
expect(error?.message).toContain("Message not found");
304+
expect(error?.message).toContain("mutableMessages");
305+
expect(error?.message).toContain("ably apps rules list");
306+
});
307+
308+
it("does NOT enrich non-40400 errors with the mutableMessages hint", async () => {
309+
const mock = getMockAblyRest();
310+
const channel = mock.channels._getChannel("test-channel");
311+
const otherErr = Object.assign(new Error("Some other error"), {
312+
code: 50000,
313+
statusCode: 500,
314+
});
315+
channel.getMessage.mockRejectedValue(otherErr);
316+
317+
const { error } = await runCommand(
318+
[COMMAND, "test-channel", "serial-001"],
319+
import.meta.url,
320+
);
321+
322+
expect(error).toBeDefined();
323+
expect(error?.message).toContain("Some other error");
324+
expect(error?.message).not.toContain("mutableMessages");
325+
});
326+
327+
it("includes the mutableMessages hint in JSON error envelope for 40400", async () => {
328+
const mock = getMockAblyRest();
329+
const channel = mock.channels._getChannel("test-channel");
330+
const notFound = Object.assign(new Error("Message not found"), {
331+
code: 40400,
332+
statusCode: 404,
333+
});
334+
channel.getMessage.mockRejectedValue(notFound);
335+
336+
const { stdout } = await runCommand(
337+
[COMMAND, "test-channel", "serial-001", "--json"],
338+
import.meta.url,
339+
);
340+
341+
const records = parseNdjsonLines(stdout);
342+
const errorRecord = records.find((r) => r.type === "error") as
343+
| { error: { message: string; code: number } }
344+
| undefined;
345+
expect(errorRecord).toBeDefined();
346+
expect(errorRecord!.error.message).toContain("mutableMessages");
347+
expect(errorRecord!.error.code).toBe(40400);
348+
});
287349
});
288350
});

0 commit comments

Comments
 (0)