-
Notifications
You must be signed in to change notification settings - Fork 61
Implement message append, protocol v5 with publish/update return values, and update/delete over realtime #2127
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
Conversation
WalkthroughAdds PublishResult and UpdateDeleteResult types and threads publish/update/delete/append responses through REST and Realtime channel APIs, transport, and queue callbacks; introduces message.append action; bumps protocol version to 5; updates internal transport/queue/connection flow and adds tests for serials, updates, deletes, and appends. Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant Channel as Channel (Rest|Realtime)
participant Protocol as Transport/Protocol
participant Queue as MessageQueue
participant Backend as Server
rect rgb(235,248,255)
Note over App,Backend: Publish (single or batch)
App->>Channel: publish(messages)
Channel->>Protocol: send(ProtocolMessage with body)
Protocol->>Queue: queue(PendingMessage with PublishCallback)
Queue->>Backend: network send
Backend-->>Protocol: ACK(serial, count, res[])
Protocol->>Queue: completeMessages({serial,count}, null, res[])
Queue->>Queue: invoke each callback(err, publishResponse)
Channel-->>App: resolve Promise<PublishResult> { serials: [...] }
end
rect rgb(255,245,235)
Note over App,Backend: Update / Delete / Append
App->>Channel: updateMessage(...) / deleteMessage(...) / appendMessage(...)
Channel->>Channel: sendUpdate(message, action, op)
Channel->>Protocol: send(ProtocolMessage action=message.update|.delete|.append)
Protocol->>Queue: queue(PendingMessage with PublishCallback)
Queue->>Backend: network send
Backend-->>Protocol: ACK(serial, count, res[] with version)
Protocol->>Queue: completeMessages({serial,count}, null, res[])
Queue->>Queue: invoke callback(err, publishResponse)
Channel-->>App: resolve Promise<UpdateDeleteResult> { versionSerial: "..." }
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~55 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
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.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ably.d.ts (1)
1451-1465: Public typings for publish/update/delete/append and new MESSAGE_APPEND action look consistent with implementation
- Adding
serials: (string | null)[]toBatchPublishSuccessResultand introducingPublishResult/UpdateDeleteResultmatches the new protocol responses and REST/realtime implementations.- Updating
Channel.publishandRealtimeChannel.publishoverloads to returnPromise<PublishResult>(and corresponding doc changes) aligns withRestChannel.publishandRealtimeChannel.publishnow returningPublishResponse.- Exposing
updateMessage/deleteMessage/appendMessageas returningPromise<UpdateDeleteResult>fits the new REST and realtime flows, which always return an object with aversionfield.- Adding
MessageActions.MESSAGE_APPENDand extendingMessageActionwithMESSAGE_APPENDdovetails with the new'message.append'operation used in both REST and realtime paths.One consideration: the public types narrow
serialsfrom optional (in internalPublishResponse) to required (in publicPublishResult). The realtime implementation defensively resolvespublishResponse || {}when the callback fires, and update/delete operations access serials with optional chainingserials?.[0]. This assumes protocol v5+ always populatesserialsfor successful publish operations—tests confirm it currently does, but if backwards compatibility with older protocol versions or edge cases becomes relevant, the required-type assumption may need revisiting.
🧹 Nitpick comments (3)
src/common/lib/client/restchannelmixin.ts (1)
11-12: Update/delete/append over REST are wired cleanlyThe refactor to build a fresh
requestMessage, encode it, and PATCH/messages/{serial}while returning a decodedUpdateDeleteResponse(or{ version: null }) is sound and keeps the caller’sMessageimmutable. Only minor nit: the error string “cannot be updated” now also covers delete/append – consider slightly more generic wording if you touch this again.Also applies to: 93-139
src/common/lib/client/realtimechannel.ts (2)
2-6: Realtime publish now returns protocol publish metadata as intendedChanging
publish(...args)andsendMessageto returnPromise<PublishResponse>cleanly exposes per-message serials from the transport layer. ThepublishResponse || {}fallback is safe given thatPublishResponse.serialsis optional, and keeps callers from having to handleundefined.If you want stricter guarantees in the future (to better align with the public
PublishResult.serialsalways being present), you could default to{ serials: [] }rather than{}when no response is provided.- } else { - resolve(publishResponse || {}); - } + } else { + resolve(publishResponse || { serials: [] }); + }Also applies to: 244-287, 493-503
1030-1088: sendUpdate flow is solid but could mirror REST’s request shape more closelyThe realtime
updateMessage/deleteMessage/appendMessagehelpers correctly:
- Require
message.serial.- Check channel/connection are publishable.
- Encode a single MESSAGE with the appropriate action.
- Return
UpdateDeleteResponseusingpublishResponse.serials?.[0] ?? null.One small improvement would be to align the constructed
Messagewith the REST path and avoid spreading the entire originalmessage, to reduce risk of sending unintended fields:- const updateDeleteMsg = Message.fromValues({ - ...message, - action: action, - }); - if (operation) { - updateDeleteMsg.version = operation; - } + const updateDeleteMsg = Message.fromValues({ + action, + serial: message.serial, + name: message.name, + data: message.data, + extras: message.extras, + }); + if (operation) { + updateDeleteMsg.version = operation; + }This would match
RestChannelMixin.updateDeleteMessageand keep the wire payload minimal.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (15)
ably.d.ts(8 hunks)src/common/lib/client/realtimeannotations.ts(1 hunks)src/common/lib/client/realtimechannel.ts(5 hunks)src/common/lib/client/restchannel.ts(4 hunks)src/common/lib/client/restchannelmixin.ts(3 hunks)src/common/lib/transport/connectionmanager.ts(3 hunks)src/common/lib/transport/messagequeue.ts(3 hunks)src/common/lib/transport/protocol.ts(2 hunks)src/common/lib/transport/transport.ts(1 hunks)src/common/lib/types/message.ts(1 hunks)src/common/lib/types/protocolmessage.ts(2 hunks)src/common/lib/util/defaults.ts(1 hunks)test/realtime/message.test.js(0 hunks)test/realtime/updates-deletes.test.js(1 hunks)test/rest/updates-deletes.test.js(8 hunks)
💤 Files with no reviewable changes (1)
- test/realtime/message.test.js
🧰 Additional context used
🧬 Code graph analysis (10)
test/rest/updates-deletes.test.js (2)
src/common/lib/client/realtimechannel.ts (2)
updateMessage(1030-1037)appendMessage(1048-1055)src/common/lib/client/restchannel.ts (2)
updateMessage(172-179)appendMessage(190-197)
src/common/lib/types/message.ts (2)
src/common/lib/types/protocolmessagecommon.ts (1)
actions(5-28)ably.d.ts (1)
MessageAction(3572-3578)
src/common/lib/transport/messagequeue.ts (1)
src/common/lib/types/protocolmessage.ts (1)
PublishResponse(152-154)
src/common/lib/transport/protocol.ts (1)
src/common/lib/types/protocolmessage.ts (1)
PublishResponse(152-154)
src/common/lib/client/realtimeannotations.ts (2)
ably.d.ts (2)
Message(3311-3369)Annotation(3374-3429)src/common/lib/util/utils.ts (1)
Properties(479-479)
test/realtime/updates-deletes.test.js (2)
src/common/lib/client/realtimechannel.ts (2)
updateMessage(1030-1037)appendMessage(1048-1055)src/common/lib/client/restchannel.ts (2)
updateMessage(172-179)appendMessage(190-197)
src/common/lib/transport/connectionmanager.ts (1)
src/common/lib/transport/protocol.ts (2)
PublishCallback(11-11)PendingMessage(13-30)
src/common/lib/client/restchannel.ts (2)
src/common/lib/types/protocolmessage.ts (2)
PublishResponse(152-154)UpdateDeleteResponse(156-158)src/common/types/http.ts (1)
RequestBody(26-29)
src/common/lib/client/restchannelmixin.ts (2)
ably.d.ts (2)
Message(3311-3369)MessageOperation(3494-3507)src/common/lib/types/protocolmessage.ts (1)
UpdateDeleteResponse(156-158)
src/common/lib/client/realtimechannel.ts (1)
src/common/lib/types/protocolmessage.ts (2)
PublishResponse(152-154)UpdateDeleteResponse(156-158)
🪛 GitHub Actions: Lint
src/common/lib/client/realtimechannel.ts
[error] 1033-1033: ESLint: '_params' is defined but never used. (@typescript-eslint/no-unused-vars)
🪛 GitHub Check: lint
src/common/lib/transport/connectionmanager.ts
[failure] 5-5:
'PublishResponse' is defined but never used. Allowed unused vars must match /^_/u
[failure] 1807-1807:
'lastQueued' is assigned a value but never used. Allowed unused vars must match /^_/u
src/common/lib/client/realtimechannel.ts
[failure] 1051-1051:
'_params' is defined but never used
[failure] 1042-1042:
'_params' is defined but never used
[failure] 1033-1033:
'_params' is defined but never used
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: test-node (20.x)
- GitHub Check: test-node (18.x)
- GitHub Check: test-node (16.x)
- GitHub Check: test-npm-package
- GitHub Check: test-browser (firefox)
- GitHub Check: test-browser (chromium)
- GitHub Check: test-browser (webkit)
🔇 Additional comments (21)
src/common/lib/util/defaults.ts (1)
94-94: Protocol version upgrade to v5 is correctly implemented.The change properly updates the protocol version across all layers: REST headers via
defaultGetHeaders/defaultPostHeaders, realtime connections viaconnectionmanager.ts, and connection parameters. No hardcoded v4 references remain in the codebase. The implementation allows version override via therequest()method parameter, enabling flexibility for testing.src/common/lib/types/message.ts (3)
23-30: LGTM! Actions array correctly updated.The addition of 'message.append' to the actions array aligns with the protocol v5 upgrade and the MessageAction type definition in the public API.
32-34: LGTM! Improved type safety.The updated return type
API.MessageActionprovides better type safety while remaining backward compatible.
36-38: LGTM! Useful encoding helper.The
encodeActionfunction provides the inverse operation tostringifyAction, enabling conversion from MessageAction strings to their numeric indices. The default to 'message.create' is appropriate.src/common/lib/transport/transport.ts (1)
164-164: LGTM! ACK handler correctly propagates response data.The addition of
message.resas a third argument to the 'ack' event emission enables the transport layer to propagate PublishResponse data, supporting the protocol v5 upgrade for publish/update return values.src/common/lib/client/realtimeannotations.ts (1)
48-48: LGTM! Explicit await improves error propagation.The change from
returntoawaitfor async operations ensures errors are caught and propagated in the current execution context, improving error handling consistency across publish/update/delete flows.Also applies to: 53-53
src/common/lib/types/protocolmessage.ts (2)
152-158: LGTM! New response types support protocol v5.The
PublishResponseandUpdateDeleteResponsetypes provide the structure for returning publish/update/delete operation results, enabling per-message serials and version metadata.
184-184: LGTM! ProtocolMessage extended with response field.The addition of
res?: PublishResponse[]enables the protocol message to carry response data for publish operations, supporting the new return value semantics in protocol v5.test/rest/updates-deletes.test.js (4)
23-55: LGTM! Comprehensive publish serial tests.The tests correctly validate that publish operations return serials for both single and batch messages, confirming the protocol v5 enhancement.
62-93: LGTM! getMessage tests validate serial-based retrieval.The tests properly verify getMessage functionality with both string serials and Message objects, aligning with the new serial-based retrieval pattern.
99-181: LGTM! Update and delete operations thoroughly tested.The tests validate operation metadata (clientId, description, metadata) and version tracking for both update and delete operations. The use of
waitForappropriately handles eventual consistency.
286-341: LGTM! Append operation test validates message concatenation.The test properly verifies that appendMessage appends data, maintains operation metadata, and that the action is correctly set to 'message.update' after the append completes. The serial-based verification approach is consistent with other tests.
test/realtime/updates-deletes.test.js (3)
23-67: LGTM! Realtime publish serial tests.The tests correctly validate that publish operations over realtime return serials for both single and batch messages, with proper resource cleanup using
realtime.close().
72-171: LGTM! Realtime update and delete operations well-tested.The tests properly use channel subscriptions to capture update and delete events, validating all aspects of the operation including version metadata, clientId, description, and metadata fields. The promise-based approach correctly handles asynchronous event delivery.
212-280: LGTM! Append test includes reattach verification.The test thoroughly validates the append operation by first capturing the append event, then reattaching with rewind to verify the full concatenated message. This confirms both the immediate append event and the eventual consistency of the message state.
src/common/lib/transport/messagequeue.ts (1)
43-65: LGTM! Message completion updated to propagate PublishResponse.The
completeMessagesmethod now correctly propagates PublishResponse data to per-message callbacks. The iteration properly maps each response to its corresponding message using the array index.Note: This changes the callback signature from
(err)to(err, publishResponse). Existing callbacks that only expect an error parameter will continue to work due to JavaScript's flexible argument handling.src/common/lib/transport/connectionmanager.ts (1)
1751-1751: LGTM! Callback signature updated for PublishResponse support.The
sendmethod signature correctly updated to usePublishCallbackinstead ofErrCallback, enabling the propagation of PublishResponse data through the messaging pipeline.src/common/lib/transport/protocol.ts (2)
2-3: Publish callback type change is coherent with new response shapeUsing
PublishCallback = StandardCallback<PublishResponse>and updatingPendingMessage.callbackkeeps the callback contract clear while enabling response metadata.ackRequiredgating remains unchanged and appropriate.Also applies to: 9-12, 15-29
36-42: Confirmed:ackemitter signature properly wired across all implementationsTransport base class correctly emits
ackevents with(message.msgSerial, message.count, message.res). Protocol listener receives this as(serial, count, res?: PublishResponse[])and passesrestoMessageQueue.completeMessages(), which has the signature(serial, count, err?, res?)and properly uses it at the callback site. Both WebSocketTransport and CometTransport inherit this behavior without override. Thenackpath correctly omitsressince NACK messages don't carry publish responses.src/common/lib/client/restchannel.ts (1)
19-26: REST publish and update/delete/append result plumbing looks correctNormalizing the POST response into
RestPublishResponseand then returning a barePublishResponsefrom_publishis tidy, and the newupdateMessage/deleteMessage/appendMessagewrappers cleanly delegate tochannelMixin.updateDeleteMessagewith the appropriate action and returnUpdateDeleteResponse. No issues spotted.Also applies to: 81-161, 172-197
src/common/lib/client/realtimechannel.ts (1)
505-512: sendPresence/sendState use sendMessage consistentlyPresence and objects state now go through
sendMessageand await its completion, so they’ll correctly propagate errors from the connection manager while ignoring the publish metadata they don’t need. This keeps all messaging paths uniform.Also applies to: 514-521
6600755 to
b28b6c0
Compare
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.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
b28b6c0 to
ff35286
Compare
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/common/lib/client/restchannelmixin.ts (2)
93-99: Consider renaming method to reflect append capability.The method name
updateDeleteMessageno longer accurately describes its functionality now that it also handles'message.append'. Consider renaming to something likeupdateDeleteAppendMessageor a more genericmodifyMessagefor clarity.This is a minor inconsistency and can be deferred if backwards compatibility is a concern.
126-127: Simplify: remove unnecessary variable assignment.
methodis assigned but never conditionally changed. CallResource.patchdirectly.- let method = Resource.patch; - const { body, unpacked } = await method<UpdateDeleteResponse>( + const { body, unpacked } = await Resource.patch<UpdateDeleteResponse>(
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
src/common/lib/client/realtimechannel.ts(5 hunks)src/common/lib/client/restchannel.ts(4 hunks)src/common/lib/client/restchannelmixin.ts(3 hunks)src/common/lib/transport/connectionmanager.ts(3 hunks)src/common/lib/types/protocolmessage.ts(2 hunks)src/platform/react-hooks/src/hooks/useChannelAttach.ts(1 hunks)test/realtime/message.test.js(0 hunks)test/realtime/updates-deletes.test.js(1 hunks)
💤 Files with no reviewable changes (1)
- test/realtime/message.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
- test/realtime/updates-deletes.test.js
🔇 Additional comments (13)
src/platform/react-hooks/src/hooks/useChannelAttach.ts (1)
42-42: LGTM! Proper React hooks compliance.Adding
ablyto the dependency array is correct since it's referenced inside the effect (line 39). This ensures the effect re-runs when the Ably instance changes, triggering a re-attachment with the new instance.src/common/lib/types/protocolmessage.ts (2)
152-158: LGTM! Protocol v5 response types are well-defined.The new
PublishResponseandUpdateDeleteResponsetypes clearly define the response shapes for publish/update/delete/append operations. The nullable types (string | nulland(string | null)[]) appropriately handle cases where values may be absent in protocol responses.
184-184: LGTM! PublishResponse array field appropriately added.The optional
resfield correctly allows a ProtocolMessage to carry multiple publish responses, consistent with the protocol v5 upgrade.src/common/lib/transport/connectionmanager.ts (3)
7-7: LGTM! Callback type import updated for protocol v5.The import change from
ErrCallbacktoPublishCallbackaligns with the protocol v5 upgrade that introduces publish/update/delete return values.
1747-1747: LGTM! Send method signature updated correctly.The
sendmethod callback parameter type correctly changed toPublishCallback, consistent with the protocol v5 changes that enable returning publish responses to callers.
1801-1803: LGTM! Queue method updated and past issue resolved.The
queuemethod callback parameter correctly changed toPublishCallback. The previously flagged unused variables (lastQueuedandmaxSize) have been removed, leaving a clean implementation that simply logs and queues the message.src/common/lib/client/restchannelmixin.ts (2)
11-11: LGTM!Import aligns with the new return type for
updateDeleteMessage.
113-121: Good practice: constructing new Message to avoid mutation.Creating a new
MessageviafromValues()instead of mutating the input is the right approach. This prevents unexpected side effects for callers.src/common/lib/client/restchannel.ts (2)
157-160: Delete operations on potentially missing keys are safe but worth noting.The code handles both unpacked and non-unpacked responses correctly, defaulting to an empty object. The
deleteoperations onchannelandmessageIdare safe even if these keys don't exist, which is appropriate here since these fields are being intentionally stripped from the RestPublishResponse before returning a PublishResponse.
172-197: LGTM! Clean delegation pattern for update/delete/append operations.All three methods (
updateMessage,deleteMessage,appendMessage) follow a consistent delegation pattern toupdateDeleteMessage, appropriately differentiating operations via the action parameter. The return type changes toPromise<UpdateDeleteResponse>align with the PR objectives.src/common/lib/client/realtimechannel.ts (3)
493-521: LGTM! sendMessage propagates PublishResponse correctly.The
sendMessagemethod now correctly returnsPromise<PublishResponse>(line 493) and defaults to an empty object if the response is undefined (line 499). ThesendPresenceandsendStatemethods appropriately consume the response viaawaitwithout exposing it to their callers, maintaining theirPromise<void>return types.
1030-1052: LGTM! Lint issue resolved and clean delegation pattern.The previously reported
@typescript-eslint/no-unused-varsissue with the_paramsparameter has been resolved by removing it from the signatures. All three methods (updateMessage,deleteMessage,appendMessage) now follow a consistent pattern, delegating to the newsendUpdatehelper with appropriate action strings.
1054-1085: Implementation is sound.Verified that
PublishResponse.serialsis correctly defined as an optional array of(string | null)[]in the codebase (src/common/lib/types/protocolmessage.ts:153). The code correctly:
- Uses optional chaining
?.to handle undefined serials- Accesses
[0]appropriately for the single message being sent- Uses nullish coalescing
?? nullto handle null elements (which occur when messages are discarded due to conflation rules)The implementation matches the documented behavior that serials is an array with 1:1 correspondence to published messages.
ff35286 to
704a9ad
Compare
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/common/lib/client/restchannelmixin.ts (1)
121-121: Useconstinstead ofletfor method.The
methodvariable is never reassigned, so it should be declared withconstfor better code clarity and to prevent accidental reassignment.Apply this diff:
- let method = Resource.patch; + const method = Resource.patch;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
src/common/lib/client/restchannelmixin.ts(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/common/lib/client/restchannelmixin.ts (3)
ably.d.ts (1)
Message(3311-3369)src/common/lib/types/protocolmessage.ts (1)
UpdateDeleteResponse(156-158)src/common/lib/types/basemessage.ts (1)
CipherOptions(13-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: test-browser (webkit)
- GitHub Check: test-node (18.x)
- GitHub Check: test-node (16.x)
- GitHub Check: test-browser (chromium)
- GitHub Check: test-browser (firefox)
- GitHub Check: test-node (20.x)
- GitHub Check: test-npm-package
🔇 Additional comments (4)
src/common/lib/client/restchannelmixin.ts (4)
11-11: LGTM!The import of
UpdateDeleteResponsecorrectly supports the new return type for theupdateDeleteMessagemethod.
113-119: LGTM!Creating a new
MessageviaMessage.fromValuesinstead of mutating the input message is good practice. The encoding flow is clean and consistent.
132-134: LGTM!The response handling with a fallback to
{ version: null }is appropriate defensive coding, ensuring the method always returns a validUpdateDeleteResponseeven if the server response body is empty or null.
93-99: No type compatibility issues exist. The method signature change improves clarity by using explicit action parameter and explicit return type. The action parameter correctly maps toAPI.MessageAction, and theMessageOperationargument is structurally compatible with theMessage.versionproperty of typeAPI.MessageVersion.
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.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/common/lib/client/restchannelmixin.ts (1)
120-121: Consider inlining the method variable.The
methodvariable is assigned but only used once immediately after. Since all update/delete/append operations now use PATCH, this could be simplified.🔎 Suggested simplification:
- let method = Resource.patch; - const { body, unpacked } = await method<API.UpdateDeleteResult>( + const { body, unpacked } = await Resource.patch<API.UpdateDeleteResult>(
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
ably.d.ts(8 hunks)src/common/lib/client/realtimechannel.ts(5 hunks)src/common/lib/client/restchannel.ts(4 hunks)src/common/lib/client/restchannelmixin.ts(2 hunks)src/common/lib/transport/messagequeue.ts(3 hunks)src/common/lib/transport/protocol.ts(2 hunks)src/common/lib/types/protocolmessage.ts(1 hunks)test/realtime/updates-deletes.test.js(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- test/realtime/updates-deletes.test.js
- src/common/lib/types/protocolmessage.ts
🧰 Additional context used
🧬 Code graph analysis (3)
src/common/lib/transport/messagequeue.ts (1)
ably.d.ts (1)
PublishResult(3512-3518)
src/common/lib/client/restchannelmixin.ts (1)
src/common/lib/types/basemessage.ts (1)
CipherOptions(13-24)
src/common/lib/client/restchannel.ts (2)
ably.d.ts (3)
PublishResult(3512-3518)Message(3311-3369)MessageOperation(3494-3507)src/common/types/http.ts (1)
RequestBody(26-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: test-node (18.x)
- GitHub Check: test-node (20.x)
- GitHub Check: test-node (16.x)
- GitHub Check: test-browser (firefox)
- GitHub Check: test-browser (webkit)
- GitHub Check: test-browser (chromium)
- GitHub Check: test-npm-package
🔇 Additional comments (19)
src/common/lib/transport/messagequeue.ts (1)
43-65: LGTM! The indexed iteration correctly correlates publish responses with messages.The refactored loop properly passes
publishResponse(if available) from theresarray to each message's callback by index. This aligns with thePublishCallbacktype signature inprotocol.ts.One consideration: the code assumes
resarray (when present) has at least as many elements ascompleteMessages. If the server ever returns fewer elements,res?.[i]would beundefined, which is safely handled by the optional chaining. This appears intentional given thePublishResult.serialscan contain null entries per the type definition.src/common/lib/transport/protocol.ts (2)
9-12: LGTM! Clean type definition for PublishCallback.The
PublishCallbacktype alias correctly wrapsAPI.PublishResultinStandardCallback, providing proper typing for the callback chain. The import of bothStandardCallbackandErrCallbackis appropriate sinceErrCallbackis still used inonceIdle.
41-51: LGTM! Consistent propagation of publish results through the ack flow.The changes correctly thread the
resparameter from the transport'sackevent throughonAcktocompleteMessages. The optional typing (res?: API.PublishResult[]) appropriately handles cases where the response may not be present.src/common/lib/client/restchannelmixin.ts (2)
112-118: LGTM! Clean message construction avoiding mutation of user's input.Creating a new
MessageviafromValuesand then assigningactionandversionproperties correctly avoids mutating the original message object passed by the user. This is a good practice for API design.
131-132: LGTM! Safe fallback for missing response body.The fallback
{ versionSerial: null }correctly handles cases where the response body might be empty or undefined, matching theUpdateDeleteResultinterface contract whereversionSerialcan be null when a message was superseded.src/common/lib/client/restchannel.ts (3)
24-25: LGTM! Clean type extension for internal response handling.The
RestPublishResponsetype correctly extendsAPI.PublishResultwith optional internal fields (channel,messageId) that are stripped before returning to the caller.
140-161: LGTM! Response handling correctly decodes and sanitizes the publish result.The implementation properly:
- Decodes the response body based on format (binary/JSON)
- Falls back to an empty object if body is undefined
- Strips internal-only fields (
channel,messageId) before returningThe
deleteoperations mutate the decoded object, but since this is a freshly decoded object (not user-provided), this is acceptable.
191-198: LGTM! New appendMessage method follows the established pattern.The
appendMessageimplementation correctly delegates toupdateDeleteMessagewith the'message.append'action, maintaining consistency withupdateMessageanddeleteMessage.src/common/lib/client/realtimechannel.ts (4)
240-283: LGTM! Publish flow correctly returns PublishResult.The updated
publishmethod properly:
- Returns
Promise<API.PublishResult>- Propagates the response from
sendMessage- Provides a safe fallback
{ serials: [] }when response is undefined
490-500: LGTM! sendMessage correctly typed for optional PublishResult.The return type
Promise<API.PublishResult | undefined>correctly reflects that not all protocol messages (e.g., ATTACH, DETACH) return a publish result. The callback parameterpublishResponseis properly propagated.
1027-1040: LGTM! Update/delete/append methods correctly delegate to sendUpdate.The refactored methods are cleaner than the previous implementation:
- Removed the unused
_paramsparameter (addressing the past lint issue)- All three methods consistently delegate to
sendUpdatewith the appropriate action- Return type
Promise<API.UpdateDeleteResult>matches the API contract
1042-1073: LGTM! sendUpdate implements realtime update/delete/append correctly.The private
sendUpdatemethod properly:
- Validates message serial presence with a clear error message
- Checks publishable state before proceeding
- Constructs a new Message to avoid mutating the input
- Encodes and wraps in a protocol message
- Extracts
versionSerialfrom the first serial in the responseMinor observation: Line 1072 uses optional chaining (
publishResponse?.serials?.[0]) which safely handles edge cases where the response or serials array might be missing.ably.d.ts (7)
1460-1464: LGTM: Well-documented serials field additionThe addition of the
serialsarray toBatchPublishSuccessResultis consistent with the newPublishResultinterface and properly documents the 1:1 mapping to published messages, including the null case for conflated messages.
3509-3529: LGTM: Clean and well-documented result interfacesThe new
PublishResultandUpdateDeleteResultinterfaces provide clear return types for the protocol v5 publish and update/delete operations. The nullable fields are appropriately documented for edge cases (conflation and superseded updates).
3561-3578: LGTM: MESSAGE_APPEND properly integratedThe new
MESSAGE_APPENDaction type is properly added to both theMessageActionsnamespace and theMessageActionunion type, following the existing pattern. The documentation clearly explains the append semantics.
2807-2826: Breaking change: Publish methods now return PublishResultThe
publishmethod overloads now returnPromise<PublishResult>instead ofPromise<void>. This is a breaking change to the public API that allows callers to access the serials of published messages.This appears intentional for the protocol v5 upgrade, but please confirm:
- Is this a documented breaking change for v5?
- Are there migration notes for users upgrading from v4?
2848-2878: LGTM: Well-designed message mutation APIThe new
updateMessage,deleteMessage, andappendMessagemethods provide a consistent API for message mutations. The documentation clearly explains:
- Patch semantics for update/delete (non-null fields replace)
- Append semantics (data appended, other fields replace)
- Return type includes versionSerial for tracking
The API design is clean and consistent across all three operations.
3079-3095: LGTM: Realtime publish methods consistent with RESTThe
RealtimeChannel.publishoverloads are updated consistently with theChannelinterface, all returningPromise<PublishResult>. This maintains consistency between REST and Realtime APIs.
3117-3147: LGTM: Realtime message mutations match REST interfaceThe
updateMessage,deleteMessage, andappendMessagemethods onRealtimeChannelare perfectly consistent with theChannelinterface, maintaining API parity between REST and Realtime clients.
1067c51 to
7ece4a5
Compare
Missed in abf2a71. Copied from [1] at faf7497. [1] ably/ably-js#2127
ttypic
left a comment
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.
LGTM
requiring protocolv5 acks. also add the corresponding publish response for publish().
Not very useful, not done by any other sdks, and would be annoying to implement with the new ack protocol (handling res in the multicaster), so just removing it.
psdr5: server always sends serials, it's up to us to extract the version if it's an update
the code was intercepting it to return nothing, but expecting the publish call to still work without error..?
faf7497 to
77e76e0
Compare
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/common/lib/client/restchannel.ts (1)
140-162: Consider validation of empty response scenario.The decoding logic properly handles both unpacked and packed responses and correctly removes extraneous
channelandmessageIdfields from the final result.However, the fallback to an empty object on line 158 could potentially mask server errors:
const decoded = (unpacked ? body : Utils.decodeBody<RestPublishResponse>(body, client._MsgPack, format)) || ({} as RestPublishResponse);If the server returns
nullorundefined, this would return{}which doesn't match thePublishResultinterface (missing requiredserialsproperty). While the tests would catch this, it might be clearer to throw an error or at least ensure a valid shape.🔎 Alternative approach with validation
const decoded = (unpacked ? body : Utils.decodeBody<RestPublishResponse>(body, client._MsgPack, format)) || - ({} as RestPublishResponse); + ({ serials: [] } as RestPublishResponse); delete decoded['channel']; delete decoded['messageId']; return decoded;Or throw an error if the response is unexpectedly empty:
const decoded = - (unpacked ? body : Utils.decodeBody<RestPublishResponse>(body, client._MsgPack, format)) || - ({} as RestPublishResponse); + unpacked ? body : Utils.decodeBody<RestPublishResponse>(body, client._MsgPack, format); +if (!decoded) { + throw new ErrorInfo('Empty response from server', 50000, 500); +} delete decoded['channel']; delete decoded['messageId']; return decoded;src/common/lib/client/realtimechannel.ts (1)
1035-1060: Consider renaming parameter for consistency.The implementation uses
paramsas the parameter name, while the type definition inably.d.tsusesoptions. For better documentation and code consistency, consider renaming the parameter to match:Optional refactor for parameter naming
async updateMessage( message: Message, operation?: API.MessageOperation, - params?: Record<string, any>, + options?: Record<string, any>, ): Promise<API.UpdateDeleteResult> { Logger.logAction(this.logger, Logger.LOG_MICRO, 'RealtimeChannel.updateMessage()', 'channel = ' + this.name); - return this.sendUpdate(message, 'message.update', operation, params); + return this.sendUpdate(message, 'message.update', operation, options); } async deleteMessage( message: Message, operation?: API.MessageOperation, - params?: Record<string, any>, + options?: Record<string, any>, ): Promise<API.UpdateDeleteResult> { Logger.logAction(this.logger, Logger.LOG_MICRO, 'RealtimeChannel.deleteMessage()', 'channel = ' + this.name); - return this.sendUpdate(message, 'message.delete', operation, params); + return this.sendUpdate(message, 'message.delete', operation, options); } async appendMessage( message: Message, operation?: API.MessageOperation, - params?: Record<string, any>, + options?: Record<string, any>, ): Promise<API.UpdateDeleteResult> { Logger.logAction(this.logger, Logger.LOG_MICRO, 'RealtimeChannel.appendMessage()', 'channel = ' + this.name); - return this.sendUpdate(message, 'message.append', operation, params); + return this.sendUpdate(message, 'message.append', operation, options); }And update the
sendUpdatesignature accordingly.Note: The
Record<string, any>type in the implementation is more permissive than thePublishOptionstype in the definition, but since line 1089 callsUtils.stringifyValues(), the actual behavior should be safe.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (20)
ably.d.tssrc/common/lib/client/realtimeannotations.tssrc/common/lib/client/realtimechannel.tssrc/common/lib/client/restchannel.tssrc/common/lib/client/restchannelmixin.tssrc/common/lib/transport/connectionmanager.tssrc/common/lib/transport/messagequeue.tssrc/common/lib/transport/protocol.tssrc/common/lib/transport/transport.tssrc/common/lib/types/message.tssrc/common/lib/types/protocolmessage.tssrc/common/lib/util/defaults.tssrc/common/lib/util/utils.tssrc/platform/react-hooks/src/hooks/useChannelAttach.tstest/browser/modular.test.jstest/realtime/init.test.jstest/realtime/message.test.jstest/realtime/updates-deletes.test.jstest/rest/http.test.jstest/rest/updates-deletes.test.js
💤 Files with no reviewable changes (1)
- test/realtime/message.test.js
🚧 Files skipped from review as they are similar to previous changes (7)
- src/common/lib/types/message.ts
- test/browser/modular.test.js
- test/realtime/init.test.js
- src/common/lib/types/protocolmessage.ts
- test/realtime/updates-deletes.test.js
- src/common/lib/client/restchannelmixin.ts
- src/common/lib/util/defaults.ts
🧰 Additional context used
🧬 Code graph analysis (7)
src/common/lib/util/utils.ts (1)
scripts/processPrivateApiData/dto.ts (1)
Record(53-53)
src/common/lib/transport/messagequeue.ts (1)
ably.d.ts (1)
PublishResult(3000-3006)
test/rest/updates-deletes.test.js (2)
src/common/lib/client/realtimechannel.ts (2)
updateMessage(1035-1042)appendMessage(1053-1060)src/common/lib/client/restchannel.ts (2)
updateMessage(173-180)appendMessage(191-198)
src/common/lib/client/realtimeannotations.ts (2)
ably.d.ts (2)
Message(2799-2857)Annotation(2862-2917)src/common/lib/util/utils.ts (1)
Properties(483-483)
src/common/lib/client/restchannel.ts (2)
ably.d.ts (4)
PublishResult(3000-3006)Message(2799-2857)MessageOperation(2982-2995)UpdateDeleteResult(3011-3017)src/common/types/http.ts (1)
RequestBody(26-29)
src/common/lib/transport/protocol.ts (2)
ably.d.ts (1)
PublishResult(3000-3006)src/common/lib/transport/messagequeue.ts (1)
count(15-17)
src/common/lib/transport/connectionmanager.ts (1)
src/common/lib/transport/protocol.ts (2)
PublishCallback(12-12)PendingMessage(14-31)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: test-node (18.x)
- GitHub Check: test-node (16.x)
- GitHub Check: test-node (20.x)
- GitHub Check: test-browser (chromium)
- GitHub Check: test-browser (firefox)
- GitHub Check: test-browser (webkit)
- GitHub Check: test-npm-package
🔇 Additional comments (23)
src/platform/react-hooks/src/hooks/useChannelAttach.ts (1)
42-42: LGTM! Correct dependency array fix.Adding
ablyto the dependency array ensures the effect re-runs when the Ably client instance changes, preventing stale closures and ensuring correct attachment behavior.src/common/lib/util/utils.ts (1)
248-250: LGTM! Clean utility function.The
stringifyValuesfunction provides a straightforward way to convert all record values to strings. The implementation usingObject.fromEntriesandString(v)is clear and appropriate.test/rest/http.test.js (1)
37-37: LGTM! Protocol version update.The test correctly reflects the protocol version bump to v5, consistent with the broader PR changes.
src/common/lib/client/realtimeannotations.ts (2)
48-48: LGTM! Explicit await improves clarity.Changing from
returntoawaitmakes it explicit that the operation completes before the function returns. Since bothpublishanddeleteareasyncfunctions returningPromise<void>, this change has no functional impact but improves code readability.
53-53: LGTM! Consistent async/await pattern.The change from
returntoawaitaligns with the pattern used in thepublishmethod above, maintaining consistency across the annotation publishing flow.src/common/lib/transport/transport.ts (1)
164-164: All 'ack' event listeners properly handle the new third parameter.Verification found one 'ack' event listener at
src/common/lib/transport/protocol.ts:41, which correctly accepts the newresparameter with proper typingres?: API.PublishResult[]. The correspondingonAckmethod at line 49 also properly handles and propagates this parameter tomessageQueue.completeMessages().test/rest/updates-deletes.test.js (3)
23-55: LGTM! Good test coverage for publish serials.The tests properly validate that:
- Single message publish returns a serials array with one element
- Batch publish returns multiple serials corresponding to the number of messages
- Each serial is a string
67-68: LGTM! Proper use of publish result serials.All tests have been correctly updated to destructure and use the serials returned from publish operations. The pattern is consistent throughout the test suite.
286-341: LGTM! Comprehensive test coverage for appendMessage.The tests properly validate:
- appendMessage returns an UpdateDeleteResult with versionSerial
- String data is concatenated correctly ('Hello' + ' World' = 'Hello World')
- Operation metadata (clientId, description, metadata) is preserved in the version
- Error handling when serial is missing (error code 40003)
src/common/lib/transport/messagequeue.ts (1)
48-88: LGTM! Proper threading of PublishResult to callbacks.The implementation correctly:
- Accepts an optional
resparameter for backwards compatibility- Uses optional chaining
res?.[i]to safely index into the results array- Passes the corresponding PublishResult to each message callback
The 1:1 correspondence between messages and results is maintained by the caller (Protocol.onAck), which is the correct design.
src/common/lib/transport/protocol.ts (1)
9-52: LGTM! Clean type updates for PublishResult support.The changes properly:
- Define
PublishCallbackasStandardCallback<API.PublishResult>- Update
PendingMessage.callbacktype fromErrCallbacktoPublishCallback- Thread the
resparameter through the ACK flow from transport to message queue- Maintain backwards compatibility with optional
resparameterThe type consistency is maintained throughout the protocol layer.
src/common/lib/transport/connectionmanager.ts (1)
1747-1804: LGTM! Proper callback type updates and cleanup.The changes correctly:
- Update
sendandqueuemethod signatures to usePublishCallbackinstead ofErrCallback- Align with the protocol layer's PublishResult support
- Resolve the previously flagged unused variables issue (
lastQueuedandmaxSizehave been removed)The simplified
queueimplementation is cleaner and correctly constructs a newPendingMessagewith the callback.src/common/lib/client/restchannel.ts (2)
173-198: LGTM! Consistent API for message operations.The update, delete, and append methods follow a consistent pattern:
- All return
Promise<API.UpdateDeleteResult>with theversionSerialof the resulting operation- All delegate to
client.rest.channelMixin.updateDeleteMessagewith the appropriate operation type ('message.update', 'message.delete', 'message.append')- All include proper logging
The newly added
appendMessagemethod follows the same design as the existing operations.
24-24: LGTM! Appropriate internal type for server response.The
RestPublishResponsetype correctly models the server response format which includesPublishResultfields plus optionalchannelandmessageIdfields that need to be stripped before returning to the caller.ably.d.ts (5)
1470-1474: LGTM! Well-documented new field.The
serialsfield addition is consistent with the newPublishResultinterface and properly documents the 1:1 correspondence with published messages and the null case for conflated messages.
2325-2344: LGTM! Consistent protocol v5 upgrade.The return type changes from
Promise<void>toPromise<PublishResult>are correctly applied across all threepublish()overloads with updated documentation.
2376-2384: LGTM! Clean addition of appendMessage with consistent API.The new
appendMessage()method follows the same pattern asupdateMessage()anddeleteMessage(), with clear documentation of the append semantics (data appended, other fields replaced).
2997-3017: LGTM! Well-designed result interfaces.The new
PublishResultandUpdateDeleteResultinterfaces are cleanly designed with appropriate nullable types and clear documentation of when null values occur.
3049-3066: LGTM! MESSAGE_APPEND properly integrated.The new
MESSAGE_APPENDaction is correctly added to both theMessageActionsnamespace and theMessageActionunion type with clear documentation.src/common/lib/client/realtimechannel.ts (4)
498-508: LGTM! Clean Promise wrapper.The
sendMessage()method correctly wraps the callback-basedconnectionManager.send()and propagates thepublishResponsecontaining serials.
510-526: LGTM! Clean async/await conversion.The
sendPresence()andsendState()methods correctly use async/await and appropriately don't use the return value since presence and state messages don't need publish results.
1062-1093: LGTM! Well-structured update/delete/append implementation.The private
sendUpdate()helper cleanly implements the common logic for all three operations:
- Validation: Properly checks for message serial and publishable state
- Error message: Clear guidance about enabling the feature in dashboard (line 1070)
- Type mapping: Correctly maps
MessageOperationtoMessageVersionfield (line 1081)- Serial extraction: Safely extracts the version serial with null fallback (line 1092)
The implementation correctly handles the single-message nature of these operations by extracting the first serial from the response.
240-292: The implementation looks correct.Utils.isObject()is implemented usingObject.prototype.toString.call(), which returns'[object Object]'for plain objects but'[object Array]'for arrays, ensuring that arrays are correctly excluded from the object check and properly handled by theArray.isArray()condition on line 252. The argument parsing logic correctly handles all three cases: string+data pairs, single message objects, and message arrays.
|
Haven't reviewed this myself but am happy with the changes made as a result of my comment — happy for you to merge if Evgenii is |
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
test/rest/updates-deletes.test.js (2)
128-128: Consider extracting the timeout value to a constant.The timeout value
10000(10 seconds) is hardcoded in multiplewaitForcalls throughout the test suite (lines 128, 171, 208, 313). Extracting this to a named constant would improve maintainability and make it easier to adjust if needed.🔎 Suggested refactor
At the top of the describe block, add:
describe('rest/message-operations', function () { this.timeout(60 * 1000); + const EVENTUAL_CONSISTENCY_TIMEOUT = 10000;Then replace hardcoded values:
- }, 10000); + }, EVENTUAL_CONSISTENCY_TIMEOUT);
322-322: Consider adding a clarifying comment about the append action.Line 322 asserts that
appendMessageresults in an action of'message.update'rather than'message.append'. While this appears intentional (append is treated as a type of update), a brief comment explaining this behavior would improve test readability.🔎 Suggested clarification
+ // Append operations result in 'message.update' action (append is a type of update) expect(latestMessage.action).to.equal('message.update');
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
test/rest/updates-deletes.test.js
🧰 Additional context used
🧬 Code graph analysis (1)
test/rest/updates-deletes.test.js (2)
src/common/lib/client/realtimechannel.ts (2)
updateMessage(1035-1042)appendMessage(1053-1060)src/common/lib/client/restchannel.ts (2)
updateMessage(173-180)appendMessage(191-198)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: test-browser (webkit)
- GitHub Check: test-browser (chromium)
- GitHub Check: test-node (20.x)
- GitHub Check: test-node (18.x)
- GitHub Check: test-node (16.x)
- GitHub Check: test-browser (firefox)
🔇 Additional comments (4)
test/rest/updates-deletes.test.js (4)
14-14: Good defensive coding practice.The explicit
returnafterdone(err)prevents the function from continuing and potentially callingdone()twice, which would cause test failures.
20-55: LGTM!Both publish serial tests are well-structured and provide comprehensive validation of the new serial-returning functionality for single and batch publishes.
62-92: LGTM!Both
getMessagetests properly validate the API's support for both string serials and Message objects with serial properties, with appropriate assertions on the retrieved messages.
217-279: LGTM!Error handling tests are comprehensive and follow a consistent pattern, properly validating that operations fail with error code 40003 when the required serial is missing.
spec change: ably/specification#410 also tweaked the typings to be more consistent (use PublishOptions instead of record<string, any>, and remove quickAck from PublishOptions, publish params should be opaque to the SDK, the typings don't need to have it as an example)
1ce5277 to
db5f3a2
Compare
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.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ably.d.ts (1)
2321-2345: Add Channel.publish breaking change to release notesThe REST
Channel.publishoverloads now returnPromise<PublishResult>instead ofPromise<void>, enabling access to message serials. This is a source-level breaking change for TypeScript consumers and must be documented in the release notes as a major version breaking change so SDK users understand the impact and can intentionally adopt the new result shape.
🧹 Nitpick comments (5)
ably.d.ts (3)
2359-2385: update/delete/append signatures and docs line up, but UpdateDeleteResult name is slightly narrowThe
Channel.updateMessage,deleteMessage, and newappendMessageoverloads all returnPromise<UpdateDeleteResult>withoptions?: PublishOptions, matching howRealtimeChannelis typed and howsendUpdateis implemented. The only nit is naming/documentation:UpdateDeleteResultand its docstring mention “update or delete”, but the same type is now used for appends too. Consider broadening the wording (e.g. “update, delete, or append operation”) to avoid confusion.
2657-2661: PublishOptions doc is intentionally generic; consider hinting at known optionsThe index‑signature‑only
PublishOptionswith “Publish options are server‑defined” keeps the type future‑proof. You might still want to briefly mention currently‑known keys likequickAckin the doc comment (without typing them explicitly) so users have a discoverability hint while preserving the open‑ended type.
2997-3017: Result types are well‑shaped; clarify append usage
PublishResult.serialsandUpdateDeleteResult.versionSerialmatch how the transport now returns serials (including null when conflated/superseded) and what the tests expect. As mentioned above,UpdateDeleteResult’s docstring could be broadened to mention append operations explicitly since it’s used for all three.src/common/lib/client/realtimechannel.ts (2)
240-292: publish(...args) correctly wires params and serials, but silently falls back when responses are absentThe new
publishcorrectly normalizes the three overload shapes intoMessage[], applies max‑size checking, allows transient publishing viathrowIfUnpublishableState, and threadsparamsthrough toProtocolMessage.params(stringified). Returning thePublishResultfromsendMessageis the right shape; theres || { serials: [] }fallback is a bit lossy though—if the server/transport ever fails to supply serials for MESSAGE publishes, callers see a successful publish with an empty serials array and no indication that results were unavailable. Consider either:
- Making absence of
publishResponsefor MESSAGE actions an error, or- At least documenting that empty
serialscan mean “no results available” as well as “no messages”.
1035-1093: sendUpdate helper unifies update/delete/append, but consider using the public PublishOptions typeThe new
updateMessage,deleteMessage, andappendMessagemethods logging then delegating tosendUpdateare straightforward.sendUpdate:
- Enforces presence of
message.serialwith a clear 40003ErrorInfo, matching the tests.- Reuses
throwIfUnpublishableState()so realtime operations follow the same gating as publish.- Builds the outbound
Messagewith the providedactionand usesversionto carryMessageOperationmetadata, then encodes under the current channel cipher.- Sends as a single‑message
actions.MESSAGEprotocol message with optionalparams, and returns{ versionSerial: publishResponse?.serials?.[0] ?? null }, which aligns withUpdateDeleteResult.Two small polish points:
- The
paramsargument could be typed asAPI.PublishOptionsinstead ofRecord<string, any>to stay in lockstep with the public surface.- If you ever extend this to support batched updates, be explicit about how you map multiple returned serials into a result shape.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
ably.d.tssrc/common/lib/client/realtimechannel.tssrc/common/lib/util/utils.tstest/rest/updates-deletes.test.js
🧰 Additional context used
🧬 Code graph analysis (3)
test/rest/updates-deletes.test.js (2)
src/common/lib/client/realtimechannel.ts (2)
updateMessage(1035-1042)appendMessage(1053-1060)src/common/lib/client/restchannel.ts (2)
updateMessage(173-180)appendMessage(191-198)
src/common/lib/util/utils.ts (1)
scripts/processPrivateApiData/dto.ts (1)
Record(53-53)
src/common/lib/client/realtimechannel.ts (4)
ably.d.ts (2)
PublishResult(3000-3006)Message(2799-2857)src/common/lib/types/errorinfo.ts (1)
ErrorInfo(35-66)src/common/lib/types/protocolmessagecommon.ts (1)
actions(5-28)src/common/lib/types/basemessage.ts (1)
CipherOptions(13-24)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
- GitHub Check: test-npm-package
- GitHub Check: test-browser (webkit)
- GitHub Check: test-node (20.x)
- GitHub Check: test-browser (chromium)
- GitHub Check: test-browser (firefox)
- GitHub Check: test-node (16.x)
- GitHub Check: test-node (18.x)
🔇 Additional comments (9)
src/common/lib/util/utils.ts (1)
248-250: Function usage is safe; edge cases are handled by callers.The implementation is correct and straightforward. Both call sites guard the function with
params ?, preventing null/undefined inputs from causing runtime errors. The function is used exclusively for simple value conversion in protocol message parameters, where complex type stringification is not a concern.Consider adding JSDoc documentation for clarity on intended usage and the string conversion behavior.
test/rest/updates-deletes.test.js (3)
9-55: Publish serial tests and setup look solidThe early
returnin thebeforehook avoids double-callingdone, and the new tests assertingpublishreturnsserials(single and batch) align with the newPublishResultshape. Channel- and data-agnostic expectations keep these tests robust as long as conflation is disabled on these channels.
67-215: Good coverage of serial‑driven get/update/delete/version flowsUsing the serial returned from
publishforgetMessage,updateMessage,deleteMessage, andgetMessageVersionsmatches the intended API and exercises version metadata (serial ordering, timestamps, clientId, description, metadata) well. ThewaitFor-based checks for “latest” state are appropriate here and keep the tests deterministic against eventual consistency.
281-341: Test assertion is correct—no changes neededThe test correctly expects
action === 'message.update'when retrieving the persisted message viagetMessage(). This is intentional behavior: whilemessage.appendis the wire action (visible in realtime subscriptions when the operation is transmitted), the persisted latest message state hasaction === 'message.update'because the append semantically represents an update to the original message. This is consistent with howupdateMessage()works and aligns with RSL15 spec requirements for message versioning. The distinction between operation action and persisted message action is sound, though SDK documentation could benefit from clarifying this for consumers reading theMessageActiontype.ably.d.ts (4)
1461-1475: Batch publish serials field matches new publish semanticsAdding
serials: (string | null)[]toBatchPublishSuccessResultis consistent withPublishResult.serialsand the conflation story (1:1 with messages, allowing nulls when discarded). This gives batch callers parity with per‑channel publish while preserving the existingmessageIdprefix behaviour.
2579-2600: RealtimeChannel.publish overloads align with the new realtime implementationThe realtime publish overloads (name+data, Message[], Message) returning
Promise<PublishResult>and takingPublishOptionsmatch the newRealtimeChannel.publish(...args)implementation andsendMessage’s propagation of publish responses. The docs correctly distinguish query‑string options (REST) from protocol message options (realtime) while sharing the samePublishOptionstype.
2615-2640: Realtime update/delete/append API surface matches sendUpdate helperThe realtime
updateMessage,deleteMessage, andappendMessagesignatures (returningUpdateDeleteResult, acceptingMessageOperationandPublishOptions) are consistent with the newsendUpdatehelper and the REST API surface. This symmetry is good for users switching between REST and Realtime channels.
3049-3066: No action needed—the tests correctly reflect the intended design.The REST test asserting
message.updateand the realtime test showing bothmessage.append(on arrival) andmessage.update(on rewind) are correct. The design intentionally treats'message.append'as a transient operation/wire action that surfaces in real-time, while the final persisted state of an appended message is represented as'message.update'. The type definitions correctly exposeMESSAGE_APPEND, and the runtime behavior is as intended.Likely an incorrect or invalid review comment.
src/common/lib/client/realtimechannel.ts (1)
498-526: sendMessage now returning PublishResult is a clean abstractionHaving
sendMessagewrapConnectionManager.sendand surface the (possibly undefined)PublishResultkeeps publish/update/delete/append call sites simple while letting attach/detach/presence/state just ignore the result. The change to havesendPresence/sendStateawaitsendMessagerather than duplicating send logic is a nice consolidation.
AIT-94
Summary by CodeRabbit
New Features
Behavior / Bug Fixes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.