Skip to content

[ECO-5577] Some alignment with JS public API#387

Merged
lawrence-forooghian merged 21 commits intomainfrom
2025-10-08-compare-with-js
Oct 13, 2025
Merged

[ECO-5577] Some alignment with JS public API#387
lawrence-forooghian merged 21 commits intomainfrom
2025-10-08-compare-with-js

Conversation

@lawrence-forooghian
Copy link
Copy Markdown
Collaborator

@lawrence-forooghian lawrence-forooghian commented Oct 8, 2025

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

    • Subscribe to all presence events via a single listener or AsyncSequence.
    • Typing status exposed as a read-only current property.
    • Chat client accepts optional client options on creation.
    • New pre-subscribe history parameters for message streams.
  • Breaking Changes

    • Message actions renamed to messageCreate/messageUpdate/messageDelete.
    • Message update/delete now take a details object (description/metadata).
    • Discontinuity callbacks now deliver an error object instead of a custom event.
    • Reactions API reshaped; Message.reactions is non-optional and reaction types/fields renamed.
    • Room reactions options removed; connection retry interval may be nil.

@lawrence-forooghian lawrence-forooghian mentioned this pull request Oct 8, 2025
58 tasks
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Oct 8, 2025

Walkthrough

Renames 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

Cohort / File(s) Summary
Message action enum rename
Sources/AblyChat/Events.swift, Sources/AblyChat/DefaultMessages.swift, Sources/AblyChat/Messages.swift, Example/AblyChatExample/ContentView.swift, Example/AblyChatExample/MessageViews/MessageView.swift, Tests/...DefaultMessagesTests.swift, Tests/...ChatAPITests.swift, Tests/...MessageSubscriptionResponseAsyncSequenceTests.swift
Rename MessageAction → ChatMessageAction and cases .create/.update/.delete.messageCreate/.messageUpdate/.messageDelete; update mappings, constructors and UI usages.
OperationDetails and mutation signatures
Sources/AblyChat/Messages.swift, Sources/AblyChat/DefaultMessages.swift, Sources/AblyChat/ChatAPI.swift, Example/AblyChatExample/ContentView.swift, Example/AblyChatExample/Mocks/MockClients.swift, Tests/...DefaultMessagesTests.swift, Tests/...IntegrationTests.swift
Replace separate description/metadata/delete params with unified OperationDetails? for update/delete APIs; update call sites, mocks, and tests to pass details.
Reactions model overhaul
Sources/AblyChat/MessageReaction.swift, Sources/AblyChat/DefaultMessageReactions.swift, Sources/AblyChat/MessageReaction+JSON.swift, Sources/AblyChat/Message.swift, Tests/...DefaultMessageReactionsTests.swift, Tests/...IntegrationTests.swift, Example/...
Introduce raw vs summary reaction event types (MessageReactionRawEventType, MessageReactionRawEvent.Reaction, MessageReactionSummaryEventType), rename summary → reactions, remove messageSerial from summary struct, make Message.reactions non-optional and provide .empty.
Discontinuity → ARTErrorInfo
Sources/AblyChat/DiscontinuityEvent.swift (removed), Sources/AblyChat/Room.swift, Sources/AblyChat/RoomLifecycleManager.swift, Tests/...DefaultRoomLifecycleManagerTests.swift, Tests/...DefaultRoomTests.swift, Tests/...Helpers/RoomLifecycleManager+AsyncSequence.swift, Tests/...Helpers/Equatable.swift, Tests/...Mocks/MockRoom*.swift, Example/...Mocks/MockClients.swift
Remove public DiscontinuityEvent; change onDiscontinuity signatures, storage, emissions and AsyncSequence bindings to use ARTErrorInfo throughout code, mocks and tests.
History-before-subscribe params
Sources/AblyChat/Messages.swift, Sources/AblyChat/Subscription.swift, Example/...Mocks/MockSubscriptionStorage.swift, Tests/...
Add HistoryBeforeSubscribeParams and convert to HistoryParams via helper; replace previous HistoryParams usage for history-before-subscribe paths and mocks.
Typing API simplification
Sources/AblyChat/Typing.swift, Sources/AblyChat/DefaultTyping.swift, Example/...Mocks/MockClients.swift, Tests/...DefaultTypingTests.swift
Replace async throwing get() with read-only property current: Set<String>; update implementations and call sites/tests to use property.
Presence subscribe(all)
Sources/AblyChat/Presence.swift, Sources/AblyChat/DefaultPresence.swift, Example/...Mocks/MockClients.swift, Tests/...DefaultPresenceTests.swift
Add subscribe(_ callback: @escaping @MainActor (PresenceEvent) -> Void) and buffering-policy AsyncSequence overloads; implement listener wiring and DefaultSubscription return.
Message/Version metadata aliases
Sources/AblyChat/OperationMetadata.swift, Sources/AblyChat/Message.swift
Add OperationMetadata alias and MessageOperationMetadata usage; adjust MessageVersion.metadata types and JSON decoding to new alias.
Connection retryIn optional
Sources/AblyChat/Connection.swift, Sources/AblyChat/DefaultConnection.swift
Make ConnectionStatusChange.retryIn optional (TimeInterval?); update initializer and assignment (no behavior change).
ChatClient convenience init
Sources/AblyChat/ChatClient.swift
Make clientOptions optional with default nil in public convenience initializer.
Room options and reactions typealiases
Sources/AblyChat/RoomOptions.swift, Sources/AblyChat/RoomReaction.swift, Sources/AblyChat/RoomReactionDTO.swift, Sources/AblyChat/RoomReactions.swift, Tests/...IntegrationTests.swift
Remove RoomOptions.reactions and RoomReactionsOptions; rename ReactionHeaders/ReactionMetadataRoomReactionHeaders/RoomReactionMetadata; update DTOs and SendReactionParams to use room-scoped typealiases.
Mocks, examples and tests alignment
Example/AblyChatExample/*, Example/.../Mocks/*, Tests/...Mocks/*, Tests/...
Update examples, mocks and tests for all renames and signature changes: message actions, reactions, discontinuity, history params, typing property, and operation details.

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
Loading
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 }
Loading
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
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • umair-ably
  • maratal

Poem

I nibble enums and hop through code,
Reactions tucked neatly in a brighter mode.
Typing now current, presence subscribed,
Discontinuities swapped and mocks revised.
A rabbit's small cheer for the tidy new road. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 2 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.30% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Linked Issues Check ❓ Inconclusive The pull request references issue ECO-5577 for a Pre-V1 audit but no specific coding requirements or acceptance criteria are provided to verify compliance with that issue’s objectives. Please provide detailed objectives or a checklist from issue ECO-5577 to confirm that all required API alignment changes have been implemented.
Out of Scope Changes Check ❓ Inconclusive Without explicit scope definitions from issue ECO-5577, it is not possible to determine whether any of the extensive public API and internal changes fall outside the intended alignment effort. Please clarify the expected scope of API changes for ECO-5577 so that unrelated modifications can be identified and removed.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly references the primary change of aligning the Swift public API with the JS API, matching the intent and scope of the pull request.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 2025-10-08-compare-with-js

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

❤️ Share

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

@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 8, 2025 19:29 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 8, 2025 19:44 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 8, 2025 19:47 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 8, 2025 19:56 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 8, 2025 20:03 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 13:44 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 13:58 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the 2025-10-08-compare-with-js branch from 0ccef4c to f67ff45 Compare October 9, 2025 15:24
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 15:37 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the 2025-10-08-compare-with-js branch from f67ff45 to c730426 Compare October 9, 2025 16:02
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 16:03 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 17:05 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the 2025-10-08-compare-with-js branch from 8d974b5 to f2fd07b Compare October 9, 2025 17:06
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 17:08 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 17:40 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 18:02 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 18:33 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the 2025-10-08-compare-with-js branch from 45c019a to 7482b09 Compare October 9, 2025 18:41
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 18:43 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the 2025-10-08-compare-with-js branch from 7482b09 to 020f577 Compare October 9, 2025 18:48
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 18:49 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the 2025-10-08-compare-with-js branch from 020f577 to e847b26 Compare October 9, 2025 18:55
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 18:57 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the 2025-10-08-compare-with-js branch from e847b26 to 8d58519 Compare October 9, 2025 19:01
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 19:03 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 19:06 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 9, 2025 19:33 Inactive
@github-actions github-actions Bot temporarily deployed to staging/pull/387/AblyChat October 10, 2025 12:20 Inactive
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.
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 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.
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.
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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 message metadata decoding 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: UpdateMessageParams still 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: Stub onDiscontinuity instead 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: Honor details in update and populate version fields.

Populate version.description/version.metadata from details so 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 carry details.

Clear text, metadata, headers, and set version.description/metadata from details.

-    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: Clarify OperationDetails.metadata docs.

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.

📥 Commits

Reviewing files that changed from the base of the PR and between 7731a43 and c247613.

📒 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, release configuration, iOS (Xcode 26.0)
  • GitHub Check: Xcode, iOS (Xcode 26.0)
  • GitHub Check: Xcode, release configuration, tvOS (Xcode 26.0)
  • GitHub Check: Xcode, release configuration, macOS (Xcode 26.0)
  • GitHub Check: SPM (Xcode 26.0)
  • GitHub Check: SPM, release configuration (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/ReactionHeaders to RoomReactionMetadata/RoomReactionHeaders are 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 callback

The new subscribe(_:) implementation is correct, but callback(presenceEvent) is invoked directly inside the Ably subscription closure which may not run on the main actor despite the @MainActor annotation. 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 with ChatMessageAction rename in Events.swift)
  • reactions parameter added to Message initializer with appropriate empty initialization

Also applies to: 25-25

Sources/AblyChat/Events.swift (1)

6-14: LGTM!

The systematic rename from MessageAction to ChatMessageAction with 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 HistoryBeforeSubscribeParams provides better type safety by distinguishing history-before-subscribe queries (which must always query backwards) from general history queries. The conversion via toHistoryParams() correctly enforces the .newestFirst ordering constraint.

Also applies to: 94-99

Sources/AblyChat/ChatAPI.swift (2)

64-87: LGTM!

Consolidating separate description and metadata parameters into a single OperationDetails? payload improves API consistency for update operations. The metadata serialization with mapValues { .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.fromRealtimeAction following 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 messageSerial directly from the event, reflecting the flattened event structure where messageSerial is now a top-level field instead of nested under summary.


406-406: LGTM!

The update and delete calls correctly use the new details parameter (passing nil for 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 .messageCreate action
  • The new OperationDetails parameter structure with description and metadata
  • The .messageUpdate action after update operations

Test 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 .messageDelete action
  • Verifies empty request body when details is nil

392-402: LGTM!

The test correctly validates HistoryBeforeSubscribeParams usage and documents that OrderBy.newestFirst is equivalent to backwards direction via the toHistoryParams conversion method.

Sources/AblyChat/DefaultMessageReactions.swift (2)

85-89: LGTM!

The reaction summary event structure is correctly updated with:

  • New type: MessageReactionSummaryEventType.summary
  • Flattened structure: messageSerial and reactions as top-level fields instead of nesting under summary

This 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-optional reactions.

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 .messageCreate is correct.


142-143: Initializing non-optional reactions is required; looks good.


225-226: Raw reaction storage switched to MessageReactionRawEvent.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 uses ChatMessageAction — aligned with new enum.


209-210: Confirm MessageOperationMetadata value type.

compactMapValues { $0.stringValue } drops non-string values. If MessageOperationMetadata is 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 from ChatMessageAction to ChatMessageEventType is correct.


388-406: AsyncSequence wiring for history-before-subscribe updated correctly.


416-419: Signature change to HistoryBeforeSubscribeParams propagated; good.

Comment thread Sources/AblyChat/DefaultMessages.swift
Copy link
Copy Markdown
Collaborator

@maratal maratal left a comment

Choose a reason for hiding this comment

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

LGTM with a question

Comment thread Sources/AblyChat/MessageReaction.swift
@lawrence-forooghian lawrence-forooghian merged commit a864485 into main Oct 13, 2025
17 checks passed
@lawrence-forooghian lawrence-forooghian deleted the 2025-10-08-compare-with-js branch October 13, 2025 11:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants