Skip to content

[ECO-5634] Messages update, delete and versions#2146

Merged
maratal merged 1 commit intomainfrom
ECO-5634-message-updates
Dec 9, 2025
Merged

[ECO-5634] Messages update, delete and versions#2146
maratal merged 1 commit intomainfrom
ECO-5634-message-updates

Conversation

@maratal
Copy link
Collaborator

@maratal maratal commented Nov 30, 2025

Summary by CodeRabbit

  • New Features

    • Add message update/delete APIs with optional operation metadata, params, and wrapper SDK agent support.
    • Add retrieval of single messages by serial and fetching message version history.
    • Introduce a message operation type for carrying clientId/description/metadata and a new message-specific callback type.
  • Tests

    • End-to-end tests covering get/update/delete and version retrieval for REST and Realtime.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 30, 2025

Walkthrough

Adds ARTMessageOperation and ARTDictionarySerializable types, new channel APIs for getting/updating/deleting message versions (with wrapperSDKAgents), REST/Realtime implementations including request/response handling, project/module header updates, and end‑to‑end tests validating the flows.

Changes

Cohort / File(s) Summary
Model & Serialization
Source/include/Ably/ARTMessageOperation.h, Source/ARTMessageOperation.m, Source/include/Ably/ARTDictionarySerializable.h, Source/ARTDictionarySerializable.m
New ARTMessageOperation public type (clientId, descriptionText, metadata), copy/description/dictionary serialization; new ARTDictionarySerializable protocol and implementations.
Private Extensions
Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h
Private category declaring ARTMessageOperation conformance to ARTDictionarySerializable.
Channel API (public & private headers)
Source/include/Ably/ARTChannelProtocol.h, Source/PrivateHeaders/Ably/ARTChannel.h
Added channel methods for update/delete/get/getVersions, plus private overloads that accept wrapperSDKAgents and ARTStringifiable params.
Base Channel / Realtime proxy
Source/ARTChannel.m, Source/ARTRealtimeChannel.m, Source/ARTWrapperSDKProxyRealtimeChannel.m
ARTChannel declares abstract methods requiring override; ARTRealtimeChannel exposes public APIs forwarding to internal/rest variants (with and without wrapperSDKAgents); wrapper proxy forwards calls injecting proxy wrapperSDKAgents.
REST channel implementation
Source/ARTRestChannel.m
Implements update/delete/get/getVersions flows, shared _updateMessage:isDelete:operation:params:wrapperSDKAgents:callback: helper, request construction, payload serialization/decoding, wrapperSDKAgents propagation and error handling.
Types & Callbacks
Source/include/Ably/ARTTypes.h
Added ARTMessageErrorCallback typedef (ARTMessage *_Nullable, ARTErrorInfo *_Nullable).
Module / Project config
Ably.xcodeproj/project.pbxproj, Source/Ably.modulemap, Source/include/module.modulemap, Source/include/Ably/AblyPublic.h
Replaced ARTSummaryTypes+Private.h references with ARTDictionarySerializable.h and ARTMessageOperation+Private.h; registered new sources/headers and added public import for ARTMessageOperation.h.
Imports & minor replacements
Source/ARTSummaryTypes.m, Source/include/Ably/AblyPublic.h
Replaced private summary header import with ARTDictionarySerializable.h; added ARTMessageOperation.h to public umbrella.
Tests
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift
New end‑to‑end Swift tests for REST and Realtime covering get/update/getVersions/delete, validating HTTP methods, endpoints, query strings and MsgPack bodies.

Sequence Diagram(s)

sequenceDiagram
  participant Test as Test Suite / Client
  participant Channel as ARTChannel (Realtime/REST layer)
  participant RestInt as ARTRestChannelInternal
  participant HTTP as Server / HTTP Executor

  Test->>Channel: updateMessage(message, operation, params)
  Channel->>RestInt: updateMessage:operation:params:wrapperSDKAgents:callback
  RestInt->>HTTP: PATCH /messages/{serial} (MsgPack body + wrapperSDKAgents)
  HTTP-->>RestInt: 200 OK / error (body)
  RestInt-->>Channel: callback(error?)
  Channel-->>Test: callback(error?)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing careful review:
    • HTTP request construction, path selection, MsgPack encoding/decoding and error augmentation in Source/ARTRestChannel.m.
    • Propagation and correct use of wrapperSDKAgents across proxy -> realtime -> rest internal layers (ARTWrapperSDKProxyRealtimeChannel.m, ARTRealtimeChannel.m, ARTChannel.m, ARTRestChannel.m).
    • ARTMessageOperation dictionary shape and private conformance (ARTMessageOperation+Private.h) vs. server expectations.
    • Modulemap and Xcode project updates to ensure headers/sources are exposed correctly and builds/tests pass.
    • New tests (MessageUpdatesDeletesTests.swift) verifying exact request bodies/endpoints—validate test assumptions and message encoding.

Poem

🐰 I hopped through headers, patch and test,

clientId warmed in metadata's nest,
PATCH and GET danced down the wire,
versions kept where edits conspire,
A tiny rabbit cheers: "Messages refreshed!"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main changes: implementing message update, delete, and version retrieval functionality.
Linked Issues check ✅ Passed The PR implements the mutable messages write API for message edits/deletes ECO-5634, adding updateMessage, deleteMessage, getMessageWithSerial, and getMessageVersionsWithSerial methods across REST and Realtime channels, aligning with ably-js behavior.
Out of Scope Changes check ✅ Passed All changes are scoped to implementing message update/delete/version APIs. Project structure updates, new ARTMessageOperation class, protocol updates, method implementations in REST/Realtime channels, and comprehensive tests are all directly related to the stated objective.
✨ 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 ECO-5634-message-updates

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/2146/features November 30, 2025 15:42 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2146/jazzydoc November 30, 2025 15:46 Inactive
@maratal maratal changed the title [ECO-5634] Message updates and deletes [ECO-5634] Messages update, delete and versions Nov 30, 2025
@github-actions github-actions bot temporarily deployed to staging/pull/2146/features December 1, 2025 01:19 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2146/jazzydoc December 1, 2025 01:22 Inactive
@lawrence-forooghian
Copy link
Collaborator

I know this one's in draft but I'm going to start taking a look at it now, because next week I'll need to build the Realtime equivalent on top of this.

@maratal
Copy link
Collaborator Author

maratal commented Dec 2, 2025

I know this one's in draft but I'm going to start taking a look at it now, because next week I'll need to build the Realtime equivalent on top of this.

You mean swift version?

@lawrence-forooghian
Copy link
Collaborator

You mean swift version?

No, I mean that the ARTRealtimeChannel versions of these methods are going to be replaced by sending a message over the Realtime connection instead of making a REST request.

@maratal maratal force-pushed the ECO-5634-message-updates branch from b63cc8f to 79f6161 Compare December 3, 2025 15:42
@github-actions github-actions bot temporarily deployed to staging/pull/2146/features December 3, 2025 15:43 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2146/jazzydoc December 3, 2025 15:46 Inactive
@maratal maratal force-pushed the ECO-5634-message-updates branch from 79f6161 to 1fff24c Compare December 3, 2025 17:50
@github-actions github-actions bot temporarily deployed to staging/pull/2146/features December 3, 2025 17:50 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2146/features December 4, 2025 21:59 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2146/jazzydoc December 4, 2025 22:02 Inactive
@maratal maratal marked this pull request as ready for review December 4, 2025 22:39
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1)

1-3: Prefer #import <Foundation/Foundation.h> and verify ARTMessageOperation.h visibility

To keep this private header friendly to all toolchains (including the static analysis configuration that reported an error), it would be safer and more consistent with typical Ably Cocoa headers to use a standard import:

-@import Foundation;
-#import <Ably/ARTMessageOperation.h>
-#import "ARTDictionarySerializable.h"
+#import <Foundation/Foundation.h>
+#import <Ably/ARTMessageOperation.h>
+#import "ARTDictionarySerializable.h"

Also, given the analyzer warning 'Ably/ARTMessageOperation.h' file not found, please double‑check that ARTMessageOperation.h is added to the appropriate header phase and exposed in all targets that include this private header so <Ably/…> resolves correctly.

Source/include/Ably/ARTChannelProtocol.h (1)

4-5: New channel message operation APIs look coherent and well-typed

  • Importing ARTStringifiable and forward‑declaring ARTMessageOperation are appropriate for the new signatures.
  • updateMessage:…params:callback: and deleteMessage:…params:callback: cleanly model operation metadata plus optional stringifiable params, while relying on the existing ARTCallback pattern.
  • getMessageWithSerial:callback: and getMessageVersionsWithSerial:callback: correctly use the new ARTMessageErrorCallback and existing ARTPaginatedMessagesCallback, matching their intended behaviors.

From a public API perspective, these additions are consistent with the surrounding channel methods and with the callback typedefs defined in ARTTypes.h.

If you plan further polish, consider expanding the docstrings slightly (for example, clarifying what kinds of values are expected in params and how message.serial is obtained) to make the new operations self‑explanatory to SDK consumers.

Also applies to: 9-10, 73-113

Source/include/Ably/ARTMessageOperation.h (1)

3-22: Consider copy semantics for properties and trimming unused imports

For an immutable, NS_SWIFT_SENDABLE type it would be safer to declare the string/dictionary properties as copy and copy the inputs in the initializer, to avoid external mutation via NSMutableString/NSMutableDictionary instances passed in.

Also, ARTStringifiable.h isn’t used in this header; if nothing transitively relies on it being re‑exported, you can drop that import to keep the public surface narrower.

Source/ARTMessageOperation.m (2)

16-21: Copy currently shares underlying objects; consider defensive copies

copyWithZone: assigns clientId, descriptionText, and metadata by reference:

operation->_clientId = self.clientId;
operation->_descriptionText = self.descriptionText;
operation->_metadata = self.metadata;

If callers ever pass mutable instances into the initializer, both the original and the copy will see subsequent mutations. If you want ARTMessageOperation to behave immutably, prefer copying here (and in the initializer) instead.


45-53: Unimplemented dictionary factories may fail silently in release

createFromDictionary: and initWithDictionary: currently NSAssert(false) and return nil. In release builds this just returns nil with no signal if someone accidentally wires these up via ARTDictionarySerializable.

If these aren’t needed yet, consider either:

  • Explicitly documenting them as unsupported (e.g. comment + ARTLogWarn), or
  • Implementing them now using the same keys as writeToDictionary:.

This avoids surprising nil in future refactors.

Source/ARTRestChannel.m (1)

104-118: REST message update/delete/get/version wiring looks correct and consistent

The new ARTRestChannel surface methods correctly forward to the internal counterparts with wrapperSDKAgents:nil, and ARTRestChannelInternal now centralises update/delete in _updateMessage:isDelete:operation:params:wrapperSDKAgents:callback: with:

  • Proper serial presence validation for RSL12/RSL13.
  • Request bodies that match the spec (serial, optional operation/name/data/encoding/extras) and reuse of dataEncoder for the message payload.
  • Correct endpoint/method selection for update (PATCH /messages/{serial}) vs delete (POST /messages/{serial}/delete), with params encoded into the query string.
  • Callbacks consistently marshalled back onto _userQueue, and wrapperSDKAgents threaded through to executeRequest / executePaginated.

Given there’s already a follow-up issue to de-duplicate REST request construction, this structure looks good for now.

Also applies to: 408-662

📜 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 44b2199 and c6474a3.

📒 Files selected for processing (16)
  • Ably.xcodeproj/project.pbxproj (16 hunks)
  • Source/ARTChannel.m (1 hunks)
  • Source/ARTMessageOperation.m (1 hunks)
  • Source/ARTRealtimeChannel.m (2 hunks)
  • Source/ARTRestChannel.m (3 hunks)
  • Source/ARTSummaryTypes.m (1 hunks)
  • Source/ARTWrapperSDKProxyRealtimeChannel.m (1 hunks)
  • Source/Ably.modulemap (1 hunks)
  • Source/PrivateHeaders/Ably/ARTChannel.h (2 hunks)
  • Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1 hunks)
  • Source/include/Ably/ARTChannelProtocol.h (2 hunks)
  • Source/include/Ably/ARTMessageOperation.h (1 hunks)
  • Source/include/Ably/ARTTypes.h (1 hunks)
  • Source/include/Ably/AblyPublic.h (1 hunks)
  • Source/include/module.modulemap (1 hunks)
  • Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (1 hunks)
🧰 Additional context used
🪛 Clang (14.0.6)
Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h

[error] 1-1: expected identifier or '('

(clang-diagnostic-error)


[error] 2-2: 'Ably/ARTMessageOperation.h' file not found

(clang-diagnostic-error)

Source/include/Ably/ARTMessageOperation.h

[error] 1-1: 'Foundation/Foundation.h' file not found

(clang-diagnostic-error)

🪛 SwiftLint (0.57.0)
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift

[Warning] 5-5: Imports should be unique

(duplicate_imports)


[Error] 126-126: Force casts should be avoided

(force_cast)


[Error] 252-252: Force casts should be avoided

(force_cast)

🔇 Additional comments (11)
Ably.xcodeproj/project.pbxproj (2)

384-392: ARTMessageOperation is correctly wired across targets and build phases

The new ARTMessageOperation files (public header, private header, and .m) are added consistently to:

  • PBXFileReference and the Types group,
  • all three frameworks’ Headers phases with appropriate Public/Private attributes,
  • all three frameworks’ Sources phases.

This matches the existing pattern for other message-related types (e.g., ARTMessageVersion) and should make the new type available on iOS, macOS, and tvOS without build issues.

Also applies to: 1241-1243, 1866-1868, 3081-3082


393-395: Confirm whether ARTDictionarySerializable is intentionally header‑only

ARTDictionarySerializable.h is added as:

  • a PBXFileReference under PrivateHeaders/Ably,
  • a member of the Types group,
  • a Private header in the iOS/macOS/tvOS Headers build phases.

There is no ARTDictionarySerializable.m referenced anywhere in this project file. If the type is meant to be header‑only (e.g. a protocol or category with no implementation), this is fine; if an implementation file exists, it still needs a PBXFileReference, PBXBuildFile, and Sources entries for each target to actually compile.

Please double‑check whether an .m is expected here and wire it up if so.

Also applies to: 1244-1244, 1935-1935, 2169-2171, 2501-2501, 2712-2712

Source/ARTSummaryTypes.m (1)

2-2: Importing ARTDictionarySerializable is appropriate here

The new import cleanly reflects that the summary types conform to ARTDictionarySerializable, without changing runtime behavior. Looks correct and consistent with the protocol usage throughout this file.

Source/include/Ably/ARTTypes.h (1)

504-505: New ARTMessageErrorCallback typedef is consistent with existing patterns

The message+error callback shape and nullability mirror other result/error callbacks in this header and are suitable for single‑message lookup APIs.

Source/include/Ably/AblyPublic.h (1)

48-48: Exposing ARTMessageOperation via the public umbrella is correct

Including ARTMessageOperation.h here makes the new message operation API available to SDK consumers in the expected way alongside other message types.

Source/include/module.modulemap (1)

142-143: SPM Private module now correctly exposes new internal headers

Adding ARTDictionarySerializable.h and ARTMessageOperation+Private.h to the Ably.Private explicit module keeps the SPM module map aligned with the new internal types and matches the Xcode module map changes.

Source/ARTChannel.m (1)

156-182: New abstract channel methods are wired consistently with existing design

The four new methods for update/delete/lookups follow the existing pattern for abstract operations on ARTChannel (assert‑only bodies to enforce subclass overrides) and align with the public protocol variants that don’t take wrapperSDKAgents. As long as ARTRestChannel and ARTRealtimeChannel override these, this is a clean extension of the existing design.

Please confirm both concrete channel implementations override all four methods so these code paths are never hit in production.

Source/Ably.modulemap (1)

142-143: Xcode module map correctly updated for new private headers

Including ARTDictionarySerializable.h and ARTMessageOperation+Private.h in the Ably.Private module keeps the Xcode module map consistent with SPM and ensures internal code using import Ably.Private can see these types.

Source/ARTWrapperSDKProxyRealtimeChannel.m (1)

107-136: Wrapper forwarding for message operations looks consistent

The new getMessageWithSerial, updateMessage, deleteMessage, and getMessageVersionsWithSerial methods correctly delegate to underlyingChannel.internal and pass through proxyOptions.agents, matching the internal API shape and keeping wrapperSDK agent propagation consistent.

Source/PrivateHeaders/Ably/ARTChannel.h (1)

48-66: Channel-level message APIs align with internal implementations

The added updateMessage, deleteMessage, getMessageWithSerial, and getMessageVersionsWithSerial signatures match the corresponding internal/rest implementations (including ARTStringifiable params and NSStringDictionary *wrapperSDKAgents), which should keep the public/internal surfaces in sync.

Source/ARTRealtimeChannel.m (1)

147-161: Realtime message operation APIs are wired cleanly through to REST

The new updateMessage, deleteMessage, getMessageWithSerial, and getMessageVersionsWithSerial overloads on ARTRealtimeChannel and ARTRealtimeChannelInternal consistently delegate to the REST channel, threading wrapperSDKAgents where provided and defaulting to nil otherwise. This keeps the public realtime API thin while reusing the REST implementation for edits/deletes/versions.

Also applies to: 470-492

@maratal maratal force-pushed the ECO-5634-message-updates branch from c6474a3 to 5109ce4 Compare December 7, 2025 16:54
@github-actions github-actions bot temporarily deployed to staging/pull/2146/features December 7, 2025 16:54 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2146/jazzydoc December 7, 2025 16:56 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (3)

1-6: Duplicate import flagged by SwiftLint.

This issue was already noted in previous review comments. The duplicate import Ably should be removed, keeping only @testable import Ably.


53-80: Polling pattern may cause flaky tests.

The helpers use sleep(1) in a loop to poll for message availability. This was already flagged in a previous review comment as potentially flaky. Consider using a more reliable mechanism such as subscribing to messages on a Realtime connection.


145-145: Force cast flagged by SwiftLint.

The force cast as! ARTMessage was already noted in previous review comments and should be replaced with a safe downcast using guard-let.

🧹 Nitpick comments (4)
Source/include/Ably/ARTMessageOperation.h (1)

3-3: Remove unused import.

The import of ARTStringifiable.h doesn't appear to be needed in this public header—none of the declared types reference ARTStringifiable.

Apply this diff:

 #import <Foundation/Foundation.h>
 #import <Ably/ARTTypes.h>
-#import "ARTStringifiable.h"
Source/ARTMessageOperation.m (1)

16-22: Consider using designated initializer in copyWithZone:.

The current implementation directly accesses ivars after calling init. While this works, using the designated initializer would be more maintainable and ensure any initialization logic is consistently applied.

Apply this diff:

 - (id)copyWithZone:(NSZone *)zone {
-    ARTMessageOperation *operation = [[[self class] allocWithZone:zone] init];
-    operation->_clientId = self.clientId;
-    operation->_descriptionText = self.descriptionText;
-    operation->_metadata = self.metadata;
-    return operation;
+    return [[[self class] allocWithZone:zone] initWithClientId:self.clientId
+                                                descriptionText:self.descriptionText
+                                                       metadata:self.metadata];
 }
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (1)

38-38: Document the "mutable:" prefix requirement.

The comment states "updates and deletes don't work without this prefix" but doesn't explain why. This appears to be a server-side or test environment constraint that should be documented more clearly for maintainability.

Source/ARTRealtimeChannel.m (1)

470-493: Document that this REST delegation is temporary.

These methods currently forward to the REST channel, but per the PR discussion, they will be replaced to send messages over the Realtime connection instead of making REST requests.

Consider adding inline comments indicating this is temporary implementation that will be replaced when true Realtime support is added.

📜 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 c6474a3 and 5109ce4.

📒 Files selected for processing (16)
  • Ably.xcodeproj/project.pbxproj (16 hunks)
  • Source/ARTChannel.m (1 hunks)
  • Source/ARTMessageOperation.m (1 hunks)
  • Source/ARTRealtimeChannel.m (2 hunks)
  • Source/ARTRestChannel.m (3 hunks)
  • Source/ARTSummaryTypes.m (1 hunks)
  • Source/ARTWrapperSDKProxyRealtimeChannel.m (1 hunks)
  • Source/Ably.modulemap (1 hunks)
  • Source/PrivateHeaders/Ably/ARTChannel.h (2 hunks)
  • Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1 hunks)
  • Source/include/Ably/ARTChannelProtocol.h (2 hunks)
  • Source/include/Ably/ARTMessageOperation.h (1 hunks)
  • Source/include/Ably/ARTTypes.h (1 hunks)
  • Source/include/Ably/AblyPublic.h (1 hunks)
  • Source/include/module.modulemap (1 hunks)
  • Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • Source/include/Ably/ARTTypes.h
  • Source/include/Ably/AblyPublic.h
  • Source/include/module.modulemap
  • Source/include/Ably/ARTChannelProtocol.h
🧰 Additional context used
🧬 Code graph analysis (1)
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (2)
Test/AblyTests/Test Utilities/TestUtilities.swift (4)
  • commonAppSetup (107-142)
  • clientOptions (144-159)
  • extractBodyAsMsgPack (698-716)
  • value (1920-1922)
Test/AblyTests/Test Utilities/Test.swift (1)
  • uniqueChannelName (15-32)
🪛 Clang (14.0.6)
Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h

[error] 1-1: expected identifier or '('

(clang-diagnostic-error)


[error] 2-2: 'Ably/ARTMessageOperation.h' file not found

(clang-diagnostic-error)

Source/include/Ably/ARTMessageOperation.h

[error] 1-1: 'Foundation/Foundation.h' file not found

(clang-diagnostic-error)

⏰ 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: check
  • GitHub Check: check
  • GitHub Check: build
  • GitHub Check: check (macOS, test_macOS)
  • GitHub Check: check (tvOS, test_tvOS18_4)
  • GitHub Check: check (iOS, test_iOS18_4)
🔇 Additional comments (24)
Source/ARTSummaryTypes.m (1)

2-2: LGTM! Clean header dependency update.

The replacement of ARTSummaryTypes+Private.h with ARTDictionarySerializable.h is consistent with the classes' existing protocol conformance and implementation. The refactoring consolidates serialization protocols without affecting the logic.

Ably.xcodeproj/project.pbxproj (7)

384-395: Build files for ARTMessageOperation and ARTDictionarySerializable are consistent across targets

The new PBXBuildFile entries correctly register public and private headers and the implementation for ARTMessageOperation, plus the private ARTDictionarySerializable header, following the existing three‑per‑target pattern. No issues spotted.


1241-1244: File references for new types are correctly defined

ARTMessageOperation public/private headers and implementation, and the private ARTDictionarySerializable header, all have coherent names, paths, and file types (public headers under include/Ably, private under PrivateHeaders/Ably). This matches how other types are wired.


1866-1868: Placement of new types in the Types group is appropriate

Adding ARTMessageOperation (public and private) and ARTDictionarySerializable into the Types group keeps the project structure consistent with other message‑related entities and shared type utilities.

Also applies to: 1935-1936


2169-2171: iOS headers phase wiring looks correct

For the iOS target, ARTMessageOperation.h is exposed as Public, ARTMessageOperation+Private.h and ARTDictionarySerializable.h are Private, matching their paths and intended visibility. All three are present, so iOS consumers and internals will see the right surfaces.

Also applies to: 2266-2267, 2296-2297


2332-2333: macOS headers phase updated consistently

The macOS target’s Headers phase includes the same trio (ARTMessageOperation.h Public; ARTMessageOperation+Private.h and ARTDictionarySerializable.h Private), mirroring the iOS configuration. No target‑skew detected.

Also applies to: 2351-2352, 2501-2502


2543-2544: tvOS headers phase updated consistently

The tvOS target also wires ARTMessageOperation and ARTDictionarySerializable into its Headers phase with the same public/private split. All three platforms are aligned.

Also applies to: 2562-2563, 2712-2713


3081-3090: ARTMessageOperation.m is compiled for all framework targets

ARTMessageOperation.m has been added to the Sources phases for iOS, macOS, and tvOS, so the new type is available everywhere the framework builds. This matches how other core types are handled.

Also applies to: 3226-3235, 3371-3380

Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1)

1-10: LGTM!

The private header correctly declares the ARTDictionarySerializable conformance for ARTMessageOperation. The structure follows standard patterns for private category extensions in this codebase.

Source/Ably.modulemap (1)

142-143: LGTM!

The module map correctly exposes the new private headers ARTDictionarySerializable.h and ARTMessageOperation+Private.h in the Private module, consistent with the existing module structure.

Source/include/Ably/ARTMessageOperation.h (1)

7-24: LGTM!

The public API design is clean and well-documented. Properties are correctly marked readonly to ensure immutability, and NS_SWIFT_SENDABLE is appropriate for this value type.

Source/ARTChannel.m (1)

156-182: LGTM!

The abstract method pattern correctly enforces subclass override requirements, consistent with the existing historyWithWrapperSDKAgents: and internalPostMessages: methods. The wrapperSDKAgents parameter is consistently threaded through all new APIs.

Source/PrivateHeaders/Ably/ARTChannel.h (2)

5-5: LGTM!

The ARTStringifiable import is correctly added to support the params parameter type used in the new method declarations.


48-67: LGTM!

The method declarations correctly match the implementations in ARTChannel.m and follow consistent parameter ordering and naming conventions with the existing API surface.

Source/ARTMessageOperation.m (2)

33-43: LGTM!

The serialization logic correctly maps descriptionText property to "description" key (line 38), which aligns with the API specification.


45-53: ARTMessageOperation is intentionally write-only and deserialization is not needed.

The class conforms to ARTDictionarySerializable protocol but implements createFromDictionary: and initWithDictionary: as "Not implemented" assertions, while providing writeToDictionary: for serialization. No calls to these deserialization methods exist in the codebase. The design reflects that message operations are created client-side, serialized for sending, and never deserialized from received messages.

Source/ARTWrapperSDKProxyRealtimeChannel.m (1)

107-136: LGTM!

The forwarding methods correctly delegate to underlyingChannel.internal with wrapperSDKAgents, following the established pattern used by the existing history: method (lines 62-65).

Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (1)

82-411: Tests provide good coverage of the new message operations API.

The test implementations thoroughly verify:

  • HTTP methods and endpoints
  • Request body serialization (including operation metadata)
  • Query parameters
  • Response message properties and versions
  • Both REST and Realtime code paths

The test structure effectively reuses logic between REST and Realtime via the TestEnvironment abstraction.

Source/ARTRealtimeChannel.m (1)

147-162: LGTM: Public API delegation is correct.

The public methods properly delegate to internal implementations with wrapperSDKAgents:nil, following the established pattern used elsewhere in this file.

Source/ARTRestChannel.m (5)

8-9: LGTM: Required imports added.


104-119: LGTM: Public API delegation is correct.


532-548: LGTM: Proper delegation to shared implementation.

The spec point comments are helpful references.


550-623: LGTM: Solid implementation with proper error handling.

The method correctly constructs the request, decodes the response, and applies data decoding consistently with the history method pattern.


625-662: LGTM: Follows established pagination pattern.

The implementation correctly mirrors the history method's approach for paginated results, ensuring consistency across the codebase.

@maratal maratal force-pushed the ECO-5634-message-updates branch from 5109ce4 to 911a9e4 Compare December 7, 2025 17:12
@github-actions github-actions bot temporarily deployed to staging/pull/2146/features December 7, 2025 17:12 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2146/jazzydoc December 7, 2025 17:15 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (3)

1-6: Remove duplicate import.

The file contains both import Ably (line 1) and @testable import Ably (line 5). The @testable import provides access to all public symbols, making the first import redundant.

Apply this diff:

-import Ably
 import Nimble
 import XCTest

 @testable import Ably

154-156: Replace force cast with safe downcast.

The force cast as! ARTMessage on line 154 will crash if copy() doesn't return an ARTMessage. Use a safe downcast with a guard statement instead.

Apply this diff:

-        let messageUpdate = publishedMessage.copy() as! ARTMessage
+        guard let messageUpdate = publishedMessage.copy() as? ARTMessage else {
+            XCTFail("Failed to copy published message as ARTMessage")
+            return
+        }

270-273: Replace force cast with safe downcast.

The force cast as! ARTMessage on line 270 will crash if copy() doesn't return an ARTMessage. Use a safe downcast with a guard statement instead.

Apply this diff:

-        let messageDelete = publishedMessage.copy() as! ARTMessage
+        guard let messageDelete = publishedMessage.copy() as? ARTMessage else {
+            XCTFail("Failed to copy published message as ARTMessage")
+            return
+        }
🧹 Nitpick comments (3)
Source/ARTMessageOperation.m (1)

6-21: Prefer going through property setters / designated initializer in init and copy

Right now both the initializer and copyWithZone: write directly to ivars. If the properties in ARTMessageOperation+Private.h are declared with copy (or later gain different memory semantics), this will bypass those guarantees and could be surprising.

Consider:

  • Using property setters in the initializer, and
  • Having copyWithZone: delegate to the designated initializer so future fields aren’t accidentally missed.

For example:

- (instancetype)initWithClientId:(NSString *)clientId
                    descriptionText:(NSString *)descriptionText
                           metadata:(NSDictionary<NSString *, NSString *> *)metadata {
-    self = [super init];
-    if (self) {
-        _clientId = clientId;
-        _descriptionText = descriptionText;
-        _metadata = metadata;
-    }
-    return self;
-}
+ (instancetype)operationWithClientId:(NSString *)clientId
+                      descriptionText:(NSString *)descriptionText
+                             metadata:(NSDictionary<NSString *, NSString *> *)metadata {
+    return [[self alloc] initWithClientId:clientId
+                          descriptionText:descriptionText
+                                 metadata:metadata];
+}
+
+- (instancetype)initWithClientId:(NSString *)clientId
+                  descriptionText:(NSString *)descriptionText
+                         metadata:(NSDictionary<NSString *, NSString *> *)metadata {
+    self = [super init];
+    if (self) {
+        self.clientId = clientId;
+        self.descriptionText = descriptionText;
+        self.metadata = metadata;
+    }
+    return self;
+}
@@
 - (id)copyWithZone:(NSZone *)zone {
-    ARTMessageOperation *operation = [[[self class] allocWithZone:zone] init];
-    operation->_clientId = self.clientId;
-    operation->_descriptionText = self.descriptionText;
-    operation->_metadata = self.metadata;
-    return operation;
+    return [[[self class] allocWithZone:zone] initWithClientId:self.clientId
+                                               descriptionText:self.descriptionText
+                                                      metadata:self.metadata];
 }

(Adjust to match your existing initializer patterns if you don’t want the extra factory method.)

Source/include/Ably/ARTMessageOperation.h (1)

3-3: Inconsistent import style for public header.

This import uses quotes while other public framework headers in this file use angle brackets. For consistency and proper framework resolution, consider using the angle bracket style.

-#import "ARTStringifiable.h"
+#import <Ably/ARTStringifiable.h>
Source/include/Ably/ARTChannelProtocol.h (1)

4-4: Inconsistent import style for public header.

Same as in ARTMessageOperation.h—this import uses quotes while other public framework headers use angle brackets.

-#import "ARTStringifiable.h"
+#import <Ably/ARTStringifiable.h>
📜 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 5109ce4 and 911a9e4.

📒 Files selected for processing (16)
  • Ably.xcodeproj/project.pbxproj (16 hunks)
  • Source/ARTChannel.m (1 hunks)
  • Source/ARTMessageOperation.m (1 hunks)
  • Source/ARTRealtimeChannel.m (2 hunks)
  • Source/ARTRestChannel.m (3 hunks)
  • Source/ARTSummaryTypes.m (1 hunks)
  • Source/ARTWrapperSDKProxyRealtimeChannel.m (1 hunks)
  • Source/Ably.modulemap (1 hunks)
  • Source/PrivateHeaders/Ably/ARTChannel.h (2 hunks)
  • Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1 hunks)
  • Source/include/Ably/ARTChannelProtocol.h (2 hunks)
  • Source/include/Ably/ARTMessageOperation.h (1 hunks)
  • Source/include/Ably/ARTTypes.h (1 hunks)
  • Source/include/Ably/AblyPublic.h (1 hunks)
  • Source/include/module.modulemap (1 hunks)
  • Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • Source/include/module.modulemap
  • Source/ARTWrapperSDKProxyRealtimeChannel.m
  • Source/include/Ably/AblyPublic.h
  • Source/ARTRealtimeChannel.m
  • Source/ARTSummaryTypes.m
🧰 Additional context used
🧬 Code graph analysis (1)
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (2)
Test/AblyTests/Test Utilities/TestUtilities.swift (4)
  • commonAppSetup (107-142)
  • clientOptions (144-159)
  • data (932-934)
  • extractBodyAsMsgPack (698-716)
Test/AblyTests/Test Utilities/Test.swift (1)
  • uniqueChannelName (15-32)
🪛 Clang (14.0.6)
Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h

[error] 1-1: expected identifier or '('

(clang-diagnostic-error)


[error] 2-2: 'Ably/ARTMessageOperation.h' file not found

(clang-diagnostic-error)

Source/include/Ably/ARTMessageOperation.h

[error] 1-1: 'Foundation/Foundation.h' file not found

(clang-diagnostic-error)

🪛 SwiftLint (0.57.0)
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift

[Warning] 5-5: Imports should be unique

(duplicate_imports)


[Error] 154-154: Force casts should be avoided

(force_cast)


[Error] 270-270: Force casts should be avoided

(force_cast)

⏰ 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: check (macOS, test_macOS)
  • GitHub Check: check (tvOS, test_tvOS18_4)
  • GitHub Check: check (iOS, test_iOS18_4)
  • GitHub Check: check
  • GitHub Check: check
  • GitHub Check: build
🔇 Additional comments (21)
Source/include/Ably/ARTTypes.h (1)

504-506: ARTMessageErrorCallback typedef looks consistent and well‑placed

The new ARTMessageErrorCallback matches the existing callback style (message first, error second), sits alongside ARTMessageCallback, and uses appropriate nullability for message/error. This is a sensible public shape for the new message APIs.

Ably.xcodeproj/project.pbxproj (2)

384-395: New ARTMessageOperation/ARTDictionarySerializable wiring looks consistent across targets*

The new PBXBuildFile, PBXFileReference, group, and Headers‑phase entries for:

  • ARTMessageOperation+Private.h
  • ARTMessageOperation.h
  • ARTMessageOperation.m
  • ARTDictionarySerializable.h

are internally consistent and follow the same pattern as existing types (e.g. ARTMessageVersion*, ARTStringifiable*) for all three framework targets (iOS, macOS, tvOS). ARTMessageOperation.h is exposed as Public, while ARTMessageOperation+Private.h and ARTDictionarySerializable.h are Private, which matches their directory locations (include/Ably vs PrivateHeaders/Ably).

One thing to double‑check: if ARTDictionarySerializable is ever intended to be part of the public ABI (e.g. appears in public method signatures), it would need to be moved under include/Ably and marked Public in the headers phases; otherwise the current private wiring is correct.

Also applies to: 1241-1244, 1866-1936, 2169-2297, 2332-2352, 2501-2501, 2543-2563, 2712-2712


3081-3081: ARTMessageOperation.m is correctly added to all platform Sources phases

ARTMessageOperation.m has three PBXBuildFile entries and is hooked into the Sources build phases for Ably‑iOS, Ably‑macOS, and Ably‑tvOS, mirroring how other shared Objective‑C sources are wired. No duplicate or missing source wiring is apparent.

Also applies to: 3226-3226, 3371-3372

Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1)

1-10: LGTM!

Clean private category extension declaring ARTDictionarySerializable protocol conformance. The import style is consistent with project conventions—angle brackets for framework public headers and quotes for private headers.

Source/PrivateHeaders/Ably/ARTChannel.h (1)

48-66: LGTM!

The internal wrapperSDKAgents variants provide the necessary plumbing for wrapper SDKs to inject their agent information. Method signatures are consistent with the public protocol and the abstract implementations in ARTChannel.m.

Source/Ably.modulemap (1)

142-143: LGTM!

The new private headers are correctly added to the explicit Private module, enabling test access via import Ably.Private.

Source/include/Ably/ARTMessageOperation.h (1)

10-24: LGTM!

The ARTMessageOperation interface is well-designed with readonly properties ensuring thread-safety for NS_SWIFT_SENDABLE. The designated initializer follows standard conventions.

Source/include/Ably/ARTChannelProtocol.h (1)

73-113: LGTM!

The new protocol methods are well-documented and follow the existing API patterns. The distinction between updateMessage/deleteMessage (with operation metadata) and getMessageWithSerial/getMessageVersionsWithSerial (retrieval operations) is clear.

Source/ARTChannel.m (1)

156-182: LGTM!

The abstract method stubs follow the established pattern in this file. All four new methods are properly implemented in both concrete subclasses:

  • ARTRestChannel implements all four methods (lines 104-117)
  • ARTRealtimeChannel implements all four methods (lines 147-160)

Each method delegates to the _internal implementation, passing wrapperSDKAgents:nil, which is the correct behavior. Using NSAssert ensures that missing overrides are caught during development, and the consistent implementation across subclasses confirms the abstract pattern is working as intended.

Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (6)

11-60: Well-structured test environment abstraction.

The TestEnvironment enum provides a clean dual-protocol testing approach with shared helpers for REST and Realtime channels. The factory methods properly configure clients with HTTP proxies for request inspection.


62-74: Polling pattern is appropriate given server behavior.

The sleep(1) + polling approach correctly handles the server's eventual consistency for history availability. The pattern was discussed in past reviews and is necessary since the server initially returns empty arrays.


91-134: Comprehensive getMessage test with proper spec coverage.

The test correctly validates RSL11a/b/c: takes serial as argument, sends GET to correct endpoint, and returns decoded message. Good use of guard statements for early exits.


183-250: Thorough validation of update request body and version properties.

The test comprehensively verifies RSL12b1-b6 (serial, operation, name, data, encoding, extras) and correctly validates version properties including serial ordering, timestamp ordering, and operation metadata.


288-365: Comprehensive delete operation validation.

The test correctly verifies RSL13b (POST to /delete endpoint), RSL13b1-b6 (request body fields), and validates the message is marked with action == .delete with proper version metadata.


367-432: Well-organized test entry points with proper resource cleanup.

The public test methods clearly map to spec points (RSL11/RTL28, RSL12/RSL14/RTL29/RTL31, RSL13/RTL30) and use defer blocks to ensure Realtime clients are properly closed, preventing resource leaks.

Source/ARTRestChannel.m (6)

8-9: LGTM!

The new imports for ARTMessageOperation support the message update/delete functionality introduced in this PR.


104-118: Consistent delegation pattern for new methods.

The public methods correctly delegate to internal implementations with wrapperSDKAgents:nil, matching the established pattern used in other methods like history:callback:error: (line 57).


408-530: Well-structured update/delete implementation following spec requirements.

The shared _updateMessage:isDelete:... method correctly:

  • Validates serial presence with a helpful error message (lines 425-430)
  • Constructs request body per RSL12b/RSL13b requirements (lines 433-470)
  • Encodes data with proper encoder (lines 453-465)
  • Differentiates PATCH vs POST to /delete endpoint (lines 485-493)
  • Handles query params and error reporting consistently (lines 497-527)

532-548: Clean internal delegation for wrapper SDK support.

The internal wrapperSDKAgents-aware methods properly delegate to the shared _updateMessage:isDelete:... helper with the appropriate isDelete flag, enabling wrapper SDK proxy implementations to pass through context.


550-623: Correct getMessage implementation with proper two-stage decoding.

The implementation correctly:

  • Constructs GET request to /messages/{serial} with URL-encoded serial (lines 564-568)
  • Selects decoder based on response MIME type (lines 588-594)
  • Applies two-stage decoding: first protocol decoding, then data decoding with dataEncoder (lines 596-611)
  • Handles errors with optional request-id augmentation (lines 573-584)

This pattern matches the established history: method at lines 228-239.


625-662: Correct paginated getMessageVersions implementation.

The implementation properly:

  • Constructs GET request to /messages/{serial}/versions (lines 639-643)
  • Uses ARTPaginatedResult.executePaginated for pagination support (line 660)
  • Applies the established two-stage decoding pattern with error logging (lines 647-658)

The response processor matches the pattern used in history: at lines 228-239.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (4)
Source/ARTMessageOperation.m (1)

45-53: Unimplemented dictionary initializers return nil in release builds.

This issue was already flagged in a past review. The createFromDictionary: and initWithDictionary: stubs assert and return nil, which silently fails in release builds where assertions are compiled out. Consider implementing proper deserialization or marking these methods NS_UNAVAILABLE if deserialization is not intended.

Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (3)

1-5: Duplicate import already flagged.

The duplicate import Ably (line 1) alongside @testable import Ably (line 5) was already identified in a past review. Only @testable import Ably is needed.


157-157: Force cast already flagged.

The force cast as! ARTMessage was already identified in a past review. Consider using guard let ... as? ARTMessage for safer handling.


273-273: Force cast already flagged.

The force cast as! ARTMessage at line 273 was already identified in a past review for line 157. The same fix applies here.

🧹 Nitpick comments (6)
Source/ARTMessageOperation.m (1)

16-22: Consider using the designated initializer in copyWithZone:.

The current implementation bypasses the designated initializer by directly assigning instance variables. This works but can become fragile if initialization logic changes in the future.

 - (id)copyWithZone:(NSZone *)zone {
-    ARTMessageOperation *operation = [[[self class] allocWithZone:zone] init];
-    operation->_clientId = self.clientId;
-    operation->_descriptionText = self.descriptionText;
-    operation->_metadata = self.metadata;
+    ARTMessageOperation *operation = [[[self class] allocWithZone:zone] initWithClientId:self.clientId
+                                                                         descriptionText:self.descriptionText
+                                                                                metadata:self.metadata];
     return operation;
 }
Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (2)

238-245: Force unwraps could cause test crashes on unexpected nil values.

Multiple force unwraps (version!.serial!, version!.timestamp!, publishedMessage.timestamp!) will crash the test if these optionals are nil, making debugging harder than using proper assertions.

Consider using XCTUnwrap or explicit assertions:

let versionSerial = try XCTUnwrap(updatedMessage.version?.serial)
let versionTimestamp = try XCTUnwrap(updatedMessage.version?.timestamp)
let publishedTimestamp = try XCTUnwrap(publishedMessage.timestamp)
XCTAssertTrue(versionSerial > publishedMessageSerial)
XCTAssertTrue(versionTimestamp > publishedTimestamp)

360-367: Same force unwrap pattern in delete test.

The force unwraps at lines 362 and 364 have the same issue as the update test. Consider using XCTUnwrap for safer test assertions.

Source/include/Ably/ARTMessageOperation.h (1)

7-24: Tighten initializer contract and broaden doc wording for multi‑use operations

The type shape looks good (readonly properties + NS_SWIFT_SENDABLE), but two small API‑polish tweaks could help:

  • The comment “Contains operation metadata for message updates” is a bit narrow now that this type is also used for deletes; consider wording like “mutable message operations (for example updates and deletes)” so the intent is clear from the header alone.
  • Since all properties are readonly and there’s a single custom initializer, consider marking initWithClientId:descriptionText:metadata: as NS_DESIGNATED_INITIALIZER and explicitly disabling plain -init (e.g. - (instancetype)init NS_UNAVAILABLE;). That will prevent partially initialised instances and makes the construction pattern clearer for both Obj‑C and Swift users.
Source/include/Ably/ARTChannelProtocol.h (1)

73-113: New mutable‑message and version APIs look coherent; consider minor doc clarifications

The added methods fit well with the existing channel API:

  • Using ARTMessageOperation here and ARTStringifiable values for params matches how other request parameters are handled.
  • Nullable callbacks on the mutating methods and non‑nullable callbacks on the retrieval methods are consistent with the existing publish: vs history: patterns.

Two minor doc‑level suggestions:

  • For updateMessage: / deleteMessage:, you already mention that message must have a populated serial. It might be worth briefly hinting where that comes from (for example, “obtained from a previously received or published message”) so users don’t need to hunt through other docs.
  • For the serial parameter in the getMessageWithSerial: and getMessageVersionsWithSerial: docs, you could cross‑reference the same concept (the serial field on ARTMessage) to tie the terminology together.

These are purely documentation refinements; the API surface itself looks solid.

Source/ARTRestChannel.m (1)

550-662: Solid implementation of message retrieval methods.

Both methods correctly implement:

  • Thread-safe callback dispatching
  • URL construction with proper encoding
  • Comprehensive error handling
  • Response decoding flow (MIME type → message → data)
  • Request ID augmentation when configured

The paginated versions method appropriately reuses the existing ARTPaginatedResult infrastructure and follows the pattern established by the history method.

Consider adding upfront validation for serial parameter (non-nil and non-empty) in both get methods, similar to the serial validation in _updateMessage at lines 425-430. While the server will reject malformed requests, client-side validation would provide clearer error messages to users.

📜 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 911a9e4 and de8df3f.

📒 Files selected for processing (16)
  • Ably.xcodeproj/project.pbxproj (16 hunks)
  • Source/ARTChannel.m (1 hunks)
  • Source/ARTMessageOperation.m (1 hunks)
  • Source/ARTRealtimeChannel.m (2 hunks)
  • Source/ARTRestChannel.m (3 hunks)
  • Source/ARTSummaryTypes.m (1 hunks)
  • Source/ARTWrapperSDKProxyRealtimeChannel.m (1 hunks)
  • Source/Ably.modulemap (1 hunks)
  • Source/PrivateHeaders/Ably/ARTChannel.h (2 hunks)
  • Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1 hunks)
  • Source/include/Ably/ARTChannelProtocol.h (2 hunks)
  • Source/include/Ably/ARTMessageOperation.h (1 hunks)
  • Source/include/Ably/ARTTypes.h (1 hunks)
  • Source/include/Ably/AblyPublic.h (1 hunks)
  • Source/include/module.modulemap (1 hunks)
  • Test/AblyTests/Tests/MessageUpdatesDeletesTests.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • Source/include/Ably/AblyPublic.h
  • Source/PrivateHeaders/Ably/ARTChannel.h
  • Source/Ably.modulemap
  • Source/include/Ably/ARTTypes.h
  • Source/ARTSummaryTypes.m
  • Source/ARTWrapperSDKProxyRealtimeChannel.m
🧰 Additional context used
🪛 Clang (14.0.6)
Source/include/Ably/ARTMessageOperation.h

[error] 1-1: 'Foundation/Foundation.h' file not found

(clang-diagnostic-error)

Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h

[error] 1-1: expected identifier or '('

(clang-diagnostic-error)


[error] 2-2: 'Ably/ARTMessageOperation.h' file not found

(clang-diagnostic-error)

⏰ 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: check
  • GitHub Check: check (macOS, test_macOS)
  • GitHub Check: check (tvOS, test_tvOS18_4)
  • GitHub Check: check (iOS, test_iOS18_4)
  • GitHub Check: check
  • GitHub Check: build
🔇 Additional comments (14)
Source/ARTChannel.m (1)

156-182: LGTM! Abstract method stubs follow established patterns.

The four new methods correctly use NSAssert(false, ...) to enforce subclass override requirements, consistent with the existing abstract methods like historyWithWrapperSDKAgents:completion: and internalPostMessages:callback: at lines 207-213.

Source/include/module.modulemap (1)

142-143: LGTM! Private headers correctly added to module map.

The new ARTDictionarySerializable.h and ARTMessageOperation+Private.h headers are appropriately added to the Private module for internal/testing access.

Source/PrivateHeaders/Ably/ARTMessageOperation+Private.h (1)

1-10: LGTM! Private category header correctly structured.

The private header properly declares the ARTMessageOperation category conforming to ARTDictionarySerializable. The static analysis errors (lines 1-2) are false positives caused by the analyzer lacking the full build context—@import Foundation and the umbrella header path are valid in the project's module structure.

Ably.xcodeproj/project.pbxproj (5)

384-395: PBXBuildFile entries for ARTMessageOperation/ARTDictionarySerializable look consistent

The new build-file entries correctly:

  • Add ARTMessageOperation+Private.h as Private and ARTMessageOperation.h as Public.
  • Wire ARTMessageOperation.m into Sources for all three platforms.
  • Expose ARTDictionarySerializable.h as Private only.

This matches existing multi-target patterns and the intended public/private API split.


1241-1244: File references for new types are correctly defined

ARTMessageOperation+Private.h, ARTMessageOperation.h, and ARTMessageOperation.m are all given PBXFileReferences, with paths consistent with other Types files. ARTDictionarySerializable.h is added under PrivateHeaders/Ably, matching its private usage.

No wiring issues apparent at the file-reference level.


1866-1868: Types group membership is organised and matches neighbouring message types

Placing ARTMessageOperation (public and private headers plus .m) and ARTDictionarySerializable.h in the Types group alongside ARTMessageVersion and message annotations keeps project structure coherent and discoverable.

Looks good and consistent with existing organisation.

Also applies to: 1935-1936


2169-2169: Header exposure across iOS/macOS/tvOS targets is wired correctly

The new header entries:

  • Export ARTMessageOperation.h as Public in all three headers build phases.
  • Keep ARTMessageOperation+Private.h and ARTDictionarySerializable.h Private in all three headers build phases.

This ensures the public API surface is consistent across platforms while keeping internals hidden.

Also applies to: 2332-2332, 2351-2351, 2501-2501, 2543-2543, 2562-2562, 2712-2712


3081-3081: Sources build phases include ARTMessageOperation.m for all platforms

ARTMessageOperation.m is added to the Sources build phases for iOS (96BF612C), macOS (D710D457), and tvOS (D710D471), matching how other shared Types are handled.

No missing target or asymmetry spotted.

Also applies to: 3226-3226, 3371-3371

Source/ARTRestChannel.m (4)

8-9: LGTM!

The imports are correctly added to support the new message operations functionality.


104-118: LGTM!

The public method delegates follow the established pattern in the codebase, correctly passing wrapperSDKAgents:nil to the internal implementations.


408-530: Well-implemented shared update/delete logic.

The implementation correctly handles:

  • Thread-safe callback dispatching
  • Serial validation with user-friendly error messages
  • Request body construction per spec (RSL12b/RSL13b)
  • Data encoding with proper error handling
  • Differentiated paths for update (PATCH) vs delete (POST to /delete endpoint)
  • Query parameter serialization
  • Error augmentation with request IDs when configured

532-548: LGTM!

The update and delete methods correctly delegate to the shared implementation with the appropriate isDelete flag, maintaining clean separation of concerns.

Source/ARTRealtimeChannel.m (2)

147-161: LGTM!

The public method delegates follow the established pattern, correctly forwarding to internal implementations with wrapperSDKAgents:nil, consistent with other public methods in the file.


470-492: LGTM!

The internal methods correctly forward to the REST channel implementation, passing through wrapperSDKAgents as intended. Per the PR objectives, this REST-based approach is the current implementation strategy, with future work planned to send these operations over the Realtime connection as protocol messages.

@maratal maratal merged commit baad166 into main Dec 9, 2025
11 of 12 checks passed
@maratal maratal deleted the ECO-5634-message-updates branch December 9, 2025 22:17
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