diff --git a/.claude/skills/ably-new-command/references/patterns.md b/.claude/skills/ably-new-command/references/patterns.md index c7dd25dd..fe6aece5 100644 --- a/.claude/skills/ably-new-command/references/patterns.md +++ b/.claude/skills/ably-new-command/references/patterns.md @@ -138,6 +138,8 @@ For single-shot publish, REST is preferred (simpler, no connection overhead). Se ## History Pattern ```typescript +import { collectPaginatedResults, formatPaginationWarning } from "../../utils/pagination.js"; + async run(): Promise { const { args, flags } = await this.parse(MyHistoryCommand); @@ -155,13 +157,23 @@ async run(): Promise { }; const history = await channel.history(historyParams); - const messages = history.items; + const { items: messages, hasMore, pagesConsumed } = await collectPaginatedResults(history, flags.limit); + + const paginationWarning = formatPaginationWarning(pagesConsumed, messages.length); + if (paginationWarning && !this.shouldOutputJson(flags)) { + this.log(paginationWarning); + } if (this.shouldOutputJson(flags)) { - this.logJsonResult({ messages }, flags); + this.logJsonResult({ messages, hasMore }, flags); } else { this.log(formatSuccess(`Found ${messages.length} messages.`)); // Display each message + + if (hasMore) { + const warning = formatLimitWarning(messages.length, flags.limit, "messages"); + if (warning) this.log(warning); + } } } catch (error) { this.fail(error, flags, "history", { channel: args.channel }); @@ -334,11 +346,59 @@ async run(): Promise { } ``` +**Product API list with pagination** (e.g., `push devices list`, `channels list`) — use `collectPaginatedResults` or `collectHttpPaginatedResults`: +```typescript +import { collectPaginatedResults, collectHttpPaginatedResults, formatPaginationWarning } from "../../utils/pagination.js"; + +async run(): Promise { + const { flags } = await this.parse(MyListCommand); + + try { + const rest = await this.createAblyRestClient(flags); + if (!rest) return; + + // For SDK methods that return PaginatedResult: + const firstPage = await rest.someResource.list({ limit: flags.limit }); + const { items, hasMore, pagesConsumed } = await collectPaginatedResults(firstPage, flags.limit); + + // For rest.request() that returns HttpPaginatedResponse: + // const firstPage = await rest.request("get", "/some/endpoint", 2, { limit: String(flags.limit) }); + // const { items, hasMore, pagesConsumed } = await collectHttpPaginatedResults(firstPage, flags.limit); + + const paginationWarning = formatPaginationWarning(pagesConsumed, items.length); + if (paginationWarning && !this.shouldOutputJson(flags)) { + this.log(paginationWarning); + } + + if (this.shouldOutputJson(flags)) { + this.logJsonResult({ items, hasMore }, flags); + } else { + this.log(`Found ${items.length} items:\n`); + for (const item of items) { + this.log(formatHeading(`Item ID: ${item.id}`)); + this.log(` ${formatLabel("Type")} ${item.type}`); + this.log(""); + } + + if (hasMore) { + const warning = formatLimitWarning(items.length, flags.limit, "items"); + if (warning) this.log(warning); + } + } + } catch (error) { + this.fail(error, flags, "listItems"); + } +} +``` + Key conventions for list output: - `formatResource()` is for inline resource name references, not for record headings - `formatHeading()` is for record heading lines that act as visual separators between multi-field records - `formatLabel(text)` for field labels in detail lines (automatically appends `:`) - `formatSuccess()` is not used in list commands — it's for confirming an action completed +- `formatLimitWarning()` should only be shown when `hasMore` is true — it means there are more results beyond the limit +- Always include `hasMore` in JSON output for paginated commands so consumers know if results are truncated +- Use `collectPaginatedResults()` for SDK paginated results, `collectHttpPaginatedResults()` for `rest.request()` results, and `collectFilteredPaginatedResults()` when a client-side filter is applied across pages --- diff --git a/README.md b/README.md index 8e2ec25a..b0608d57 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,6 @@ $ ably-interactive * [`ably apps rules delete NAMEORID`](#ably-apps-rules-delete-nameorid) * [`ably apps rules list`](#ably-apps-rules-list) * [`ably apps rules update NAMEORID`](#ably-apps-rules-update-nameorid) -* [`ably apps set-apns-p12 ID`](#ably-apps-set-apns-p12-id) * [`ably apps switch [APPID]`](#ably-apps-switch-appid) * [`ably apps update ID`](#ably-apps-update-id) * [`ably auth`](#ably-auth) @@ -145,6 +144,27 @@ $ ably-interactive * [`ably logs push history`](#ably-logs-push-history) * [`ably logs push subscribe`](#ably-logs-push-subscribe) * [`ably logs subscribe`](#ably-logs-subscribe) +* [`ably push`](#ably-push) +* [`ably push batch-publish`](#ably-push-batch-publish) +* [`ably push channels`](#ably-push-channels) +* [`ably push channels list`](#ably-push-channels-list) +* [`ably push channels list-channels`](#ably-push-channels-list-channels) +* [`ably push channels remove`](#ably-push-channels-remove) +* [`ably push channels remove-where`](#ably-push-channels-remove-where) +* [`ably push channels save`](#ably-push-channels-save) +* [`ably push config`](#ably-push-config) +* [`ably push config clear-apns`](#ably-push-config-clear-apns) +* [`ably push config clear-fcm`](#ably-push-config-clear-fcm) +* [`ably push config set-apns`](#ably-push-config-set-apns) +* [`ably push config set-fcm`](#ably-push-config-set-fcm) +* [`ably push config show`](#ably-push-config-show) +* [`ably push devices`](#ably-push-devices) +* [`ably push devices get DEVICE-ID`](#ably-push-devices-get-device-id) +* [`ably push devices list`](#ably-push-devices-list) +* [`ably push devices remove DEVICE-ID`](#ably-push-devices-remove-device-id) +* [`ably push devices remove-where`](#ably-push-devices-remove-where) +* [`ably push devices save`](#ably-push-devices-save) +* [`ably push publish`](#ably-push-publish) * [`ably queues`](#ably-queues) * [`ably queues create`](#ably-queues-create) * [`ably queues delete QUEUEID`](#ably-queues-delete-queueid) @@ -404,14 +424,13 @@ EXAMPLES $ ably apps switch my-app COMMANDS - ably apps create Create a new app - ably apps current Show the currently selected app - ably apps delete Delete an app - ably apps list List all apps in the current account - ably apps rules Manage Ably channel rules (namespaces) - ably apps set-apns-p12 Upload Apple Push Notification Service P12 certificate for an app - ably apps switch Switch to a different Ably app - ably apps update Update an app + ably apps create Create a new app + ably apps current Show the currently selected app + ably apps delete Delete an app + ably apps list List all apps in the current account + ably apps rules Manage Ably channel rules (namespaces) + ably apps switch Switch to a different Ably app + ably apps update Update an app ``` _See code: [src/commands/apps/index.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/apps/index.ts)_ @@ -517,12 +536,13 @@ List all apps in the current account ``` USAGE - $ ably apps list [-v] [--json | --pretty-json] + $ ably apps list [-v] [--json | --pretty-json] [--limit ] FLAGS - -v, --verbose Output verbose logs - --json Output in JSON format - --pretty-json Output in colorized JSON format + -v, --verbose Output verbose logs + --json Output in JSON format + --limit= [default: 100] Maximum number of results to return (default: 100) + --pretty-json Output in colorized JSON format DESCRIPTION List all apps in the current account @@ -650,13 +670,14 @@ List channel rules for an app ``` USAGE - $ ably apps rules list [-v] [--json | --pretty-json] [--app ] + $ ably apps rules list [-v] [--json | --pretty-json] [--app ] [--limit ] FLAGS - -v, --verbose Output verbose logs - --app= The app ID or name (defaults to current app) - --json Output in JSON format - --pretty-json Output in colorized JSON format + -v, --verbose Output verbose logs + --app= The app ID or name (defaults to current app) + --json Output in JSON format + --limit= [default: 100] Maximum number of results to return (default: 100) + --pretty-json Output in colorized JSON format DESCRIPTION List channel rules for an app @@ -724,41 +745,6 @@ EXAMPLES _See code: [src/commands/apps/rules/update.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/apps/rules/update.ts)_ -## `ably apps set-apns-p12 ID` - -Upload Apple Push Notification Service P12 certificate for an app - -``` -USAGE - $ ably apps set-apns-p12 ID --certificate [-v] [--json | --pretty-json] [--password ] - [--use-for-sandbox] - -ARGUMENTS - ID App ID to set the APNS certificate for - -FLAGS - -v, --verbose Output verbose logs - --certificate= (required) Path to the P12 certificate file - --json Output in JSON format - --password= Password for the P12 certificate - --pretty-json Output in colorized JSON format - --use-for-sandbox Whether to use this certificate for the APNS sandbox environment - -DESCRIPTION - Upload Apple Push Notification Service P12 certificate for an app - -EXAMPLES - $ ably apps set-apns-p12 app-id --certificate /path/to/certificate.p12 - - $ ably apps set-apns-p12 app-id --certificate /path/to/certificate.p12 --password "YOUR_CERTIFICATE_PASSWORD" - - $ ably apps set-apns-p12 app-id --certificate /path/to/certificate.p12 --use-for-sandbox - - $ ably apps set-apns-p12 app-id --certificate /path/to/certificate.p12 --json -``` - -_See code: [src/commands/apps/set-apns-p12.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/apps/set-apns-p12.ts)_ - ## `ably apps switch [APPID]` Switch to a different Ably app @@ -1072,13 +1058,14 @@ List all keys in the app ``` USAGE - $ ably auth keys list [-v] [--json | --pretty-json] [--app ] + $ ably auth keys list [-v] [--json | --pretty-json] [--app ] [--limit ] FLAGS - -v, --verbose Output verbose logs - --app= The app ID (defaults to current app) - --json Output in JSON format - --pretty-json Output in colorized JSON format + -v, --verbose Output verbose logs + --app= The app ID (defaults to current app) + --json Output in JSON format + --limit= [default: 100] Maximum number of results to return (default: 100) + --pretty-json Output in colorized JSON format DESCRIPTION List all keys in the app @@ -2243,13 +2230,14 @@ List all integrations ``` USAGE - $ ably integrations list [-v] [--json | --pretty-json] [--app ] + $ ably integrations list [-v] [--json | --pretty-json] [--app ] [--limit ] FLAGS - -v, --verbose Output verbose logs - --app= The app ID or name (defaults to current app) - --json Output in JSON format - --pretty-json Output in colorized JSON format + -v, --verbose Output verbose logs + --app= The app ID or name (defaults to current app) + --json Output in JSON format + --limit= [default: 100] Maximum number of results to return (default: 100) + --pretty-json Output in colorized JSON format DESCRIPTION List all integrations @@ -2674,6 +2662,639 @@ EXAMPLES _See code: [src/commands/logs/subscribe.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/logs/subscribe.ts)_ +## `ably push` + +Manage push notifications + +``` +USAGE + $ ably push + +DESCRIPTION + Manage push notifications + +EXAMPLES + $ ably push publish --device-id device1 --title Hello --body World + + $ ably push devices list + + $ ably push channels list --channel my-channel + + $ ably push config show + +COMMANDS + ably push batch-publish Publish push notifications to multiple recipients in a batch + ably push channels Manage push notification channel subscriptions + ably push config Manage push notification configuration (APNs, FCM) + ably push devices Manage push notification device registrations + ably push publish Publish a push notification to a device or client +``` + +_See code: [src/commands/push/index.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/index.ts)_ + +## `ably push batch-publish` + +Publish push notifications to multiple recipients in a batch + +``` +USAGE + $ ably push batch-publish --payload [-v] [--json | --pretty-json] + +FLAGS + -v, --verbose Output verbose logs + --json Output in JSON format + --payload= (required) Batch payload as JSON array, @filepath, or - for stdin + --pretty-json Output in colorized JSON format + +DESCRIPTION + Publish push notifications to multiple recipients in a batch + +EXAMPLES + $ ably push batch-publish --payload '[{"recipient":{"deviceId":"dev1"},"notification":{"title":"Hello"}}]' + + $ ably push batch-publish --payload @batch.json + + cat batch.json | ably push batch-publish --payload - + + $ ably push batch-publish --payload @batch.json --json +``` + +_See code: [src/commands/push/batch-publish.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/batch-publish.ts)_ + +## `ably push channels` + +Manage push notification channel subscriptions + +``` +USAGE + $ ably push channels + +DESCRIPTION + Manage push notification channel subscriptions + +EXAMPLES + $ ably push channels list --channel my-channel + + $ ably push channels save --channel my-channel --device-id device-123 + + $ ably push channels list-channels +``` + +_See code: [src/commands/push/channels/index.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/channels/index.ts)_ + +## `ably push channels list` + +List push channel subscriptions + +``` +USAGE + $ ably push channels list --channel [-v] [--json | --pretty-json] [--device-id ] [--client-id ] + [--limit ] + +FLAGS + -v, --verbose Output verbose logs + --channel= (required) Channel name to list subscriptions for + --client-id= Filter by client ID + --device-id= Filter by device ID + --json Output in JSON format + --limit= [default: 100] Maximum number of results to return (default: 100) + --pretty-json Output in colorized JSON format + +DESCRIPTION + List push channel subscriptions + +EXAMPLES + $ ably push channels list --channel my-channel + + $ ably push channels list --channel my-channel --device-id device-123 + + $ ably push channels list --channel my-channel --json +``` + +_See code: [src/commands/push/channels/list.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/channels/list.ts)_ + +## `ably push channels list-channels` + +List channels with push subscriptions + +``` +USAGE + $ ably push channels list-channels [-v] [--json | --pretty-json] [--limit ] + +FLAGS + -v, --verbose Output verbose logs + --json Output in JSON format + --limit= [default: 100] Maximum number of results to return (default: 100) + --pretty-json Output in colorized JSON format + +DESCRIPTION + List channels with push subscriptions + +EXAMPLES + $ ably push channels list-channels + + $ ably push channels list-channels --limit 50 + + $ ably push channels list-channels --json +``` + +_See code: [src/commands/push/channels/list-channels.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/channels/list-channels.ts)_ + +## `ably push channels remove` + +Remove a push channel subscription + +``` +USAGE + $ ably push channels remove --channel [-v] [--json | --pretty-json] [--device-id | --client-id ] + [-f] + +FLAGS + -f, --force Skip confirmation prompt + -v, --verbose Output verbose logs + --channel= (required) Channel name to unsubscribe from + --client-id= Client ID to unsubscribe + --device-id= Device ID to unsubscribe + --json Output in JSON format + --pretty-json Output in colorized JSON format + +DESCRIPTION + Remove a push channel subscription + +EXAMPLES + $ ably push channels remove --channel my-channel --device-id device-123 + + $ ably push channels remove --channel my-channel --client-id client-1 --force + + $ ably push channels remove --channel my-channel --device-id device-123 --json +``` + +_See code: [src/commands/push/channels/remove.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/channels/remove.ts)_ + +## `ably push channels remove-where` + +Remove push channel subscriptions matching filter criteria + +``` +USAGE + $ ably push channels remove-where --channel [-v] [--json | --pretty-json] [--device-id ] [--client-id ] + [-f] + +FLAGS + -f, --force Skip confirmation prompt + -v, --verbose Output verbose logs + --channel= (required) Channel name to filter by + --client-id= Filter by client ID + --device-id= Filter by device ID + --json Output in JSON format + --pretty-json Output in colorized JSON format + +DESCRIPTION + Remove push channel subscriptions matching filter criteria + +EXAMPLES + $ ably push channels remove-where --channel my-channel + + $ ably push channels remove-where --channel my-channel --device-id device-123 --force + + $ ably push channels remove-where --channel my-channel --json +``` + +_See code: [src/commands/push/channels/remove-where.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/channels/remove-where.ts)_ + +## `ably push channels save` + +Subscribe a device or client to push notifications on a channel + +``` +USAGE + $ ably push channels save --channel [-v] [--json | --pretty-json] [--device-id | --client-id ] + +FLAGS + -v, --verbose Output verbose logs + --channel= (required) Channel name to subscribe to + --client-id= Client ID to subscribe + --device-id= Device ID to subscribe + --json Output in JSON format + --pretty-json Output in colorized JSON format + +DESCRIPTION + Subscribe a device or client to push notifications on a channel + +EXAMPLES + $ ably push channels save --channel my-channel --device-id device-123 + + $ ably push channels save --channel my-channel --client-id client-1 + + $ ably push channels save --channel my-channel --device-id device-123 --json +``` + +_See code: [src/commands/push/channels/save.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/channels/save.ts)_ + +## `ably push config` + +Manage push notification configuration (APNs, FCM) + +``` +USAGE + $ ably push config + +DESCRIPTION + Manage push notification configuration (APNs, FCM) + +EXAMPLES + $ ably push config show + + $ ably push config set-apns --certificate /path/to/cert.p12 + + $ ably push config set-fcm --service-account /path/to/service-account.json +``` + +_See code: [src/commands/push/config/index.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/config/index.ts)_ + +## `ably push config clear-apns` + +Clear APNs push notification configuration for an app + +``` +USAGE + $ ably push config clear-apns [-v] [--json | --pretty-json] [--app ] [-f] + +FLAGS + -f, --force Skip confirmation prompt + -v, --verbose Output verbose logs + --app= The app ID or name (defaults to current app) + --json Output in JSON format + --pretty-json Output in colorized JSON format + +DESCRIPTION + Clear APNs push notification configuration for an app + +EXAMPLES + $ ably push config clear-apns + + $ ably push config clear-apns --app my-app --force + + $ ably push config clear-apns --force --json +``` + +_See code: [src/commands/push/config/clear-apns.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/config/clear-apns.ts)_ + +## `ably push config clear-fcm` + +Clear FCM push notification configuration for an app + +``` +USAGE + $ ably push config clear-fcm [-v] [--json | --pretty-json] [--app ] [-f] + +FLAGS + -f, --force Skip confirmation prompt + -v, --verbose Output verbose logs + --app= The app ID or name (defaults to current app) + --json Output in JSON format + --pretty-json Output in colorized JSON format + +DESCRIPTION + Clear FCM push notification configuration for an app + +EXAMPLES + $ ably push config clear-fcm + + $ ably push config clear-fcm --app my-app --force + + $ ably push config clear-fcm --force --json +``` + +_See code: [src/commands/push/config/clear-fcm.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/config/clear-fcm.ts)_ + +## `ably push config set-apns` + +Configure APNs push notifications for an app + +``` +USAGE + $ ably push config set-apns [-v] [--json | --pretty-json] [--app ] [--certificate | --key-file ] + [--key-id ] [--password ] [--sandbox] [--team-id ] [--topic ] + +FLAGS + -v, --verbose Output verbose logs + --app= The app ID or name (defaults to current app) + --certificate= Path to the P12 certificate file + --json Output in JSON format + --key-file= Path to the P8 key file + --key-id= The APNs key ID (required for P8) + --password= Password for the P12 certificate + --pretty-json Output in colorized JSON format + --sandbox Use the APNs sandbox environment + --team-id= The Apple Developer Team ID (required for P8) + --topic= The APNs topic / bundle ID (required for P8) + +DESCRIPTION + Configure APNs push notifications for an app + +EXAMPLES + $ ably push config set-apns --certificate /path/to/cert.p12 + + $ ably push config set-apns --certificate /path/to/cert.p12 --password secret --sandbox + + $ ably push config set-apns --key-file /path/to/key.p8 --key-id ABC123 --team-id DEF456 --topic com.example.app + + $ ably push config set-apns --certificate /path/to/cert.p12 --json +``` + +_See code: [src/commands/push/config/set-apns.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/config/set-apns.ts)_ + +## `ably push config set-fcm` + +Configure FCM push notifications for an app + +``` +USAGE + $ ably push config set-fcm --service-account [-v] [--json | --pretty-json] [--app ] + +FLAGS + -v, --verbose Output verbose logs + --app= The app ID or name (defaults to current app) + --json Output in JSON format + --pretty-json Output in colorized JSON format + --service-account= (required) Path to the FCM service account JSON file + +DESCRIPTION + Configure FCM push notifications for an app + +EXAMPLES + $ ably push config set-fcm --service-account /path/to/service-account.json + + $ ably push config set-fcm --service-account /path/to/service-account.json --app my-app + + $ ably push config set-fcm --service-account /path/to/service-account.json --json +``` + +_See code: [src/commands/push/config/set-fcm.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/config/set-fcm.ts)_ + +## `ably push config show` + +Show push notification configuration for an app + +``` +USAGE + $ ably push config show [-v] [--json | --pretty-json] [--app ] + +FLAGS + -v, --verbose Output verbose logs + --app= The app ID or name (defaults to current app) + --json Output in JSON format + --pretty-json Output in colorized JSON format + +DESCRIPTION + Show push notification configuration for an app + +EXAMPLES + $ ably push config show + + $ ably push config show --app my-app + + $ ably push config show --json +``` + +_See code: [src/commands/push/config/show.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/config/show.ts)_ + +## `ably push devices` + +Manage push notification device registrations + +``` +USAGE + $ ably push devices + +DESCRIPTION + Manage push notification device registrations + +EXAMPLES + $ ably push devices list + + $ ably push devices get device-123 + + $ ably push devices save --id device-123 --platform ios --form-factor phone --transport-type apns --device-token token123 +``` + +_See code: [src/commands/push/devices/index.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/devices/index.ts)_ + +## `ably push devices get DEVICE-ID` + +Get details of a push device registration + +``` +USAGE + $ ably push devices get DEVICE-ID [-v] [--json | --pretty-json] + +ARGUMENTS + DEVICE-ID The device ID to retrieve + +FLAGS + -v, --verbose Output verbose logs + --json Output in JSON format + --pretty-json Output in colorized JSON format + +DESCRIPTION + Get details of a push device registration + +EXAMPLES + $ ably push devices get device-123 + + $ ably push devices get device-123 --json +``` + +_See code: [src/commands/push/devices/get.ts](https://github.com/ably/ably-cli/blob/v0.17.0/src/commands/push/devices/get.ts)_ + +## `ably push devices list` + +List push device registrations + +``` +USAGE + $ ably push devices list [-v] [--json | --pretty-json] [--device-id ] [--client-id ] [--state + ACTIVE|FAILING|FAILED] [--limit ] + +FLAGS + -v, --verbose Output verbose logs + --client-id= Filter by client ID + --device-id= Filter by device ID + --json Output in JSON format + --limit= [default: 100] Maximum number of results to return (default: 100) + --pretty-json Output in colorized JSON format + --state=