Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/commands/channels/annotations/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
validateAnnotationParams,
} from "../../../utils/annotations.js";
import {
formatLabel,
formatProgress,
formatResource,
formatSuccess,
Expand Down Expand Up @@ -94,7 +95,7 @@ export default class ChannelsAnnotationsDelete extends AblyBaseCommand {
channel: channelName,
serial,
type,
name: flags.name,
...(flags.name === undefined ? {} : { name: flags.name }),
},
);

Expand All @@ -105,7 +106,7 @@ export default class ChannelsAnnotationsDelete extends AblyBaseCommand {
channel: channelName,
serial,
type,
name: flags.name,
...(flags.name === undefined ? {} : { name: flags.name }),
},
},
flags,
Expand All @@ -116,6 +117,10 @@ export default class ChannelsAnnotationsDelete extends AblyBaseCommand {
`Annotation deleted on message ${formatResource(serial)} in channel ${formatResource(channelName)}.`,
),
);
this.log(` ${formatLabel("Type")} ${formatResource(type)}`);
if (flags.name !== undefined) {
this.log(` ${formatLabel("Name")} ${formatResource(flags.name)}`);
}
}
} catch (error) {
this.fail(error, flags, "annotationDelete", {
Expand Down
3 changes: 3 additions & 0 deletions src/commands/channels/annotations/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ export default class ChannelsAnnotationsGet extends AblyBaseCommand {
count: annotation.count,
serial: annotation.serial,
data: annotation.data,
encoding: annotation.encoding,
messageSerial: annotation.messageSerial,
extras: annotation.extras,
indexPrefix: `${formatIndex(index + 1)} ${formatTimestamp(formatMessageTimestamp(ts))}`,
};
},
Expand Down
41 changes: 39 additions & 2 deletions src/commands/channels/annotations/publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
validateAnnotationParams,
} from "../../../utils/annotations.js";
import {
formatLabel,
formatProgress,
formatResource,
formatSuccess,
Expand Down Expand Up @@ -108,7 +109,12 @@ export default class ChannelsAnnotationsPublish extends AblyBaseCommand {
"annotationPublish",
"annotationPublished",
`Published annotation on message ${serial} in channel ${channelName}`,
{ channel: channelName, serial, type, name: flags.name },
{
channel: channelName,
serial,
type,
...(flags.name === undefined ? {} : { name: flags.name }),
},
);

if (this.shouldOutputJson(flags)) {
Expand All @@ -118,7 +124,14 @@ export default class ChannelsAnnotationsPublish extends AblyBaseCommand {
channel: channelName,
serial,
type,
name: flags.name,
...(flags.name === undefined ? {} : { name: flags.name }),
...(flags.count === undefined ? {} : { count: flags.count }),
...(annotation.data === undefined
? {}
: { data: annotation.data }),
...(flags.encoding === undefined
? {}
: { encoding: flags.encoding }),
},
},
flags,
Expand All @@ -129,6 +142,30 @@ export default class ChannelsAnnotationsPublish extends AblyBaseCommand {
`Annotation published on message ${formatResource(serial)} in channel ${formatResource(channelName)}.`,
),
);
this.log(` ${formatLabel("Type")} ${formatResource(type)}`);
if (flags.name !== undefined) {
this.log(` ${formatLabel("Name")} ${formatResource(flags.name)}`);
}

if (flags.count !== undefined) {
this.log(
` ${formatLabel("Count")} ${formatResource(String(flags.count))}`,
);
}

if (annotation.data !== undefined) {
const displayData =
typeof annotation.data === "string"
? annotation.data
: JSON.stringify(annotation.data, null, 2);
this.log(` ${formatLabel("Data")} ${formatResource(displayData)}`);
}

if (flags.encoding !== undefined) {
this.log(
` ${formatLabel("Encoding")} ${formatResource(flags.encoding)}`,
);
}
}
} catch (error) {
this.fail(error, flags, "annotationPublish", {
Expand Down
22 changes: 18 additions & 4 deletions src/commands/channels/annotations/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,22 @@ export default class ChannelsAnnotationsSubscribe extends AblyBaseCommand {
channel: channelName,
annotationType: annotation.type,
action: annotation.action,
name: annotation.name,
clientId: annotation.clientId,
count: annotation.count,
serial: annotation.serial,
data: annotation.data,
messageSerial: annotation.messageSerial,
...(annotation.name === undefined ? {} : { name: annotation.name }),
...(annotation.clientId === undefined
? {}
: { clientId: annotation.clientId }),
...(annotation.count === undefined
? {}
: { count: annotation.count }),
...(annotation.data === undefined ? {} : { data: annotation.data }),
...(annotation.encoding === undefined
? {}
: { encoding: annotation.encoding }),
...(annotation.extras === undefined
? {}
: { extras: annotation.extras }),
};

this.logCliEvent(
Expand Down Expand Up @@ -149,6 +160,9 @@ export default class ChannelsAnnotationsSubscribe extends AblyBaseCommand {
count: annotation.count,
serial: annotation.serial,
data: annotation.data,
encoding: annotation.encoding,
messageSerial: annotation.messageSerial,
extras: annotation.extras,
};
this.log(formatAnnotationsOutput([displayFields]));
this.log("");
Expand Down
19 changes: 19 additions & 0 deletions src/utils/output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,9 @@ export interface AnnotationDisplayFields {
count?: number;
serial?: string;
data?: unknown;
encoding?: string;
messageSerial?: string;
extras?: unknown;
indexPrefix?: string;
}

Expand Down Expand Up @@ -359,6 +362,22 @@ export function formatAnnotationsOutput(
}
}

if (ann.encoding) {
lines.push(`${formatLabel("Encoding")} ${ann.encoding}`);
}

if (ann.messageSerial) {
lines.push(`${formatLabel("Message Serial")} ${ann.messageSerial}`);
}

if (ann.extras !== undefined && ann.extras !== null) {
if (isJsonData(ann.extras)) {
lines.push(`${formatLabel("Extras")}`, formatMessageData(ann.extras));
} else {
lines.push(`${formatLabel("Extras")} ${String(ann.extras)}`);
}
}

blocks.push(lines.join("\n"));
}

Expand Down
57 changes: 57 additions & 0 deletions test/unit/commands/channels/annotations/delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,63 @@ describe("channels:annotations:delete command", () => {
expect(result.annotation).toHaveProperty("channel", "test-channel");
expect(result.annotation).toHaveProperty("serial", "serial-001");
});

it("should show Type and Name labels in non-JSON output", async () => {
const { stdout } = await runCommand(
[
"channels:annotations:delete",
"test-channel",
"serial-001",
"reactions:distinct.v1",
"--name",
"thumbsup",
],
import.meta.url,
);

expect(stdout).toContain("Type");
expect(stdout).toContain("reactions:distinct.v1");
expect(stdout).toContain("Name");
expect(stdout).toContain("thumbsup");
});

it("should not include name in JSON output when not provided", async () => {
const records = await captureJsonLogs(async () => {
await runCommand(
[
"channels:annotations:delete",
"test-channel",
"serial-001",
"reactions:flag.v1",
"--json",
],
import.meta.url,
);
});

const result = records[0];
expect(result.annotation).not.toHaveProperty("name");
});

it("should include name in JSON output when provided", async () => {
const records = await captureJsonLogs(async () => {
await runCommand(
[
"channels:annotations:delete",
"test-channel",
"serial-001",
"reactions:flag.v1",
"--name",
"thumbsup",
"--json",
],
import.meta.url,
);
});

const result = records[0];
expect(result.annotation).toHaveProperty("name", "thumbsup");
});
});

describe("error handling", () => {
Expand Down
31 changes: 31 additions & 0 deletions test/unit/commands/channels/annotations/get.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,37 @@ describe("channels:annotations:get command", () => {
expect(stdout).toContain("Data:");
expect(stdout).toContain("extra");
});

it("should display encoding, messageSerial, and extras when present", async () => {
const mock = getMockAblyRest();
const channel = mock.channels._getChannel("test-channel");
channel.annotations.get.mockResolvedValue({
items: [
{
id: "ann-extras-001",
type: "reactions:flag.v1",
name: "thumbsup",
serial: "ann-serial-001",
messageSerial: "msg-serial-001",
timestamp: 1700000000000,
encoding: "utf8",
extras: { headers: { key: "value" } },
},
],
});

const { stdout } = await runCommand(
["channels:annotations:get", "test-channel", "serial-001"],
import.meta.url,
);

expect(stdout).toContain("Encoding:");
expect(stdout).toContain("utf8");
expect(stdout).toContain("Message Serial:");
expect(stdout).toContain("msg-serial-001");
expect(stdout).toContain("Extras:");
expect(stdout).toContain("headers");
});
});

describe("error handling", () => {
Expand Down
85 changes: 85 additions & 0 deletions test/unit/commands/channels/annotations/publish.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,91 @@ describe("channels:annotations:publish command", () => {
expect(result.annotation).toHaveProperty("channel", "test-channel");
expect(result.annotation).toHaveProperty("serial", "serial-001");
});

it("should not include undefined fields in JSON output", async () => {
const { stdout } = await runCommand(
[
"channels:annotations:publish",
"test-channel",
"serial-001",
"reactions:flag.v1",
"--json",
],
import.meta.url,
);

const result = JSON.parse(stdout);
expect(result.annotation).not.toHaveProperty("name");
expect(result.annotation).not.toHaveProperty("count");
expect(result.annotation).not.toHaveProperty("data");
expect(result.annotation).not.toHaveProperty("encoding");
});

it("should include optional fields in JSON output when provided", async () => {
const { stdout } = await runCommand(
[
"channels:annotations:publish",
"test-channel",
"serial-001",
"reactions:multiple.v1",
"--name",
"thumbsup",
"--count",
"3",
"--data",
"test-data",
"--encoding",
"utf8",
"--json",
],
import.meta.url,
);

const result = JSON.parse(stdout);
expect(result.annotation).toHaveProperty("name", "thumbsup");
expect(result.annotation).toHaveProperty("count", 3);
expect(result.annotation).toHaveProperty("data", "test-data");
expect(result.annotation).toHaveProperty("encoding", "utf8");
});

it("should output parsed JSON data in JSON output", async () => {
const { stdout } = await runCommand(
[
"channels:annotations:publish",
"test-channel",
"serial-001",
"reactions:flag.v1",
"--data",
'{"foo":"bar"}',
"--json",
],
import.meta.url,
);

const result = JSON.parse(stdout);
expect(result.annotation.data).toEqual({ foo: "bar" });
});

it("should show data and encoding in non-JSON output when provided", async () => {
const { stdout } = await runCommand(
[
"channels:annotations:publish",
"test-channel",
"serial-001",
"reactions:flag.v1",
"--data",
"test-data",
"--encoding",
"utf8",
],
import.meta.url,
);

expect(stdout).toContain("Data");
expect(stdout).toContain("test-data");
expect(stdout).toContain("Encoding");
expect(stdout).toContain("utf8");
});
});

describe("error handling", () => {
Expand Down
Loading
Loading