[ECO-5577] Some alignment with JS public API#387
Conversation
WalkthroughRenames message action enums, overhauls reaction event shapes and Message.reactions to non-optional, consolidates update/delete parameters into OperationDetails, replaces DiscontinuityEvent with ARTErrorInfo, introduces HistoryBeforeSubscribeParams, converts Typing.get() to current property, adds Presence.subscribe(all), and updates examples, mocks, and tests accordingly. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as Example UI
participant Messages as Messages API
participant ChatAPI as ChatAPI
User->>UI: Edit/Delete message
UI->>Messages: update(newMessage, details?) / delete(message, details?)
Messages->>ChatAPI: updateMessage(..., details?) / deleteMessage(..., details?)
ChatAPI-->>Messages: Message { action: messageUpdate/messageDelete, reactions }
Messages-->>UI: Updated Message
sequenceDiagram
autonumber
actor Client
participant Reactions as DefaultMessageReactions
participant Ably as Realtime Channel
participant Handler as Callback
Client->>Reactions: subscribeRaw / subscribe
Reactions->>Ably: listen annotations
Ably-->>Reactions: annotation events
Reactions->>Handler: emit RawEvent { type, reaction, timestamp } or SummaryEvent { type, messageSerial, reactions }
sequenceDiagram
autonumber
participant Ably as Realtime
participant LM as RoomLifecycleManager
participant Room
participant App as Consumer
Ably-->>LM: discontinuity detected (ARTErrorInfo)
LM->>Room: emitDiscontinuity(ARTErrorInfo)
App->>Room: onDiscontinuity(callback)
Room-->>App: ARTErrorInfo
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (2 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 |
0ccef4c to
f67ff45
Compare
f67ff45 to
c730426
Compare
8d974b5 to
f2fd07b
Compare
45c019a to
7482b09
Compare
7482b09 to
020f577
Compare
020f577 to
e847b26
Compare
e847b26 to
8d58519
Compare
This reverts 0a52874; no longer needed now that the discontinuity error is no longer optional post-61771ac. This makes us consistent with the JS API.
Match name, make it a synchronous non-throwing property. Based on JS at c6a624a.
Based on JS at c6a624a.
In line with JS at c6a624a.
In line with JS at c6a624a.
In line with JS at c6a624a.
In line with JS at c6a624a.
In line with JS at c6a624a. The expected behaviour is unclear; for now just do something sensible-seeming, we can revisit later.
In line with ably/ably-chat-js#660.
In line with JS at c6a624a.
In line with JS at c6a624a.
In line with JS at c6a624a. I've removed the tests because they aren't actually testing anything (they should be emitting a message via the channel, not the subscription) and I don't have time to sort out the RealtimePresence mocks now; have split out into #396.
Our TypeScript API somewhat communicates that HistoryParams's `orderBy` will be ignored by using `Omit<HistoryParams, 'orderBy'>`; we don't have that option so instead create a separate type to communicate that the user can't set the order of these results.
- Rename MessageReactionSummaryEvent.summary to `reactions` - Lift messageSerial up to top level of the event (as it doesn't belong in a message's `reactions` property) In line with [1] at 1e9a7ce. [1] ably/ably-chat-js#670
This makes us consistent with the use of a literal type in JS, and means that there won't be a clash if JS introduces some other MessageReaction type in the future.
For consistency with JS at c6a624a.
In line with JS at c6a624a. Resolves #226.
Rename DeleteMessageParams to OperationDetails, change the parameter name to `details`, make it optional.
Accept an OperationDetails instead of separate description and metadata, and align the (currently-unused) UpdateMessageParams. We can't fully align the signature yet (to not require a `Message` and instead take a serial-like value and an UpdateMessageParams) because we're waiting on updating `update` to use the server return value, which is currently WIP in #392.
7731a43 to
c247613
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Sources/AblyChat/Message.swift (1)
189-196: Make messagemetadatadecoding resilient (default to empty).
objectValueForKey("metadata")throws if absent/null. Default to{}to uphold “always set” semantics and avoid decode failures.- metadata: jsonObject.objectValueForKey("metadata"), + metadata: (try? jsonObject.optionalObjectValueForKey("metadata")) ?? [:],
♻️ Duplicate comments (1)
Sources/AblyChat/Messages.swift (1)
175-192: Note:UpdateMessageParamsstill unused.Previously discussed and intended for imminent use; leaving as-is is fine for now.
🧹 Nitpick comments (9)
Tests/AblyChatTests/IntegrationTests.swift (3)
157-165: Reactions container assertions look correct; minor iteration nit.Using map purely for side-effects constructs an unused array. Prefer a for-in or forEach to avoid allocation.
278-278: Assert update details are persisted.Also assert
rxEditedMessageFromSubscription.version.description == "random"to verify OperationDetails propagation.
299-303: Assert delete details are persisted.Consider asserting
rxDeletedMessageFromSubscription.version.description == "deleted in testing"for completeness.Example/AblyChatExample/Mocks/MockClients.swift (3)
108-110: StubonDiscontinuityinstead of crashing.Return a no-op subscription to keep mocks usable rather than fatalError.
Apply:
- func onDiscontinuity(_: @escaping @MainActor (ARTErrorInfo) -> Void) -> DefaultStatusSubscription { - fatalError("Not yet implemented") - } + func onDiscontinuity(_: @escaping @MainActor (ARTErrorInfo) -> Void) -> DefaultStatusSubscription { + DefaultStatusSubscription { /* no-op */ } + }
181-192: Honordetailsin update and populate version fields.Populate
version.description/version.metadatafromdetailsso mocks mirror API behavior.- func update(newMessage: Message, details _: OperationDetails?) async throws(ARTErrorInfo) -> Message { + func update(newMessage: Message, details: OperationDetails?) async throws(ARTErrorInfo) -> Message { let message = Message( serial: newMessage.serial, action: .messageUpdate, clientID: clientID, text: newMessage.text, metadata: newMessage.metadata, headers: newMessage.headers, - version: .init(serial: "\(Date().timeIntervalSince1970)", timestamp: Date(), clientID: clientID), + version: .init( + serial: "\(Date().timeIntervalSince1970)", + timestamp: Date(), + clientID: clientID, + description: details?.description, + metadata: details?.metadata + ), timestamp: Date(), reactions: .init(unique: [:], distinct: [:], multiple: [:]), )
197-213: Mirror server delete semantics and carrydetails.Clear
text,metadata,headers, and setversion.description/metadatafromdetails.- func delete(message: Message, details _: OperationDetails?) async throws(ARTErrorInfo) -> Message { + func delete(message: Message, details: OperationDetails?) async throws(ARTErrorInfo) -> Message { let message = Message( serial: message.serial, action: .messageDelete, clientID: clientID, - text: message.text, - metadata: message.metadata, - headers: message.headers, + text: "", + metadata: [:], + headers: [:], version: .init( serial: "\(Date().timeIntervalSince1970)", timestamp: Date(), - clientID: clientID, + clientID: clientID, + description: details?.description, + metadata: details?.metadata ), timestamp: Date(), reactions: .init(unique: [:], distinct: [:], multiple: [:]), )Sources/AblyChat/Messages.swift (3)
65-65: Doc: fix action case in return description.Change “set as
.update” to “.messageUpdate” to match the enum.
80-80: Doc: fix action case in return description.Change “set as
.delete” to “.messageDelete”.
194-207: ClarifyOperationDetails.metadatadocs.It says “Defaults to empty,” but the default is
nil. Suggest: “Optional metadata to record for the action.”
📜 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 (42)
Example/AblyChatExample/ContentView.swift(4 hunks)Example/AblyChatExample/MessageViews/MessageView.swift(1 hunks)Example/AblyChatExample/Mocks/Misc.swift(2 hunks)Example/AblyChatExample/Mocks/MockClients.swift(12 hunks)Example/AblyChatExample/Mocks/MockSubscriptionStorage.swift(4 hunks)Sources/AblyChat/ChatAPI.swift(3 hunks)Sources/AblyChat/ChatClient.swift(1 hunks)Sources/AblyChat/Connection.swift(1 hunks)Sources/AblyChat/DefaultConnection.swift(1 hunks)Sources/AblyChat/DefaultMessageReactions.swift(3 hunks)Sources/AblyChat/DefaultMessages.swift(3 hunks)Sources/AblyChat/DefaultPresence.swift(1 hunks)Sources/AblyChat/DefaultTyping.swift(1 hunks)Sources/AblyChat/DiscontinuityEvent.swift(0 hunks)Sources/AblyChat/Events.swift(3 hunks)Sources/AblyChat/Message.swift(7 hunks)Sources/AblyChat/MessageReaction+JSON.swift(1 hunks)Sources/AblyChat/MessageReaction.swift(5 hunks)Sources/AblyChat/Messages.swift(8 hunks)Sources/AblyChat/OperationMetadata.swift(1 hunks)Sources/AblyChat/Presence.swift(4 hunks)Sources/AblyChat/Room.swift(4 hunks)Sources/AblyChat/RoomLifecycleManager.swift(3 hunks)Sources/AblyChat/RoomOptions.swift(1 hunks)Sources/AblyChat/RoomReaction.swift(3 hunks)Sources/AblyChat/RoomReactionDTO.swift(2 hunks)Sources/AblyChat/RoomReactions.swift(2 hunks)Sources/AblyChat/Subscription.swift(2 hunks)Sources/AblyChat/Typing.swift(1 hunks)Tests/AblyChatTests/ChatAPITests.swift(2 hunks)Tests/AblyChatTests/DefaultMessageReactionsTests.swift(3 hunks)Tests/AblyChatTests/DefaultMessagesTests.swift(7 hunks)Tests/AblyChatTests/DefaultPresenceTests.swift(1 hunks)Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift(1 hunks)Tests/AblyChatTests/DefaultRoomTests.swift(2 hunks)Tests/AblyChatTests/DefaultTypingTests.swift(2 hunks)Tests/AblyChatTests/Helpers/Equatable.swift(0 hunks)Tests/AblyChatTests/Helpers/RoomLifecycleManager+AsyncSequence.swift(1 hunks)Tests/AblyChatTests/IntegrationTests.swift(5 hunks)Tests/AblyChatTests/MessageSubscriptionResponseAsyncSequenceTests.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoom.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift(2 hunks)
💤 Files with no reviewable changes (2)
- Tests/AblyChatTests/Helpers/Equatable.swift
- Sources/AblyChat/DiscontinuityEvent.swift
✅ Files skipped from review due to trivial changes (1)
- Sources/AblyChat/DefaultConnection.swift
🚧 Files skipped from review as they are similar to previous changes (15)
- Tests/AblyChatTests/Mocks/MockRoom.swift
- Sources/AblyChat/Connection.swift
- Sources/AblyChat/RoomReactions.swift
- Sources/AblyChat/Typing.swift
- Sources/AblyChat/MessageReaction+JSON.swift
- Tests/AblyChatTests/DefaultTypingTests.swift
- Sources/AblyChat/OperationMetadata.swift
- Sources/AblyChat/RoomLifecycleManager.swift
- Sources/AblyChat/DefaultTyping.swift
- Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift
- Tests/AblyChatTests/Helpers/RoomLifecycleManager+AsyncSequence.swift
- Sources/AblyChat/RoomReaction.swift
- Tests/AblyChatTests/DefaultPresenceTests.swift
- Tests/AblyChatTests/MessageSubscriptionResponseAsyncSequenceTests.swift
- Sources/AblyChat/Presence.swift
🧰 Additional context used
🧬 Code graph analysis (16)
Tests/AblyChatTests/DefaultRoomTests.swift (4)
Sources/AblyChat/Room.swift (3)
onDiscontinuity(179-192)onDiscontinuity(195-197)onDiscontinuity(409-412)Sources/AblyChat/RoomLifecycleManager.swift (2)
onDiscontinuity(225-228)emitDiscontinuity(230-232)Tests/AblyChatTests/Helpers/RoomLifecycleManager+AsyncSequence.swift (1)
onDiscontinuity(26-39)Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift (2)
onDiscontinuity(82-85)emitDiscontinuity(87-89)
Sources/AblyChat/Events.swift (1)
Example/AblyChatExample/Mocks/MockClients.swift (6)
update(181-195)update(492-494)update(496-498)update(500-513)delete(197-215)delete(271-282)
Sources/AblyChat/Subscription.swift (2)
Sources/AblyChat/Messages.swift (2)
historyBeforeSubscribe(417-419)toHistoryParams(303-305)Example/AblyChatExample/Mocks/MockSubscriptionStorage.swift (1)
historyBeforeSubscribe(211-213)
Sources/AblyChat/ChatAPI.swift (3)
Tests/AblyChatTests/DefaultMessagesTests.swift (2)
updateMessage(61-115)deleteMessage(119-168)Sources/AblyChat/Message.swift (1)
with(226-235)Example/AblyChatExample/ContentView.swift (1)
deleteMessage(412-416)
Example/AblyChatExample/Mocks/MockSubscriptionStorage.swift (2)
Sources/AblyChat/Messages.swift (1)
historyBeforeSubscribe(417-419)Sources/AblyChat/Subscription.swift (1)
historyBeforeSubscribe(94-108)
Tests/AblyChatTests/DefaultMessagesTests.swift (4)
Example/AblyChatExample/Mocks/MockClients.swift (6)
update(181-195)update(492-494)update(496-498)update(500-513)delete(197-215)delete(271-282)Sources/AblyChat/DefaultMessages.swift (2)
update(136-142)delete(144-150)Sources/AblyChat/Messages.swift (1)
historyBeforeSubscribe(417-419)Sources/AblyChat/Subscription.swift (1)
historyBeforeSubscribe(94-108)
Example/AblyChatExample/MessageViews/MessageView.swift (1)
Example/AblyChatExample/Misc/Utils.swift (4)
padding(38-40)padding(42-44)padding(46-48)padding(50-52)
Sources/AblyChat/Messages.swift (4)
Example/AblyChatExample/Mocks/MockClients.swift (6)
update(181-195)update(492-494)update(496-498)update(500-513)delete(197-215)delete(271-282)Sources/AblyChat/DefaultMessages.swift (2)
update(136-142)delete(144-150)Example/AblyChatExample/Mocks/MockSubscriptionStorage.swift (1)
historyBeforeSubscribe(211-213)Sources/AblyChat/Subscription.swift (1)
historyBeforeSubscribe(94-108)
Example/AblyChatExample/ContentView.swift (3)
Example/AblyChatExample/Mocks/MockClients.swift (6)
update(181-195)update(492-494)update(496-498)update(500-513)delete(197-215)delete(271-282)Sources/AblyChat/DefaultMessages.swift (2)
update(136-142)delete(144-150)Sources/AblyChat/ChatAPI.swift (1)
deleteMessage(92-107)
Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift (6)
Example/AblyChatExample/Mocks/MockClients.swift (1)
onDiscontinuity(107-110)Sources/AblyChat/Room.swift (3)
onDiscontinuity(179-192)onDiscontinuity(195-197)onDiscontinuity(409-412)Sources/AblyChat/RoomLifecycleManager.swift (2)
onDiscontinuity(225-228)emitDiscontinuity(230-232)Tests/AblyChatTests/DefaultRoomTests.swift (1)
onDiscontinuity(296-318)Tests/AblyChatTests/Helpers/RoomLifecycleManager+AsyncSequence.swift (1)
onDiscontinuity(26-39)Tests/AblyChatTests/Mocks/MockRoom.swift (1)
onDiscontinuity(72-75)
Sources/AblyChat/Room.swift (7)
Example/AblyChatExample/Mocks/MockClients.swift (1)
onDiscontinuity(107-110)Sources/AblyChat/RoomLifecycleManager.swift (1)
onDiscontinuity(225-228)Tests/AblyChatTests/DefaultRoomTests.swift (1)
onDiscontinuity(296-318)Tests/AblyChatTests/Helpers/RoomLifecycleManager+AsyncSequence.swift (1)
onDiscontinuity(26-39)Tests/AblyChatTests/Mocks/MockRoom.swift (1)
onDiscontinuity(72-75)Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift (1)
onDiscontinuity(82-85)Sources/AblyChat/SubscriptionAsyncSequence.swift (1)
emit(73-80)
Sources/AblyChat/DefaultMessageReactions.swift (1)
Sources/AblyChat/MessageReaction.swift (1)
fromAnnotationAction(27-36)
Sources/AblyChat/DefaultMessages.swift (5)
Sources/AblyChat/Events.swift (1)
fromRealtimeAction(16-31)Example/AblyChatExample/Mocks/MockClients.swift (6)
update(181-195)update(492-494)update(496-498)update(500-513)delete(197-215)delete(271-282)Sources/AblyChat/ChatAPI.swift (2)
updateMessage(64-88)deleteMessage(92-107)Tests/AblyChatTests/DefaultMessagesTests.swift (2)
updateMessage(61-115)deleteMessage(119-168)Sources/AblyChat/Message.swift (1)
with(226-235)
Sources/AblyChat/DefaultPresence.swift (6)
Sources/AblyChat/DefaultMessages.swift (1)
subscribe(39-117)Sources/AblyChat/Presence.swift (6)
subscribe(154-168)subscribe(181-195)subscribe(208-222)subscribe(225-227)subscribe(230-232)subscribe(235-237)Sources/AblyChat/Subscription.swift (2)
unsubscribe(63-65)unsubscribe(90-92)Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift (1)
unsubscribe(160-162)Sources/AblyChat/AblyCocoaExtensions/InternalAblyCocoaTypes.swift (3)
unsubscribe(212-214)unsubscribe(316-318)unsubscribe(430-432)Tests/AblyChatTests/Mocks/MockRealtimePresence.swift (1)
unsubscribe(15-17)
Sources/AblyChat/Message.swift (1)
Sources/AblyChat/JSONCodable.swift (3)
objectValueForKey(58-68)stringValueForKey(130-140)optionalObjectValueForKey(73-87)
Example/AblyChatExample/Mocks/MockClients.swift (6)
Sources/AblyChat/Room.swift (3)
onDiscontinuity(179-192)onDiscontinuity(195-197)onDiscontinuity(409-412)Sources/AblyChat/RoomLifecycleManager.swift (1)
onDiscontinuity(225-228)Tests/AblyChatTests/Mocks/MockRoom.swift (1)
onDiscontinuity(72-75)Sources/AblyChat/DefaultMessages.swift (3)
update(136-142)delete(144-150)subscribe(39-117)Sources/AblyChat/DefaultMessageReactions.swift (2)
delete(43-59)subscribe(62-100)Sources/AblyChat/Presence.swift (6)
subscribe(154-168)subscribe(181-195)subscribe(208-222)subscribe(225-227)subscribe(230-232)subscribe(235-237)
⏰ 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). (11)
- GitHub Check: Example app, tvOS (Xcode 26.0)
- GitHub Check: Example app, macOS (Xcode 26.0)
- GitHub Check: Example app, iOS (Xcode 26.0)
- GitHub Check: Xcode, tvOS (Xcode 26.0)
- GitHub Check: Xcode, macOS (Xcode 26.0)
- GitHub Check: Xcode,
releaseconfiguration, iOS (Xcode 26.0) - GitHub Check: Xcode, iOS (Xcode 26.0)
- GitHub Check: Xcode,
releaseconfiguration, tvOS (Xcode 26.0) - GitHub Check: Xcode,
releaseconfiguration, macOS (Xcode 26.0) - GitHub Check: SPM (Xcode 26.0)
- GitHub Check: SPM,
releaseconfiguration (Xcode 26.0)
🔇 Additional comments (39)
Sources/AblyChat/RoomReactionDTO.swift (1)
8-8: LGTM! Type alignment with room-scoped naming.The type renames from
ReactionMetadata/ReactionHeaderstoRoomReactionMetadata/RoomReactionHeadersare applied consistently throughout the DTO structure, initializer, and accessor methods. The changes correctly align the Swift API with the JavaScript public API as intended.Also applies to: 12-12, 17-17, 26-26, 30-30
Sources/AblyChat/DefaultPresence.swift (1)
201-229: Verify main actor execution for callbackThe new
subscribe(_:)implementation is correct, butcallback(presenceEvent)is invoked directly inside the Ably subscription closure which may not run on the main actor despite the@MainActorannotation. Confirm that the Ably SDK delivers events on the main actor; if not, wrap the call in:Task { @MainActor in callback(presenceEvent) }Example/AblyChatExample/Mocks/Misc.swift (1)
15-15: LGTM!The mock updates correctly reflect the public API changes:
- Action enum case renamed to
.messageCreate(aligning withChatMessageActionrename in Events.swift)reactionsparameter added toMessageinitializer with appropriate empty initializationAlso applies to: 25-25
Sources/AblyChat/Events.swift (1)
6-14: LGTM!The systematic rename from
MessageActiontoChatMessageActionwith explicit case names (.messageCreate,.messageUpdate,.messageDelete) improves API clarity. The internal wire format and mapping logic remain correct.Sources/AblyChat/Subscription.swift (1)
57-57: LGTM!The introduction of
HistoryBeforeSubscribeParamsprovides better type safety by distinguishing history-before-subscribe queries (which must always query backwards) from general history queries. The conversion viatoHistoryParams()correctly enforces the.newestFirstordering constraint.Also applies to: 94-99
Sources/AblyChat/ChatAPI.swift (2)
64-87: LGTM!Consolidating separate
descriptionandmetadataparameters into a singleOperationDetails?payload improves API consistency for update operations. The metadata serialization withmapValues { .string($0) }correctly prepares values for the wire format.
92-106: LGTM!The delete operation follows the same consolidation pattern as update, using
OperationDetails?for a cleaner, more consistent API surface.Sources/AblyChat/DefaultMessages.swift (2)
48-48: LGTM!Correctly updated to use
ChatMessageAction.fromRealtimeActionfollowing the enum rename.
136-146: LGTM!The update and delete method signatures correctly adopt
OperationDetails?for consolidated parameter passing, aligning with the ChatAPI changes.Example/AblyChatExample/ContentView.swift (3)
114-114: LGTM!The UI correctly references the renamed action enum cases (
.messageDelete,.messageCreate,.messageUpdate).Also applies to: 282-282
302-302: LGTM!Correctly updated to access
messageSerialdirectly from the event, reflecting the flattened event structure wheremessageSerialis now a top-level field instead of nested undersummary.
406-406: LGTM!The update and delete calls correctly use the new
detailsparameter (passingnilfor both operations as no description or metadata is provided in these UI flows).Also applies to: 414-414
Tests/AblyChatTests/DefaultMessagesTests.swift (3)
45-45: LGTM!Tests correctly validate:
- The renamed
.messageCreateaction- The new
OperationDetailsparameter structure withdescriptionandmetadata- The
.messageUpdateaction after update operationsTest expectations properly verify the end-to-end flow including request body structure.
Also applies to: 98-114
152-167: LGTM!Delete operation test correctly:
- Passes
details: nil(appropriate for delete with no description/metadata)- Expects
.messageDeleteaction- Verifies empty request body when details is nil
392-402: LGTM!The test correctly validates
HistoryBeforeSubscribeParamsusage and documents thatOrderBy.newestFirstis equivalent to backwards direction via thetoHistoryParamsconversion method.Sources/AblyChat/DefaultMessageReactions.swift (2)
85-89: LGTM!The reaction summary event structure is correctly updated with:
- New type:
MessageReactionSummaryEventType.summary- Flattened structure:
messageSerialandreactionsas top-level fields instead of nesting undersummaryThis improves API ergonomics and aligns with the JS SDK.
131-133: Fallback already tracked by existing TODO referencing #395; no action needed.Likely an incorrect or invalid review comment.
Tests/AblyChatTests/IntegrationTests.swift (4)
167-171: LGTM: summary events reflect new reactions container.
172-186: LGTM: subsequent reaction summary assertions align with new event shape.
255-255: Good: history uses non-optionalreactions.This aligns with the new public model and validates raw reactions persisted earlier.
317-317: LGTM: delete metadata persistence verified.Example/AblyChatExample/Mocks/MockSubscriptionStorage.swift (3)
130-131: Type migration to HistoryBeforeSubscribeParams looks good.
155-156: Factory signature aligned with new params type.
209-221: Forwarder and storage updated to new params.Actor annotations match usage; forwarding is correct.
Example/AblyChatExample/Mocks/MockClients.swift (7)
133-133: Action rename to.messageCreateis correct.
142-143: Initializing non-optionalreactionsis required; looks good.
225-226: Raw reaction storage switched toMessageReactionRawEvent.Reaction— aligns with new event model.
254-267: Summary emissions: new fields (messageSerial,reactions) look correct.
291-303: Subscription generator for summaries matches new shape.
388-390: Typing.current exposed as computed property — matches new API.
538-541: Presence.subscribe(_:) added — conforms to Presence surface.Sources/AblyChat/Message.swift (4)
172-178: Good: non-optional reactions default to.empty.
181-181: Action decode now usesChatMessageAction— aligned with new enum.
209-210: ConfirmMessageOperationMetadatavalue type.
compactMapValues { $0.stringValue }drops non-string values. IfMessageOperationMetadatais not strictly[String: String], this will lose data; otherwise, it’s fine. Please confirm.
229-234: with(summaryEvent): serial check and reactions update are correct.Sources/AblyChat/Messages.swift (4)
264-306: HistoryBeforeSubscribeParams looks good; conversion enforces newest-first.
366-374: Mapping fromChatMessageActiontoChatMessageEventTypeis correct.
388-406: AsyncSequence wiring for history-before-subscribe updated correctly.
416-419: Signature change toHistoryBeforeSubscribeParamspropagated; good.
This addresses many differences between the JS and Swift public APIs; i.e. a subset of the differences identified in #386. See commit messages for more details.
Summary by CodeRabbit
New Features
Breaking Changes