diff --git a/docs/Product-Requirements.md b/docs/Product-Requirements.md index 98130793..b1c70958 100644 --- a/docs/Product-Requirements.md +++ b/docs/Product-Requirements.md @@ -79,7 +79,7 @@ The CLI uses topics (space-separated) to group related commands logically. *(Interact with Ably Pub/Sub using the Realtime SDK)* - `$ ably channels list`: Lists active channels via channel enumeration API. Supports `--prefix`, `--limit`. -- `$ ably channels publish CHANNEL MESSAGE`: Publishes a message. Supports `--name`, `--encoding`, `--count`, `--delay`, JSON/text message, message interpolation (`{{.Count}}`, `{{.Timestamp}}`), `--transport rest|realtime`. +- `$ ably channels publish CHANNEL MESSAGE`: Publishes a message. Supports `--name`, `--encoding`, `--count`, `--delay`, JSON/text message, message interpolation (`{{.Count}}`, `{{.Timestamp}}`), `--transport rest|realtime`. Supports `extras.push` for push notifications in message payload. - `$ ably channels batch-publish [MESSAGE]`: Publishes multiple messages via REST batch API. Supports `--channels`, `--channels-json`, `--spec`. - `$ ably channels subscribe CHANNELS...`: Subscribes to messages on one or more channels. Supports `--rewind`, `--delta`, `--cipher-*` flags for decryption. Runs until terminated. - `$ ably channels history CHANNEL`: Retrieves message history. Supports `--start`, `--end`, `--limit`, `--direction`, `--cipher` flags. diff --git a/src/commands/channels/publish.ts b/src/commands/channels/publish.ts index bde8e7ca..afe80f6a 100644 --- a/src/commands/channels/publish.ts +++ b/src/commands/channels/publish.ts @@ -31,6 +31,7 @@ export default class ChannelsPublish extends AblyBaseCommand { '$ ably channels publish --transport realtime my-channel "Using realtime transport"', '$ ably channels publish my-channel "Hello World" --json', '$ ably channels publish my-channel "Hello World" --pretty-json', + '$ ably channels publish my-channel \'{"data":"Push notification","extras":{"push":{"notification":{"title":"Hello","body":"World"}}}}\'', ]; static override flags = { @@ -206,6 +207,13 @@ export default class ChannelsPublish extends AblyBaseCommand { delete messageData.name; } + // Add extras if provided in the message data (before processing data) + if ("extras" in messageData) { + message.extras = messageData.extras; + // Remove extras from messageData to avoid duplication in data + delete messageData.extras; + } + // If data is explicitly provided in the message, use it if ("data" in messageData) { message.data = messageData.data; diff --git a/test/unit/commands/channels/publish.test.ts b/test/unit/commands/channels/publish.test.ts index 173d2069..7b189549 100644 --- a/test/unit/commands/channels/publish.test.ts +++ b/test/unit/commands/channels/publish.test.ts @@ -399,4 +399,31 @@ describe("ChannelsPublish", function () { expect(stdout).toMatch(/error/i); }); }); + + describe("extras.push support", function () { + it("should include extras.push when provided in message data", async function () { + const restMock = getMockAblyRest(); + const channel = restMock.channels._getChannel("test-channel"); + + await runCommand( + [ + "channels:publish", + "test-channel", + '{"data":"hello","extras":{"push":{"notification":{"title":"Test","body":"Push notification"}}}}', + "--transport", + "rest", + ], + import.meta.url, + ); + + expect(channel.publish).toHaveBeenCalledOnce(); + const publishArgs = channel.publish.mock.calls[0][0]; + expect(publishArgs).toHaveProperty("data", "hello"); + expect(publishArgs).toHaveProperty("extras"); + expect(publishArgs.extras).toHaveProperty("push"); + expect(publishArgs.extras.push).toEqual({ + notification: { title: "Test", body: "Push notification" }, + }); + }); + }); });