Skip to content

[DX-964] Add new spaces commands#177

Merged
umair-ably merged 3 commits intomainfrom
feature/add-new-spaces-commands
Mar 20, 2026
Merged

[DX-964] Add new spaces commands#177
umair-ably merged 3 commits intomainfrom
feature/add-new-spaces-commands

Conversation

@sacOO7
Copy link
Contributor

@sacOO7 sacOO7 commented Mar 19, 2026

Added following missing commands

  1. spaces create
  2. spaces get
  3. spaces subscribe
  4. spaces members get-all

Summary by CodeRabbit

  • New Features

    • Added ably spaces create SPACE_NAME command to create new spaces
    • Added ably spaces get SPACE_NAME command to view space state and members
    • Added ably spaces members get-all SPACE_NAME command to retrieve all members in a space
    • Added ably spaces subscribe SPACE_NAME command to monitor real-time space updates
  • Documentation

    • Extended README with new space management command documentation and examples

@vercel
Copy link

vercel bot commented Mar 19, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cli-web-cli Ready Ready Preview, Comment Mar 20, 2026 0:37am

Request Review

@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e8e9b495-60c8-438a-9976-637ab167d4be

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR introduces four new space management commands (create, get, subscribe, and members get-all) to the Ably CLI, complete with command implementations, utility updates, comprehensive test coverage, and documentation. The changes extend the spaces feature with membership and state retrieval capabilities.

Changes

Cohort / File(s) Summary
Documentation & Examples
README.md, src/commands/spaces/index.ts
Extended README with new command documentation for create, get, members get-all, and subscribe; added example usage entries in spaces index command.
Space Management Commands
src/commands/spaces/create.ts, src/commands/spaces/get.ts, src/commands/spaces/subscribe.ts
Implemented three new oclif commands: create initializes a space without entering; get retrieves presence state and member list via REST; subscribe listens to space update events with ongoing member tracking.
Space Members Command
src/commands/spaces/members/get-all.ts
Added members get-all command to fetch all current members from a specified space with formatted output support.
Output Formatting
src/utils/spaces-output.ts
Updated member block formatting to separate last event name and timestamp into distinct labeled lines.
Testing Utilities
test/helpers/mock-ably-spaces.ts
Extended MockSpace interface with subscribe, unsubscribe, and getState methods plus internal _emitter for space-level event simulation.
Command Test Suites
test/unit/commands/spaces/create.test.ts, test/unit/commands/spaces/get.test.ts, test/unit/commands/spaces/members/get-all.test.ts, test/unit/commands/spaces/subscribe.test.ts
Added comprehensive Vitest suites for each new command covering success paths, JSON output validation, error handling, and edge cases (empty members, API failures).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • jamiehenson
  • denissellu

Poem

🐰 Four new spaces to explore and command,
From creation through subscription so grand,
Members gathered, their presence displayed,
With tests for each move that our spaces have made! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change—adding four new spaces commands (create, get, subscribe, members get-all)—which aligns with the changeset's primary focus.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/add-new-spaces-commands
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/commands/spaces/get.ts (2)

128-158: Consider extracting member formatting to avoid duplication with formatMemberBlock.

The inline formatting here closely mirrors formatMemberBlock from src/utils/spaces-output.ts (context snippet 1). While the input types differ (MemberInfo vs SpaceMember), the output structure is identical.

You could either:

  1. Create a shared interface that both types satisfy for formatting purposes, or
  2. Accept this duplication given the REST-based approach in this command

This is a minor refactor opportunity that can be deferred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/spaces/get.ts` around lines 128 - 158, The member-printing loop
duplicates the output of formatMemberBlock; refactor by creating a small adapter
that converts the REST MemberInfo shape used in the get command to the shape
expected by formatMemberBlock (or introduce a shared interface both MemberInfo
and SpaceMember implement), then replace the inline logging inside the loop with
a single call to formatMemberBlock(memberAdapter) to centralize formatting and
remove duplication; reference the loop in the get command, the types MemberInfo
and SpaceMember, and the existing formatMemberBlock utility when making the
change.

17-17: Extract SPACE_CHANNEL_TAG to a shared constant file.

This constant is defined in three files: src/commands/spaces/get.ts, src/commands/spaces/occupancy/get.ts, and src/commands/spaces/occupancy/subscribe.ts. Extract it to src/utils/spaces-constants.ts to prevent divergence if the suffix changes.

♻️ Suggested refactor

Create a shared constant file:

// src/utils/spaces-constants.ts
export const SPACE_CHANNEL_TAG = "::$space";

Then import it in all three files:

-const SPACE_CHANNEL_TAG = "::$space";
+import { SPACE_CHANNEL_TAG } from "../../utils/spaces-constants.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/spaces/get.ts` at line 17, Extract the repeated constant
SPACE_CHANNEL_TAG into a single shared module (e.g., export const
SPACE_CHANNEL_TAG = "::$space" from a new spaces-constants module) and replace
the local declarations in each file with an import from that module; update the
three places where SPACE_CHANNEL_TAG is currently defined to import the shared
constant so the suffix is maintained in one location.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/spaces/members/get-all.ts`:
- Around line 35-38: Remove clientIdFlag from the static flags definition on the
get-all command: update the static override flags object (the "static override
flags" declaration in the get-all command class) to only spread productApiFlags
and remove ...clientIdFlag; also search the same class for any references to
clientIdFlag and delete or adapt them so the command remains a read-only query
using only productApiFlags.

In `@src/commands/spaces/subscribe.ts`:
- Around line 42-43: The listener stored in the property "listener" is
subscribed via this.space!.subscribe("update", this.listener) but never removed;
override or extend the class's finally() method (the one in SpacesBaseCommand or
the command class that sets this.listener) to, if this.space and this.listener
are non-null, call this.space.unsubscribe("update", this.listener), then set
this.listener = null to allow GC; ensure the unsubscribe call is guarded (check
this.space and this.listener) and placed before calling super.finally() if
applicable.

---

Nitpick comments:
In `@src/commands/spaces/get.ts`:
- Around line 128-158: The member-printing loop duplicates the output of
formatMemberBlock; refactor by creating a small adapter that converts the REST
MemberInfo shape used in the get command to the shape expected by
formatMemberBlock (or introduce a shared interface both MemberInfo and
SpaceMember implement), then replace the inline logging inside the loop with a
single call to formatMemberBlock(memberAdapter) to centralize formatting and
remove duplication; reference the loop in the get command, the types MemberInfo
and SpaceMember, and the existing formatMemberBlock utility when making the
change.
- Line 17: Extract the repeated constant SPACE_CHANNEL_TAG into a single shared
module (e.g., export const SPACE_CHANNEL_TAG = "::$space" from a new
spaces-constants module) and replace the local declarations in each file with an
import from that module; update the three places where SPACE_CHANNEL_TAG is
currently defined to import the shared constant so the suffix is maintained in
one location.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fabbcfdc-be62-4728-9cfb-dd91c60baabe

📥 Commits

Reviewing files that changed from the base of the PR and between 5692f63 and 28a33b5.

📒 Files selected for processing (12)
  • README.md
  • src/commands/spaces/create.ts
  • src/commands/spaces/get.ts
  • src/commands/spaces/index.ts
  • src/commands/spaces/members/get-all.ts
  • src/commands/spaces/subscribe.ts
  • src/utils/spaces-output.ts
  • test/helpers/mock-ably-spaces.ts
  • test/unit/commands/spaces/create.test.ts
  • test/unit/commands/spaces/get.test.ts
  • test/unit/commands/spaces/members/get-all.test.ts
  • test/unit/commands/spaces/subscribe.test.ts
👮 Files not reviewed due to content moderation or server errors (8)
  • test/helpers/mock-ably-spaces.ts
  • src/commands/spaces/index.ts
  • src/utils/spaces-output.ts
  • README.md
  • test/unit/commands/spaces/subscribe.test.ts
  • test/unit/commands/spaces/create.test.ts
  • src/commands/spaces/create.ts
  • test/unit/commands/spaces/members/get-all.test.ts

@sacOO7 sacOO7 requested review from Copilot March 19, 2026 14:58
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds missing Ably Spaces CLI commands to create/inspect/subscribe to spaces and to retrieve all space members, along with supporting mocks, output tweaks, tests, and README docs.

Changes:

  • Introduces new commands: spaces create, spaces get, spaces subscribe, and spaces members get-all.
  • Extends the Spaces test mocks and adds unit tests covering JSON and non-JSON output plus error cases.
  • Updates human-readable member output to separate “Last Event” from its timestamp, and documents the new commands in the README.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/unit/commands/spaces/subscribe.test.ts Adds unit coverage for spaces:subscribe output, JSON mode, and error handling.
test/unit/commands/spaces/members/get-all.test.ts Adds unit coverage for spaces:members:get-all including NDJSON envelopes and non-JSON display.
test/unit/commands/spaces/get.test.ts Adds unit coverage for REST-backed spaces:get behavior and parsing.
test/unit/commands/spaces/create.test.ts Adds unit coverage for spaces:create including JSON envelope and failure path.
test/helpers/mock-ably-spaces.ts Extends Spaces SDK mocks with space-level subscribe/unsubscribe/state support.
src/utils/spaces-output.ts Adjusts member block formatting to output event type and timestamp on separate lines.
src/commands/spaces/subscribe.ts Implements spaces subscribe command to stream space update events.
src/commands/spaces/members/get-all.ts Implements spaces members get-all command to retrieve all members without entering.
src/commands/spaces/index.ts Updates topic examples to include new spaces subcommands.
src/commands/spaces/get.ts Implements spaces get via REST presence query against the ::$space channel.
src/commands/spaces/create.ts Implements spaces create command behavior and JSON/human output.
README.md Documents the new spaces commands and adds them to the command index.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Collaborator

@umair-ably umair-ably left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - pushed up small bits that needed addressing

@umair-ably umair-ably merged commit c2c1d30 into main Mar 20, 2026
10 checks passed
@umair-ably umair-ably deleted the feature/add-new-spaces-commands branch March 20, 2026 12:46
@@ -0,0 +1,61 @@
import { Args } from "@oclif/core";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this command add any value? Is it misleading?

It essentially just calls spaces.get('foo') which under the hood implicitly attaches the channel. So the channel exists for a very brief period and disappears. Other commands like get will fail because there are no members.

This could be misleading as a create command usually has an air of persistence about it. So I think its better we don't have it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s true, but earlier when you looked at spaces, there wasn’t any way to tell how they were created. It also felt quite odd that a space only becomes visible when a member joins it using spaces members enter. At the moment, the spaces create command simply creates an ephemeral space. I had added an explicit description to clarify this, but it was overridden by Umair’s commit (dfd9360).

Now, when you look at the commands, it’s straightforward to create a space using spaces create, and you can also see it listed in spaces list in another terminal

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, you can see it via list - but that's misleading no? If I go and make a cup of tea between running the two commands, then suddenly the space I thought I created is no longer there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's why we had explicit description on spaces create, I feel we should revert it there or there should be clear way to communicate how spaces are initialised. From my perspective, initialising spaces using spaces members enter feels super odd.
Other way is spaces create should print warning message that, space created is ephemeral and will cease to exist if no member is entered

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be logging as a warning -> #185

);
}

const members: MemberOutput[] = items.map((item) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work how we're intending. isConnected will always be true.

This is because the endpoint being called is a instantaneous presence, so no leave or absent will be in there. The way spaces works (broadly) is that when a member leaves the space, it's retained in the spaces client for a short period before being expelled (to give the air of "so and so was here, but is no longer").

If we're intending to create that sort of behaviour here, we should use the presence history REST endpoint, which would give us our leave events and thus we could approximate that.

Alternatively, we just show "who's online right now".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can go with standard method space.getState(), but it will need to create active realtime connection and behave exactly like SDK method

const { members } = spaceState;

if (this.shouldOutputJson(flags)) {
this.logJsonEvent(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would the user expect to see here? A list of all members in the space on every change (which could be large) or just the event that's just happened?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No spaces subscribe shows both members and location change events as per doc. Command description says

DESCRIPTION
  Subscribe to both spaces members and location update events

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My question was about the volume of information rather than what information - should we be showing the member/location that changed on each listener call, or should it be everything in presence?

Copy link
Contributor Author

@sacOO7 sacOO7 Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, this behaves as per standard space.subscribe method -> https://ably.com/docs/spaces/space#subscribe

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine programatically, but what's the UX like on the CLI?

If I have 100 people in the space, 1 person changing their location means I get 100 space members dumped into my console. I've got no way of telling what happened and it its hundreds of lines of terminal buffer.

I don't think we should be following the APIs directly if the CLI experience is going to be bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per doc, that seems to be the behaviour. Seems, it should only return the changes. Maybe internally subscribing to member, location, cursor changes etc would make more sense.
I am manually checking all commands, so will cross check again.

Copy link
Contributor Author

@sacOO7 sacOO7 Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since, official doc says Subscribe to both spaces members and location update events, we should only be emitting changes to those events combined instead of the full state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be fixed as a part of -> #185

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants