-
Notifications
You must be signed in to change notification settings - Fork 0
Minor Fixes: Spaces commands #185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,8 +38,6 @@ export default class SpacesMembersSubscribe extends SpacesBaseCommand { | |
| ...durationFlag, | ||
| }; | ||
|
|
||
| private listener: ((member: SpaceMember) => void) | null = null; | ||
|
|
||
| async run(): Promise<void> { | ||
| const { args, flags } = await this.parse(SpacesMembersSubscribe); | ||
| const { space_name: spaceName } = args; | ||
|
|
@@ -69,69 +67,69 @@ export default class SpacesMembersSubscribe extends SpacesBaseCommand { | |
| "subscribing", | ||
| "Subscribing to member updates", | ||
| ); | ||
| // Define the listener function | ||
| this.listener = (member: SpaceMember) => { | ||
| const now = Date.now(); | ||
|
|
||
| // Determine the action from the member's lastEvent | ||
| const action = member.lastEvent?.name || "unknown"; | ||
| const clientId = member.clientId || "Unknown"; | ||
| const connectionId = member.connectionId || "Unknown"; | ||
|
|
||
| // Skip self events - check connection ID | ||
| const selfConnectionId = this.realtimeClient!.connection.id; | ||
| if (member.connectionId === selfConnectionId) { | ||
| return; | ||
| } | ||
|
|
||
| // Create a unique key for this client+connection combination | ||
| const clientKey = `${clientId}:${connectionId}`; | ||
|
|
||
| // Check if we've seen this exact event recently (within 500ms) | ||
| const lastEvent = lastSeenEvents.get(clientKey); | ||
| const memberListener = (member: SpaceMember) => { | ||
| try { | ||
| const now = Date.now(); | ||
|
|
||
| // Determine the action from the member's lastEvent | ||
| const action = member.lastEvent?.name || "unknown"; | ||
| const clientId = member.clientId || "Unknown"; | ||
| const connectionId = member.connectionId || "Unknown"; | ||
|
|
||
| // Create a unique key for this client+connection combination | ||
| const clientKey = `${clientId}:${connectionId}`; | ||
|
|
||
| // Check if we've seen this exact event recently (within 500ms) | ||
| const lastEvent = lastSeenEvents.get(clientKey); | ||
|
|
||
| if ( | ||
| lastEvent && | ||
| lastEvent.action === action && | ||
| now - lastEvent.timestamp < 500 | ||
| ) { | ||
| this.logCliEvent( | ||
| flags, | ||
| "member", | ||
| "duplicateEventSkipped", | ||
| `Skipping duplicate event '${action}' for ${clientId}`, | ||
| { action, clientId }, | ||
| ); | ||
| return; // Skip duplicate events within 500ms window | ||
| } | ||
|
|
||
| // Update the last seen event for this client+connection | ||
| lastSeenEvents.set(clientKey, { | ||
| action, | ||
| timestamp: now, | ||
| }); | ||
|
|
||
| if ( | ||
| lastEvent && | ||
| lastEvent.action === action && | ||
| now - lastEvent.timestamp < 500 | ||
| ) { | ||
| this.logCliEvent( | ||
| flags, | ||
| "member", | ||
| "duplicateEventSkipped", | ||
| `Skipping duplicate event '${action}' for ${clientId}`, | ||
| { action, clientId }, | ||
| `update-${action}`, | ||
| `Member event '${action}' received`, | ||
| { action, clientId, connectionId }, | ||
| ); | ||
| return; // Skip duplicate events within 500ms window | ||
| } | ||
|
|
||
| // Update the last seen event for this client+connection | ||
| lastSeenEvents.set(clientKey, { | ||
| action, | ||
| timestamp: now, | ||
| }); | ||
|
|
||
| this.logCliEvent( | ||
| flags, | ||
| "member", | ||
| `update-${action}`, | ||
| `Member event '${action}' received`, | ||
| { action, clientId, connectionId }, | ||
| ); | ||
|
|
||
| if (this.shouldOutputJson(flags)) { | ||
| this.logJsonEvent({ member: formatMemberOutput(member) }, flags); | ||
| } else { | ||
| this.log( | ||
| formatTimestamp(formatMessageTimestamp(member.lastEvent.timestamp)), | ||
| ); | ||
| this.log(formatMemberEventBlock(member, action)); | ||
| this.log(""); | ||
| if (this.shouldOutputJson(flags)) { | ||
| this.logJsonEvent({ member: formatMemberOutput(member) }, flags); | ||
| } else { | ||
| this.log( | ||
| formatTimestamp( | ||
| formatMessageTimestamp(member.lastEvent.timestamp), | ||
| ), | ||
| ); | ||
|
Comment on lines
+118
to
+122
|
||
| this.log(formatMemberEventBlock(member, action)); | ||
| this.log(""); | ||
| } | ||
| } catch (error) { | ||
| this.fail(error, flags, "memberSubscribe", { spaceName }); | ||
|
Comment on lines
+119
to
+127
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: In the Citations:
🏁 Script executed: cat -n src/commands/spaces/members/subscribe.ts | head -150Repository: ably/ably-cli Length of output: 5568 🏁 Script executed: find node_modules/@ably/spaces -name "*.d.ts" -o -name "*.ts" | head -20Repository: ably/ably-cli Length of output: 117 🏁 Script executed: cat package.json | grep -A 5 "@ably/spaces"Repository: ably/ably-cli Length of output: 288 Move error handling from callback to outer catch block and use consistent optional chaining. According to More importantly, calling If keeping the try-catch for defensive programming, either make both accesses use optional chaining ( 🤖 Prompt for AI Agents |
||
| } | ||
| }; | ||
|
|
||
| // Subscribe using the stored listener | ||
| await this.space!.members.subscribe("update", this.listener); | ||
| // Subscribe using the listener | ||
| await this.space!.members.subscribe("update", memberListener); | ||
|
|
||
| this.logCliEvent( | ||
| flags, | ||
|
|
@@ -140,13 +138,6 @@ export default class SpacesMembersSubscribe extends SpacesBaseCommand { | |
| "Subscribed to member updates", | ||
| ); | ||
|
|
||
| this.logCliEvent( | ||
| flags, | ||
| "member", | ||
| "listening", | ||
| "Listening for member updates...", | ||
| ); | ||
|
|
||
| // Wait until the user interrupts or the optional duration elapses | ||
| await this.waitAndTrackCleanup(flags, "member", flags.duration); | ||
| } catch (error) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep one-shot JSON output as a single result record.
This currently emits two JSON records (
logJsonResultthenlogJsonStatus) for a one-shot command. Prefer a singlelogJsonResultpayload that includes warning metadata, and reservelogJsonStatusfor long-running status signals. Also useformatResource(...)for resource names in the human-readable warning branch.Proposed adjustment
As per coding guidelines: "Use this.logJsonResult(data, flags) for one-shot results ... this.logJsonStatus(status, message, flags) for hold/status signals in long-running commands" and "Always use formatResource(name) (cyan) for resource names instead of quoted strings."
🤖 Prompt for AI Agents