-
Notifications
You must be signed in to change notification settings - Fork 7
[ECO-4974] Throw ARTErrorInfo from public API
#234
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis pull request refines error handling throughout the Chat SDK. It adds a new “Throwing errors” section to the documentation and updates numerous asynchronous method signatures to explicitly throw either an Changes
Sequence Diagram(s)sequenceDiagram
participant C as Client
participant API as Chat API Method
participant IC as InternalError Converter
participant PA as Public API Layer
C->>API: Call async method (e.g. sendMessage)
API->>API: Execute with async/continuation
alt An error occurs
API->>IC: Convert caught error → InternalError
IC-->>API: Return InternalError
API->>PA: Convert InternalError to ARTErrorInfo for public API
PA-->>C: Throw ARTErrorInfo
else Success
API-->>C: Return result
end
Possibly related PRs
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
c2cb928 to
dba13ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 8
🔭 Outside diff range comments (1)
Sources/AblyChat/DefaultPresence.swift (1)
267-295: 🛠️ Refactor suggestionRobust decoding of presence messages.
processPresenceGet(lines 267-295) handles multiple possible missing fields (clientID, timestamp, data). The approach is well-structured. Consider grouping the repeated guard statements under a single descriptive error method to keep code DRY and to unify the error response, especially if more presence fields are introduced.
🧹 Nitpick comments (17)
CONTRIBUTING.md (1)
43-43: Minor grammatical improvement neededThere's a small grammatical issue in this line.
- - It is not currently possible to create a `Task`, `CheckedContinuation`, or `AsyncThrowingStream` with a specific error type. You will need to instead return a `Result` and then call its `.get()` method. + - It is not currently possible to create a `Task`, `CheckedContinuation`, or `AsyncThrowingStream` with a specific error type. You will need to instead return a `Result` and then call its `.get()` method.🧰 Tools
🪛 LanguageTool
[uncategorized] ~43-~43: “its” (belonging to it) seems less likely than “it”
Context: ...instead return aResultand then call its.get()method. - `Dictionary.mapVal...(AI_HYDRA_LEO_CPT_ITS_IT)
Sources/AblyChat/Rooms.swift (1)
154-253: Consistent internaldo throws(InternalError)enclosure
By first catching errors asInternalErrorand then converting toARTErrorInfoonly at the API boundary, you ensure more precise error handling logic inside the method. The stepwise approach (guarding existing room state vs. waiting for release) is well-structured, though it’s quite verbose. If the logic expands further, consider extracting subroutines to enhance readability.Sources/AblyChat/Room.swift (1)
232-232: Suggest refined error code for clarity.
While wrapping anARTErrorInfointo anInternalErroris valid, consider using a more descriptive or unique error code than40000for greater clarity.Sources/AblyChat/PaginatedResult.swift (3)
10-12: Consider converting these properties into async/throwing methods.
Definingnext,first, andcurrentas computed properties that areasync throwsis unusual and may reduce clarity, since properties ordinarily imply trivial access. Converting them to methods (e.g.func next() async throws -> (any PaginatedResult<T>)?) can make the asynchronous or error-prone nature more explicit.
25-30: Clarify thenoErrorWithInvalidResponsecase.
Using.failure(PaginatedResultError.noErrorWithInvalidResponse.toInternalError())is fine, but the name can be confusing. Consider naming it something likeinvalidResponseif that is the true meaning.
45-46: Use a common error type or expand this enum.
SincePaginatedResultErrorcurrently contains a single case, you could either rename it to better reflect the scenario (e.g.InvalidResponseError) or consolidate it into an existing error enum if appropriate.Sources/AblyChat/DefaultMessages.swift (2)
117-125: Potential repeated throw in error handling path.
Inside the catch block (lines 117-125), you rethrow the same error after logging it. This is fine, but if you plan to unify error types, consider converting to a single typed error on first throw. Right now, some errors get converted toARTErrorInfowhile others pass through as-is.
160-190: Repeated do/catch code for REST calls.
The methodsget,send,update, anddelete(lines 160-190) follow a repetitive pattern: a do block that callschatAPI.*and throwserror.toARTErrorInfo(). Consider factoring this pattern into a helper function to reduce code duplication.- do { - return try await chatAPI.getMessages(roomId: roomID, params: options) - } catch { - throw error.toARTErrorInfo() - } + return try await convertError { + try await chatAPI.getMessages(roomId: roomID, params: options) + }Sources/AblyChat/ChatAPI.swift (2)
22-26: Consider using a safer conversion for numbers.
The initializer forSendMessageResponse(lines 22-25) forcibly convertscreatedAtusingjsonObject.numberValueForKey("createdAt"). If the server returns a floating value or an unexpected numeric type, it might cause runtime issues. Consider safe-casting or providing a fallback.
134-170: Delete message request with partial body.
deleteMessage(lines 134-170) conditionally addsdescriptionandmetadatato the request body. If a future logic introduces additional optional fields, consider centralizing the body-building logic in a single function. This helps reduce code duplication across message operations.Sources/AblyChat/RoomLifecycleManager.swift (4)
590-600: Avoid indefinite continuation in OperationResultContinuations.
While storing continuations by operation ID is straightforward, carefully handle any edge cases where an operation might complete exceptionally or never complete. If a continuation is never removed, it can lead to memory leaks or indefinite hangs.
655-656: Recommend structured concurrency for waiting logic.
waitForCompletionOfOperationWithIDuses an ad-hoc continuation approach. While valid, consider adopting Swift’s new concurrency patterns (e.g.,AsyncStream) for operation coordination. This can simplify code and reduce the risk of continuation misuse.
865-897: Check for stale references upon detach.
InperformDetachOperation, if the manager is deallocated or the contributor references become stale mid-cycle, you might end up with a partial operation. You do handle repeated detach attempts for non-failed contributors, but ensure no concurrency drift breaks the final state.
1220-1252: Wait logic for presence operations can be canceled.
waitToBeAbleToPerformPresenceOperations(lines 1220-1252) uses subscription to wait for status changes. If the task is canceled, the next status change might never be handled. Consider adding a short-circuit orTask.isCancelledcheck in your loop to avoid waiting indefinitely in canceled tasks.Sources/AblyChat/DefaultPresence.swift (3)
72-97: isUserPresent concurrency approach.
isUserPresentlines 72-97 also callswaitToBeAbleToPerformPresenceOperationsbefore callingchannel.presence.getAsync(...). This is correct, but be sure your concurrency usage doesn’t cause race conditions if presence changes while you’re waiting.
167-199: Leaving presence with typed throws.
leave(optionalData:)(lines 167-199) replicates the same approach asenter. Code duplication is minimal but might be further simplified if you wrap the logic in a shared helper since it’s nearly identical—only the presence action differs.
252-257: Add more descriptive error message.
WhenpresenceDataisnilat line 254, you throw a generic "Received incoming message without data". Improve clarity by specifying that the presence data was unexpectedly nil to help debugging.- let error = ARTErrorInfo.create(withCode: 50000, status: 500, message: "Received incoming message without data") + let error = ARTErrorInfo.create(withCode: 50000, status: 500, message: "Received nil presence data in message")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (42)
CONTRIBUTING.md(1 hunks)Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift(1 hunks)Sources/AblyChat/ChatAPI.swift(7 hunks)Sources/AblyChat/DefaultMessages.swift(7 hunks)Sources/AblyChat/DefaultOccupancy.swift(1 hunks)Sources/AblyChat/DefaultPresence.swift(5 hunks)Sources/AblyChat/DefaultRoomLifecycleContributor.swift(1 hunks)Sources/AblyChat/DefaultRoomReactions.swift(1 hunks)Sources/AblyChat/DefaultTyping.swift(3 hunks)Sources/AblyChat/Errors.swift(4 hunks)Sources/AblyChat/Extensions/Dictionary+Extensions.swift(1 hunks)Sources/AblyChat/Headers.swift(3 hunks)Sources/AblyChat/InternalError.swift(1 hunks)Sources/AblyChat/JSONCodable.swift(22 hunks)Sources/AblyChat/Message.swift(2 hunks)Sources/AblyChat/Messages.swift(6 hunks)Sources/AblyChat/Occupancy.swift(2 hunks)Sources/AblyChat/PaginatedResult.swift(3 hunks)Sources/AblyChat/Presence.swift(7 hunks)Sources/AblyChat/PresenceDataDTO.swift(1 hunks)Sources/AblyChat/Room.swift(4 hunks)Sources/AblyChat/RoomFeature.swift(2 hunks)Sources/AblyChat/RoomLifecycleManager.swift(17 hunks)Sources/AblyChat/RoomReactionDTO.swift(2 hunks)Sources/AblyChat/RoomReactions.swift(1 hunks)Sources/AblyChat/Rooms.swift(6 hunks)Sources/AblyChat/Typing.swift(2 hunks)Tests/AblyChatTests/ChatAPITests.swift(1 hunks)Tests/AblyChatTests/DefaultMessagesTests.swift(3 hunks)Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift(1 hunks)Tests/AblyChatTests/DefaultRoomPresenceTests.swift(6 hunks)Tests/AblyChatTests/DefaultRoomTypingTests.swift(2 hunks)Tests/AblyChatTests/DefaultRoomsTests.swift(2 hunks)Tests/AblyChatTests/Helpers/Helpers.swift(2 hunks)Tests/AblyChatTests/InternalErrorTests.swift(1 hunks)Tests/AblyChatTests/Mocks/MockFeatureChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoom.swift(2 hunks)Tests/AblyChatTests/Mocks/MockRoomFactory.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift(2 hunks)Tests/AblyChatTests/PresenceDataDTOTests.swift(1 hunks)Tests/AblyChatTests/RoomReactionDTOTests.swift(2 hunks)
🧰 Additional context used
🪛 LanguageTool
CONTRIBUTING.md
[uncategorized] ~43-~43: “its” (belonging to it) seems less likely than “it”
Context: ...instead return a Result and then call its .get() method. - `Dictionary.mapVal...
(AI_HYDRA_LEO_CPT_ITS_IT)
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like: do throws(InternalError) { … }. - The compiler will never infer the t...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g. let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: Example app, tvOS (Xcode 16)
- GitHub Check: Example app, iOS (Xcode 16)
- GitHub Check: Example app, macOS (Xcode 16)
- GitHub Check: Xcode, tvOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, tvOS (Xcode 16) - GitHub Check: Xcode, iOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, iOS (Xcode 16) - GitHub Check: Xcode, macOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, macOS (Xcode 16) - GitHub Check: SPM (Xcode 16)
🔇 Additional comments (113)
Sources/AblyChat/PresenceDataDTO.swift (1)
13-13: Appropriate removal of throws keywordThe removal of the
throwskeyword from this initializer simplifies the API since this simple assignment operation doesn't need error propagation. This aligns with the broader effort to standardize error handling across the codebase.Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift (1)
2194-2194: Appropriately broadened error type to accommodate new error handlingChanging the error type from
ARTErrorInfo?toError?correctly adapts the test to the updated error handling mechanism. This allows the test to catch any error type thrown by the implementation, which is necessary since the SDK is standardizing on different error types for different layers.Tests/AblyChatTests/ChatAPITests.swift (1)
23-27: Correctly updated error checking logicThe modification to use pattern matching with
InternalErrorcorrectly adapts the test to the new error handling mechanism. This update properly verifies that errors are now wrapped in theInternalErrortype, which is consistent with the SDK's standardized approach to error handling.Sources/AblyChat/RoomReactions.swift (1)
17-17: Improved API clarity with typed throwsThis change implements the PR objective by specifying that the method throws
ARTErrorInforather than a generic error. This provides better API clarity for users, allowing them to make more informed decisions about error handling, particularly for determining whether operations can be retried based on the error's status code.Tests/AblyChatTests/PresenceDataDTOTests.swift (1)
21-25: Improved error validation pattern.The test now uses a closure pattern to capture and validate the error type using
isInternalErrorWithCase, which is more flexible than directly checking for a specific error type. This aligns with the PR's objective to standardize on typed error handling across the SDK.Sources/AblyChat/DefaultRoomReactions.swift (1)
24-24: Function signature updated to use typed throws.The method now explicitly specifies that it throws
ARTErrorInfoinstead of a generic error, which aligns with the PR objective to standardize error handling in the public API. This change improves API clarity by communicating the exact error type that callers should expect to handle.Sources/AblyChat/Headers.swift (3)
1-2: Added Ably import.Added import for the Ably module, which is likely needed for the error handling modifications in this file.
78-78: Updated initializer to use typed throws.The initializer now explicitly declares that it throws
InternalErrorinstead of a generic error, improving type safety and API clarity.
89-89: Modified error transformation pattern.The error is now converted to an
InternalErrorusing thetoInternalError()extension method before being thrown. This ensures consistency with the updated error handling approach across the SDK.Sources/AblyChat/Errors.swift (4)
215-215: Added new case for handling internal errors without ARTErrorInfo.The new
nonErrorInfoInternalErrorcase allows for representing internal errors that don't have an associatedARTErrorInfo, which enhances the error handling system's flexibility.
228-231: Added error status code handling for internal errors.Internal errors without an
ARTErrorInfoare now treated as non-recoverable user errors with a.badRequeststatus code. This provides a consistent approach to handling these errors in the public API.
314-317: Added localized description for internal errors.The implementation provides a simple string representation of the internal error enum case. This ensures that all errors have descriptive messages for debugging and user feedback.
347-348: Updated error cases without a cause.Added the new
nonErrorInfoInternalErrorcase to the list of errors that don't have an underlying cause, maintaining consistency in the error handling implementation.Sources/AblyChat/Extensions/Dictionary+Extensions.swift (1)
1-8: Good implementation of typed error handling for dictionary transformations.This new utility method
ablyChat_mapValuesWithTypedThrowproperly preserves the error type thrown by the transform function, allowing for more precise error handling compared toDictionary.mapValueswhich usesrethrows.The implementation correctly preserves key uniqueness and propagates the typed error, which aligns with the PR objective of standardizing error types throughout the API.
Tests/AblyChatTests/DefaultRoomTypingTests.swift (2)
83-84: Good use of typed throws syntax for error handling.Changed the
doblock to usedo throws(ARTErrorInfo)to explicitly specify the expected error type. This change removes the need for explicit casting of the error toARTErrorInfolater in the catch block, making the code cleaner while maintaining type safety.This aligns well with the PR objective of standardizing error types across the codebase.
108-109: Consistent application of typed throws pattern.Similar to the previous change, this modification uses
do throws(ARTErrorInfo)to specify the expected error type, ensuring consistent error handling across test methods.This approach follows the typed throws pattern being applied throughout the codebase.
Tests/AblyChatTests/Mocks/MockRoomFactory.swift (1)
16-16: Updated method signature with typed throws to specifyInternalError.Modified the method signature to use
throws(InternalError)instead of genericthrows, which makes the error type explicit. This change supports the PR objective of standardizing error types throughout the codebase.The implementation correctly specifies that the
createRoommethod can throw anInternalError, providing more precise error handling information to callers.Tests/AblyChatTests/RoomReactionDTOTests.swift (3)
10-14: Good update to use structured error handling withisInternalErrorWithCaseThe updated test now properly checks that the error is an
InternalErrorwith the specific case of.jsonValueDecodingError, aligning with the changes made to standardize error types in the library.
19-23: Consistent error verification approachThis follows the same pattern of verifying the specific
InternalErrorcase, maintaining consistency with the other test updates.
73-77: Aligned error handling pattern for Extras testsThe test for
RoomReactionDTO.Extrasnow follows the same structured error verification pattern, creating consistency across all test cases.Tests/AblyChatTests/InternalErrorTests.swift (1)
1-25: Well-structured tests for error conversionThese tests properly validate the two key conversion paths for
InternalErrortoARTErrorInfo:
- When the underlying error is already an
ARTErrorInfo, it should be returned directly- When the underlying error is not an
ARTErrorInfo, it should be properly wrappedThis implementation directly supports the PR objective of standardizing public API errors as
ARTErrorInfoand ensures the conversion mechanism works correctly.Tests/AblyChatTests/DefaultRoomPresenceTests.swift (2)
106-114: Updated to use typed throws in error handlingThe test now explicitly declares the expected error type with
throws(ARTErrorInfo), which aligns with the changes to standardize on typed throws in the public API.
131-138: Consistent error type specification across testsAll error handling blocks have been updated to use
throws(ARTErrorInfo), ensuring consistency across the test suite and properly validating that the functions throw the expected error type.Also applies to: 224-232, 249-256, 329-336, 399-407
Tests/AblyChatTests/Mocks/MockRoom.swift (2)
1-1: Added necessary import for ARTErrorInfoAdded the Ably import which is required for the ARTErrorInfo type used in the method signatures.
47-47: Updated method signatures to use typed throwsThe
attach()anddetach()methods now explicitly specify that they throwARTErrorInfo, aligning with the PR goal of standardizing on typed throws in the public API.Also applies to: 51-51
Sources/AblyChat/DefaultOccupancy.swift (1)
56-62: Method correctly updated to throw ARTErrorInfoThe
get()method has been properly updated to explicitly throwARTErrorInfoinstead of a generic error, aligning with the PR's objective of standardizing error handling. The implementation effectively wraps the original code in a do-catch block and converts any caught errors toARTErrorInfousing thetoARTErrorInfo()method.This change ensures that the error type is consistent with the updated protocol definition and allows clients to access additional error information like
statusCode.Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift (2)
67-78: Properly updatedattach()method to throw InternalErrorThe method signature has been correctly updated to throw
InternalErrorinstead of a generic error. The implementation now properly wraps the call toperformBehavior()in a do-catch block and converts any caught errors toInternalErrorusing thetoInternalError()method.This change maintains consistency with the rest of the codebase's error handling approach.
82-93: Properly updateddetach()method to throw InternalErrorSimilar to the
attach()method, thedetach()method has been correctly updated to throwInternalErrorand includes proper error conversion in the do-catch block.This change is consistent with the error handling approach being implemented across the codebase.
Sources/AblyChat/Occupancy.swift (2)
30-30: Protocol method signature correctly updatedThe
get()method signature in theOccupancyprotocol has been properly updated to explicitly throwARTErrorInfo. This change aligns with the PR objective of standardizing public API error types and matches the implementation inDefaultOccupancy.This change ensures that clients will have access to the error's
statusCodeto help determine if they can retry actions that resulted in errors.
69-69: JSONObjectDecodable initializer correctly updatedThe initializer signature has been properly updated to throw
InternalErrorinstead of a generic error. This change is consistent with the pattern of having internal methods throwInternalErrorwhile public API methods throwARTErrorInfo.This change contributes to the standardization of error types throughout the codebase.
Tests/AblyChatTests/Mocks/MockFeatureChannel.swift (1)
25-34: Mock implementation correctly updated to throw InternalErrorThe
waitToBeAbleToPerformPresenceOperationsmethod has been properly updated to throwInternalErrorinstead ofARTErrorInfo. The implementation now includes a do-catch block that correctly converts any caught errors toInternalErrorusing thetoInternalError()method.This change maintains consistency with the rest of the error handling approach in the codebase and properly reflects the behavior of the interface it's implementing.
CONTRIBUTING.md (2)
37-46: Great addition of error handling guidelinesThe documentation on typed throws is clear and comprehensive, offering valuable guidance on when to use
ARTErrorInfoversusInternalError. The guidelines align well with the PR objective of ensuring consistent error typing.🧰 Tools
🪛 LanguageTool
[uncategorized] ~43-~43: “its” (belonging to it) seems less likely than “it”
Context: ...instead return aResultand then call its.get()method. - `Dictionary.mapVal...(AI_HYDRA_LEO_CPT_ITS_IT)
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like:do throws(InternalError) { … }. - The compiler will never infer the t...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g.let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...(UNLIKELY_OPENING_PUNCTUATION)
45-46: Documentation clearly explains Swift typing inference limitationsThe explanation of error type inference limitations in
doblocks and closures is excellent. It will help developers understand why they need to explicitly specify error types in certain scenarios.🧰 Tools
🪛 LanguageTool
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like:do throws(InternalError) { … }. - The compiler will never infer the t...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g.let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...(UNLIKELY_OPENING_PUNCTUATION)
Sources/AblyChat/DefaultRoomLifecycleContributor.swift (2)
37-39: Updated error type aligns with internal error handling strategyChanging from
throws(ARTErrorInfo)tothrows(InternalError)correctly implements the internal error handling strategy outlined in the contributing guidelines, whereInternalErroris used internally and converted toARTErrorInfoat the public API boundary.
41-43: Updated error type aligns with internal error handling strategySimilarly, updating the detach method to throw
InternalErrormaintains consistency with the internal error handling approach.Tests/AblyChatTests/Helpers/Helpers.swift (4)
5-18: Improved error checking logic for test helpersThe updated implementation correctly checks for both direct
ARTErrorInfoerrors andInternalErrorinstances that wrapARTErrorInfo. This enhancement aligns with the new error handling strategy and improves test reliability.
35-41: Helpful utility function for internal error testingThis new helper function provides a clean way to verify when an
InternalErroris wrapping a specificARTErrorInfo, which will be useful for testing the error conversion logic mentioned in the contributing guidelines.
43-66: Well-structured error case enumerationThe addition of the
Caseenum provides a clear categorization of internal error types, making tests more readable and maintainable. TheenumCaseproperty offers a convenient way to check error types without complex pattern matching.
68-74: Useful utility for case-based error testingThis function complements the enumeration by providing a simple way to check if an error is of a specific case type, which will streamline test assertions.
Sources/AblyChat/Typing.swift (3)
30-30: Public API now uses typed throws with ARTErrorInfoThe change to
throws(ARTErrorInfo)correctly implements the requirements specified in the contributing guidelines, ensuring that the public API uses typed throws withARTErrorInfoas the error type.
42-42: Public API now uses typed throws with ARTErrorInfoThe
start()method now correctly specifiesARTErrorInfoas its thrown error type, aligning with the PR objective.
50-50: Public API now uses typed throws with ARTErrorInfoThe
stop()method now correctly specifiesARTErrorInfoas its thrown error type, aligning with the PR objective.Sources/AblyChat/RoomReactionDTO.swift (2)
43-43: Good use of typed throwsThe initializer now explicitly declares that it throws
InternalError, which aligns with the PR objective to make error handling more specific and consistent across the codebase.
61-64: Improved error handling with typed throwsThe implementation now uses
ablyChat_mapValuesWithTypedThrowto explicitly handle potential errors with theInternalErrortype during JSON parsing. This is a good pattern that increases type safety and makes error handling more predictable.Tests/AblyChatTests/DefaultMessagesTests.swift (3)
61-67: Temporary workaround for compiler crashThe TODO comment explains that this is a temporary solution to work around a compiler crash. Make sure to track issue #233 so this code can be reverted once Xcode 16.3 is released.
Could you confirm if there's a plan to monitor the release of Xcode 16.3 so these workarounds can be removed promptly?
273-277: Improved error validation approachThe test now uses a more specific validation for the thrown error, checking if it's an
InternalErrorwrapping anARTErrorInfo. This aligns with the PR objective to ensure proper error types are thrown from the API.
318-324:Details
✅ Verification successful
Same compiler crash workaround
This is the same workaround pattern as seen earlier in the file. The implementation maintains the test's intent while working around the compiler limitation.
🏁 Script executed:
#!/bin/bash # Check if there are other instances of this workaround pattern that might need to be reverted later rg --type swift "TODO: avoids compiler crash.*revert once Xcode 16\.3 released" -B 1 -A 5Length of output: 2579
Compiler Crash Workaround Validated Across Test Files
The workaround pattern in the tests (as seen in both DefaultMessagesTests.swift and DefaultRoomsTests.swift) consistently applies the necessary temporary fix for the Xcode compiler crash. The tests preserve their intended behavior, and the pattern is uniformly applied. Please ensure that when Xcode 16.3 is released, these workarounds are reverted as noted in the TODO comments.
Sources/AblyChat/RoomFeature.swift (2)
73-73: Implementation correctly updatedThe implementation in
DefaultFeatureChannelhas been properly updated to match the protocol change, maintaining consistency in error handling.
61-61:Details
✅ Verification successful
Protocol method now throws InternalError
The method signature has been updated to throw
InternalErrorinstead ofARTErrorInfo. This aligns with the PR objective but make sure all implementers of this protocol have been updated accordingly.
🏁 Script executed:
#!/bin/bash # Check for implementations of waitToBeAbleToPerformPresenceOperations to ensure they've been updated rg --type swift "func waitToBeAbleToPerformPresenceOperations.*\(" -A 1Length of output: 2928
Verified: Protocol Method Signature Update Confirmed
The change to throw
InternalErrorinstead ofARTErrorInfohas been successfully propagated. All relevant implementations (including those in Sources and Tests) are updated accordingly:
- Sources/AblyChat/RoomFeature.swift – Signature now correctly uses
InternalError.- Sources/AblyChat/RoomLifecycleManager.swift – Updated signature in both protocol and its internal implementation.
- Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift and MockFeatureChannel.swift – Mocks now reflect the updated method signature.
- Additional tests in DefaultRoomLifecycleManagerTests.swift confirm consistent usage across scenarios.
No further changes are required.
Sources/AblyChat/Message.swift (3)
155-155: Good use of typed throwsThe initializer now explicitly declares that it throws
InternalError, which aligns with the PR objective to make error handling more specific.
165-167: Improved error handling with typed throwsThe implementation now uses
ablyChat_mapValuesWithTypedThrowto handle errors with the specificInternalErrortype when parsing JSON values. This improves type safety and error handling predictability.
170-170: Consistent typed throws in operation mappingThe operation mapping closure now explicitly throws
InternalError, maintaining consistency with the other error handling improvements in this file.Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift (2)
19-29: Good use of typed throws inperformAttachOperation
The typed throws withInternalErrorcleanly encapsulate internal Ably errors (ARTErrorInfo). The logic for rethrowing viaerror.toInternalError()aligns well with the new error handling approach.
31-41: ConsistentInternalErrorusage inperformDetachOperation
This method follows the same pattern asperformAttachOperation, ensuring uniform error propagation.Sources/AblyChat/InternalError.swift (3)
1-16: Well-structured definition ofInternalError
Defining a dedicated internal error enum reduces ambiguity and provides a clear mapping fromARTErrorInfoto internal and public-facing errors.
17-31:toARTErrorInfo()andmessageproperty provide smooth error translation
These functions uniformly translate internal errors intoARTErrorInfoand facilitate consistent logging. Good clarity in bridging internal and external error layers.
33-61: Extensions streamline conversions toInternalError
Each extension method clearly wraps domain-specific error types for unified handling. This modular approach helps maintain consistency as the SDK evolves.Sources/AblyChat/Rooms.swift (5)
28-28: Typed throws onget(...): async throws(ARTErrorInfo)
ExposingARTErrorInfoat the public API boundary meets the PR objective to consistently throw typed Ably errors.
256-260: Clear final conversion toARTErrorInfo
CatchingInternalErrorand rethrowing asARTErrorInfosatisfies the typed error requirement. Good job ensuring that bridging logic is at the end.
263-283: Helper functions for creation-failure signaling
ThemakeCreationFailureFunctionsapproach is creative, providing structured ways to inject errors into in-flight async tasks. This design is flexible, though it’s somewhat intricate. Consider adding unit tests that ensure all code paths for success/failure are covered.Would you like a sample test snippet or script to verify coverage of these code paths?
294-299:createRoom(...)modernization
Shifting toasync throws(InternalError)is consistent with the rest of the refactor. The method body is straightforward and easy to follow.
335-335: Graceful logging for release-induced failure
Transforming the “room released” scenario into anInternalErrorclarifies the reason for creation failure. Adequate debug logs help with diagnosis.Sources/AblyChat/Room.swift (7)
91-91: Public API typed throws alignment looks good.
The newfunc attach() async throws(ARTErrorInfo)signature aligns well with the PR objective of exposingARTErrorInfofrom the public API.
98-98: Consistent typed throws for detaching.
Thefunc detach() async throws(ARTErrorInfo)signature is consistent with the typed-throw approach used inattach().
142-142: Internal error type usage is acceptable.
UsingInternalErrorincreateRoomat an internal protocol level is fine, as these errors are not directly exposed through the public interface.
148-148: Continuation of internal error typing.
This factory method’sasync throws(InternalError)signature is consistent with the rest of the internal error handling approach.
224-224: Initialization error handling.
The constructor’sasync throws(InternalError)signature cleanly distinguishes internal errors duringDefaultRoomcreation.
397-402: Rethrowing asARTErrorInfois correct.
Thisattach()implementation properly catches lower-level errors and rethrows them asARTErrorInfo, matching the public API contract.
405-410: Consistent detach code.
Similar toattach(), thedetach()method correctly wraps and rethrows errors asARTErrorInfo.Sources/AblyChat/Messages.swift (7)
18-18: Typed throws forsubscribe(bufferingPolicy:).
Changing the signature toasync throws(ARTErrorInfo)is consistent with the new approach of exposingARTErrorInfoat the public API level.
23-23: Additive typed throws in defaultsubscribe().
ExposingARTErrorInfohere as well ensures consistency with the buffering-policy overload.
33-33: Query method error type.
Enablingget(options:)to throwARTErrorInfoclarifies error details for message history retrieval.
47-47: Enhanced error detail for sending messages.
UsingARTErrorInfoinsend(params:)improves transparency around send-failure causes.
63-63: Specific typed throw for message updates.
update(newMessage:description:metadata:)now explicitly throwingARTErrorInfomatches the broader error-handling improvements.
78-78: Explicit error type for message deletion.
delete(message:params:)adoptingARTErrorInfoconsistently completes the suite of typed throws for message operations.
89-89: Unified subscription convenience.
The defaultsubscribe()method’sasync throws(ARTErrorInfo)complements the buffering-policy-based overload cleanly.Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift (9)
6-29: Bridge from callback-based requests to Swift concurrency.
The internalrequestAsyncmethod elegantly wraps the callback inwithCheckedContinuation, properly rethrowing errors asInternalError.
32-46: Asynchronous attach extension.
attachAsync()correctly maps the callback-based attach flow to async/await, rethrowingARTErrorInfoasInternalErrorfor internal usage.
48-62: Asynchronous detach extension.
detachAsync()follows the same pattern asattachAsync(), ensuring consistent error wrapping.
65-72: Concurrent-safe presence message struct.
DefiningPresenceMessageseparately with only required fields is a clean, sendable-friendly approach.
74-85: Initializer bridging toPresenceMessage.
Reading fields fromARTPresenceMessageand converting them toPresenceMessageis straightforward and correct.
88-105: Fetching presence members asynchronously.
getAsync()properly wraps presence retrieval in an async/await continuation, then rethrows asInternalError.
107-123: Query-based presence fetch.
Similarly,getAsync(_ query:)is well-implemented, parallelinggetAsync()to retrieve presence with typed error handling.
125-139: Asynchronous presence leave.
leaveAsync(_:)bridging from callbacks to async is consistent, ensuring typedInternalErrorfrom underlyingARTErrorInfo.
141-155: Client-specific presence entry.
enterClientAsyncparallelsleaveAsync, maintaining consistency when bridging the callback flow.Sources/AblyChat/PaginatedResult.swift (3)
19-19: Good use of typedResultwith continuations.
Switching toCheckedContinuation<Result<PaginatedResultWrapper<Response>, InternalError>, Never>clarifies success/failure scenarios and aligns with typed error handling.
98-100: LGTM: Extension for conversion is well-structured.
The helper methodtoPaginatedResult(items:)cleanly encapsulates logic for converting low-level responses into a typed wrapper.
36-36:Details
✅ Verification successful
Validate Swift language version for advanced closure throws syntax.
try jsonValues.map { jsonValue throws(InternalError) in … }is valid in newer Swift versions; confirm that your minimum deployment environment supports this feature. Otherwise, you may need to map errors within a standarddo … catchblock.
🏁 Script executed:
#!/bin/bash # Searching for Swift language version constraints in the project files rg -A 3 "SWIFT_VERSION|swift-tools-version"Length of output: 1770
Swift Language Version Confirmed
The project is correctly configured to use Swift 6.0 (as seen in both
Package.swiftand the Xcode project settings). This version supports the advanced closurethrows(InternalError)syntax, so no changes are required.
- Confirmed in
Package.swift:// swift-tools-version: 6.0- Confirmed in
Example/AblyChatExample.xcodeproj:SWIFT_VERSION = 6.0Sources/AblyChat/DefaultTyping.swift (3)
122-161: Typed error conversion boundary is consistent.
WrappingInternalErrorwithin ado throws(InternalError)block and converting it toARTErrorInfoexternally ensures the public API consistently exposesARTErrorInfo. This design is aligned well with typed error handling.
164-191: Stop method concurrency approach looks consistent.
The concurrency approach forstop()uses the same pattern asstart(). No major concerns unless multiple actors callstop()simultaneously, which your concurrency strategy may already handle.
198-210: Good approach to refiningprocessPresenceGet.
This helper ensures each member has aclientId. Throwing anInternalErroras soon as one is missing is a clean fail-fast mechanism.Sources/AblyChat/Presence.swift (1)
15-15: Consistent usage ofARTErrorInfoin public methods.
All these methods now throwARTErrorInfo, which aligns with the newly standardized typed throws approach. This improves error specificity and consistency throughout the presence API.Also applies to: 27-27, 39-39, 49-49, 59-59, 69-69, 99-99, 107-107, 115-115
Sources/AblyChat/DefaultMessages.swift (3)
261-280: Clarify distinction between InternalError vs. ARTErrorInfo.
InresolveSubscriptionStart(...)(line 261) andserialOnChannelAttach(...)(line 280), you switch from throwingInternalErrortoARTErrorInfoin some places. This is consistent with the rest of the typed-throws approach, but ensure all code paths use the final error type the caller expects. Thoroughly test edge cases (e.g., missingchannelSerial) to confirm.
295-335: Check concurrency safety of withCheckedContinuation usage.
ThewithCheckedContinuationcall (lines 295-335) properly resumes the continuation only once. However, if multiple channel events arrive in quick succession, ensure there's no race that might resume or mutatenillableContinuationprematurely. Consider usingactor-isolatedorasyncstreams to handle potential concurrency complexities.
60-69:Details
✅ Verification successful
Handle concurrency within Task blocks carefully.
When subscribing to realtime messages (lines 60-69), each message callback spawns aTaskthat performs multiple checks and can throwARTErrorInfo. This is correct usage of Swift concurrency, but be mindful that ifselfis deallocated or ifchannelis detached mid-callback, subsequent calls (likemessage.extras) could fail. Consider adding defensive checks if needed.Do you want to verify if the object remains valid throughout the entire
Tasklifecycle? You could run a quick script to grep for possible mid-callback references:
🏁 Script executed:
#!/bin/bash rg -A 5 "Task {"Length of output: 94
Ensure Task Block’s Object Validity Remains Intact
In the realtime message subscription (lines 60–69 ofSources/AblyChat/DefaultMessages.swift), the usage ofTask { … }follows Swift concurrency patterns and is acceptable. However, please verify that any objects referenced within the Task’s closure—such asselforchannel—are still valid for the entire Task lifecycle. This is important because if, for example,selfis deallocated or the channel is detached before the Task completes, subsequent property accesses (likemessage.extras, if they occur) might fail. Consider adding defensive checks (or adjusting capture semantics, such as using[weak self]) if these objects’ lifetimes are uncertain.
🏁 Script executed:
#!/bin/bash # Use fixed-string search to avoid regex errors when looking for "Task {" in the file rg -F -A 5 "Task {" Sources/AblyChat/DefaultMessages.swiftLength of output: 1284
Concurrency Handling Validated: No Further Changes Needed
The verification shows that the Task blocks in
Sources/AblyChat/DefaultMessages.swiftare using Swift concurrency correctly. In the realtime message subscription block (lines 60–69), there isn’t an unnecessary capture ofself—and whereselfis needed (such as within the MainActor block or during attachment handling), the code already leverages[weak self]or optional chaining. This defensive approach adequately prevents issues due to object deallocation or detached channels during the Task’s lifecycle.
- Realtime message subscription Task: Does not capture
selfunnecessarily.- Subsequent Task blocks: Correctly use
[weak self]and safe optional chaining when referencing instance members.- General recommendation: Continue monitoring if new references are added mid-callback, but no changes are required at this time.
Sources/AblyChat/ChatAPI.swift (3)
13-16: Ensure paginated request usage is correct.
getMessages(lines 13-16) now returns a typedany PaginatedResult<Message>withthrows(InternalError). Verify all call sites handleInternalErrorproperly and confirm that your unwrapped JSON decoding doesn’t miss potential edge cases.
43-78: Consistent error transformation for ‘sendMessage’.
sendMessagenow throwsInternalErrorifclientIdis nil or a network error occurs. This is good for typed error consistency. Just ensure that the top-level code usingsendMessagecan handleInternalErroruniformly. No issues found with concurrency.
172-205: makePaginatedRequest concurrency check.
makePaginatedRequest(lines 195-205) usesrequestAsyncinternally. This approach looks sound. Verify concurrency usage, especially if other tasks cancel or alter therealtimereference. Ensure therealtime.requestAsynccall doesn’t get canceled mid-pipeline.Sources/AblyChat/RoomLifecycleManager.swift (4)
44-50: Typed errors in lifecycle operations.
performAttachOperationandperformDetachOperationnow throwInternalError. This ensures alignment with typed error handling. Double-check that calling code properly awaits or handles these operations, as they can fail at runtime.
746-759: Handle potential race conditions around status changes.
InperformAttachOperation(lines 746-759), if the channel state changes again while you wait, ensure you don’t incorrectly override or skip states. You do partial checks withstatus.operationID. Just confirm that concurrency or reentrancy can’t cause you to lose an important update.
790-817: Graceful fallback for suspended or failed states.
InsideperformAttachmentCycle, suspended or failed states cause immediate exit from the loop with subsequent scheduling of a retry or rundown operation (lines 805-817). This design makes sense. Validate that any ephemeral state changes incontributorStateafter the error are safe to ignore.
971-972: Retain original error context when rethrowing.
After the detach loop, an error is rethrown at lines 971-972 usingfirstDetachError.toInternalError(). That preserves typed error consistency. Confirm the original error’s message and cause remain visible to end users.Sources/AblyChat/DefaultPresence.swift (4)
22-45: Unified typed throws for ‘get()’.
Yourget()function lines 22-45 now usesthrows(ARTErrorInfo)externally while converting internal errors toInternalErrorfirst. This is consistent but watch for any new internal error types that never get converted toARTErrorInfo, e.g.,PresenceDataDTOdecoding errors.
107-130: Converting presence operation errors.
Forenter(optionalData:)(lines 107-130), you correctly catch any errors and rethrow them via.toARTErrorInfo(). This matches the typed throw approach. No immediate concerns, but continued coverage in tests will help ensure it’s robust.
142-165: Updating presence with fallback data.
Inupdate(optionalData:)(lines 142-165), you build aPresenceDataDTOand then callpresence.updateAsync. Ifdatais nil, you pass an empty object. Confirm with product owners whether passing no data or an empty object is the intended default.
297-321: Prevent partial data in presence subscription events.
processPresenceSubscribe(lines 297-321) again decodes presence data. IfclientIdortimestampis missing, you throw an error. This is consistent. Ensure that your documentation clarifies possible behaviors to library consumers if partial presence data arrives from unexpected sources.Sources/AblyChat/JSONCodable.swift (7)
9-9: Good update to the protocol method signaturesChanging the
init(jsonValue:)method to explicitly throwInternalErrorinstead of a generic error aligns well with the PR objective of standardizing error types. This provides more type safety and clearer error contracts.
26-26: Consistent error type specificationThe update to
init(jsonObject:)to throwInternalErrorspecifically maintains consistency with other method signatures in this file. This is a good practice for API clarity.
38-41: Good error handling implementationConverting
JSONValueDecodingErrortoInternalErrorusing thetoInternalError()method ensures consistent error types are propagated through the public API. This aligns with the PR objectives to standardize error handling.
58-68: Appropriate method signature updateThe update to the
objectValueForKeymethod signature ensures consistent error handling. The implementation correctly usestoInternalError()to convert domain-specific errors to the standardInternalErrortype.
73-87: Consistent error handling in optional methodsThe error handling in
optionalObjectValueForKeyhas been appropriately updated. The method now explicitly throwsInternalErrorand usestoInternalError()for error conversion, maintaining consistency with the non-optional variant.
275-279: Good error handling for RawRepresentable valuesThe
RawRepresentablehandling methods have been properly updated to throwInternalErrorwith consistent error conversion. This includes both the public methods and the private implementation method, which is thorough and maintains consistency.Also applies to: 286-292, 294-300
1-301: Overall consistent implementation of the error handling strategyAll method signatures and error handling code have been consistently updated to use
InternalErrorinstead of generic errors. This systematic approach ensures a uniform error handling experience across the API, which aligns perfectly with the PR objectives of standardizing errors for better usability.The changes also enable users to access specific error information like
statusCode(as mentioned in the PR objectives) by propagating the more specific error type. This is a significant improvement for API consumers who need to make informed decisions about error recovery.
dba13ae to
1dfa781
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (14)
Tests/AblyChatTests/InternalErrorTests.swift (1)
16-16: Consider consistent naming pattern for test methodsThe first test method is named
toARTErrorInfo_whenUnderlyingErrorIsARTErrorInfo, while this one has atestprefix:testToARTErrorInfo_whenUnderlyingErrorIsNotARTErrorInfo. For consistency, consider removing thetestprefix.- func testToARTErrorInfo_whenUnderlyingErrorIsNotARTErrorInfo() { + func toARTErrorInfo_whenUnderlyingErrorIsNotARTErrorInfo() {CONTRIBUTING.md (2)
43-43: Minor grammar correction in documentation- - It is not currently possible to create a `Task`, `CheckedContinuation`, or `AsyncThrowingStream` with a specific error type. You will need to instead return a `Result` and then call its `.get()` method. + - It is not currently possible to create a `Task`, `CheckedContinuation`, or `AsyncThrowingStream` with a specific error type. You will need to instead return a `Result` and then call its `.get()` method.The possessive "its" is correct here, referring to the
Result's.get()method.🧰 Tools
🪛 LanguageTool
[uncategorized] ~43-~43: “its” (belonging to it) seems less likely than “it”
Context: ...instead return aResultand then call its.get()method. - `Dictionary.mapVal...(AI_HYDRA_LEO_CPT_ITS_IT)
45-46: Consider improving punctuation in code examplesThere are loose punctuation marks before the code examples. Consider standardizing the approach to introducing code examples throughout the documentation.
- - There are times when the compiler struggles to infer the type of the error thrown within a `do` block. In these cases, you can disable type inference for a `do` block and explicitly specify the type of the thrown error, like: `do throws(InternalError) { … }`. - - The compiler will never infer the type of the error thrown by a closure; you will need to specify this yourself; e.g. `let items = try jsonValues.map { jsonValue throws(InternalError) in … }`. + - There are times when the compiler struggles to infer the type of the error thrown within a `do` block. In these cases, you can disable type inference for a `do` block and explicitly specify the type of the thrown error, like `do throws(InternalError) { … }`. + - The compiler will never infer the type of the error thrown by a closure; you will need to specify this yourself, e.g., `let items = try jsonValues.map { jsonValue throws(InternalError) in … }`.🧰 Tools
🪛 LanguageTool
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like:do throws(InternalError) { … }. - The compiler will never infer the t...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g.let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...(UNLIKELY_OPENING_PUNCTUATION)
Tests/AblyChatTests/Helpers/Helpers.swift (1)
43-66: Evaluate naming clarity for the nestedCaseenum.
The nested enumCaseclarifies high-level error categories, which is good for typed error handling. However, consider giving it a more descriptive name (e.g.,InternalErrorType) if you expect to expand it significantly.Sources/AblyChat/InternalError.swift (3)
3-31: Ensure completeness ofInternalErrorconversions.
The layout of.errorInfo(ARTErrorInfo)and.other(Other)is straightforward. If you plan on adding further specialized cases (beyondOther), confirm you won’t lose vital metadata if you rely ontoARTErrorInfo()for external usage.
45-49: Minimal overhead withHeadersValue.JSONDecodingErrorbridging.
This extension is straightforward. If you plan to add more detail (e.g., original JSON snippet) to the error, consider augmenting theother(...)payload for richer debugging.
51-55: Maintain consistent error detail.
JSONValueDecodingErroris mapped similarly toheadersValueJSONDecodingError, which is good for uniformity. Consider standardizing error messages across these two for logs if they differ significantly in internal usage.Sources/AblyChat/Rooms.swift (4)
104-108: Check concurrency race conditions inwaitForRoom().
AwaitingcreationTask.valueis done in an actor, which is good. Be mindful of external cancellations (e.g., a user callingrelease(roomID:)), ensuring the canceled states are properly handled.
166-181: Appropriate fallback towaitForRoom.
Your fallback logic clarifies waiting on the existing map entry if the entry is already present. The debug logs are helpful. Consider adding a short doc snippet explaining the concurrency rationale for future maintainers.
263-283: Effective approach to manage creation failure signals.
The usage ofAsyncStream<Result<Void, InternalError>>is a neat pattern to unify a fail signal and normal release completion. Recommend adding stress tests to confirm that multiple signals or cancellations don’t cause unexpected behaviors.
335-336: Use descriptive error on forced release.
Failing creation with a.roomReleasedBeforeOperationCompletedmessage is helpful. If you see repeated confusion in user logs, consider adding more context about which room and operation triggered the release.Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift (1)
6-28: Ensure consistency of error handling and consider avoidingfatalError.
Although usingfatalError(line 22) to handle programmer errors aligns with the current design comments, you could replace it with a custom assertion or descriptive error throw that gracefully fails without abruptly terminating. This helps maintain stability in environments where unexpected runtime termination is undesirable.- fatalError("ably-cocoa request threw an error - this indicates a programmer error") + assertionFailure("ably-cocoa request encountered an unexpected error; please check usage.") + throw InternalError(description: "Programmer error in AblyCocoa request")Sources/AblyChat/DefaultPresence.swift (1)
211-211: Catch thrown errors during subscription callbacks.
In both subscription callbacks (lines 211 & 230), ifprocessPresenceSubscribethrows, theTaskwill silently fail. Consider wrapping withdo-catchand logging or accommodating user-facing error handling for more graceful fallback.Task { - let presenceEvent = try processPresenceSubscribe(...) - subscription.emit(presenceEvent) + do { + let presenceEvent = try processPresenceSubscribe(...) + subscription.emit(presenceEvent) + } catch { + logger.log(message: "Error subscribing: \(error)", level: .error) + } }Also applies to: 230-230
Sources/AblyChat/RoomLifecycleManager.swift (1)
758-759:_performAttachOperationandperformAttachmentCycle: watch concurrency states.
The code checks for in-progress operations and usesstatus.operationIDto coordinate concurrency. Ensure all transitions remain atomic if anything else tries to modifystatussimultaneously (e.g., from other actor tasks).Also applies to: 764-785, 791-791
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)
📒 Files selected for processing (42)
CONTRIBUTING.md(1 hunks)Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift(1 hunks)Sources/AblyChat/ChatAPI.swift(7 hunks)Sources/AblyChat/DefaultMessages.swift(7 hunks)Sources/AblyChat/DefaultOccupancy.swift(1 hunks)Sources/AblyChat/DefaultPresence.swift(5 hunks)Sources/AblyChat/DefaultRoomLifecycleContributor.swift(1 hunks)Sources/AblyChat/DefaultRoomReactions.swift(1 hunks)Sources/AblyChat/DefaultTyping.swift(3 hunks)Sources/AblyChat/Errors.swift(4 hunks)Sources/AblyChat/Extensions/Dictionary+Extensions.swift(1 hunks)Sources/AblyChat/Headers.swift(3 hunks)Sources/AblyChat/InternalError.swift(1 hunks)Sources/AblyChat/JSONCodable.swift(22 hunks)Sources/AblyChat/Message.swift(2 hunks)Sources/AblyChat/Messages.swift(6 hunks)Sources/AblyChat/Occupancy.swift(2 hunks)Sources/AblyChat/PaginatedResult.swift(3 hunks)Sources/AblyChat/Presence.swift(7 hunks)Sources/AblyChat/PresenceDataDTO.swift(1 hunks)Sources/AblyChat/Room.swift(4 hunks)Sources/AblyChat/RoomFeature.swift(2 hunks)Sources/AblyChat/RoomLifecycleManager.swift(17 hunks)Sources/AblyChat/RoomReactionDTO.swift(2 hunks)Sources/AblyChat/RoomReactions.swift(1 hunks)Sources/AblyChat/Rooms.swift(6 hunks)Sources/AblyChat/Typing.swift(2 hunks)Tests/AblyChatTests/ChatAPITests.swift(1 hunks)Tests/AblyChatTests/DefaultMessagesTests.swift(3 hunks)Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift(1 hunks)Tests/AblyChatTests/DefaultRoomPresenceTests.swift(6 hunks)Tests/AblyChatTests/DefaultRoomTypingTests.swift(2 hunks)Tests/AblyChatTests/DefaultRoomsTests.swift(2 hunks)Tests/AblyChatTests/Helpers/Helpers.swift(2 hunks)Tests/AblyChatTests/InternalErrorTests.swift(1 hunks)Tests/AblyChatTests/Mocks/MockFeatureChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoom.swift(2 hunks)Tests/AblyChatTests/Mocks/MockRoomFactory.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift(2 hunks)Tests/AblyChatTests/PresenceDataDTOTests.swift(1 hunks)Tests/AblyChatTests/RoomReactionDTOTests.swift(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (31)
- Sources/AblyChat/DefaultRoomReactions.swift
- Tests/AblyChatTests/ChatAPITests.swift
- Sources/AblyChat/PresenceDataDTO.swift
- Tests/AblyChatTests/PresenceDataDTOTests.swift
- Tests/AblyChatTests/DefaultRoomsTests.swift
- Tests/AblyChatTests/RoomReactionDTOTests.swift
- Sources/AblyChat/Errors.swift
- Tests/AblyChatTests/DefaultRoomPresenceTests.swift
- Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift
- Sources/AblyChat/Headers.swift
- Sources/AblyChat/Extensions/Dictionary+Extensions.swift
- Sources/AblyChat/DefaultOccupancy.swift
- Sources/AblyChat/RoomReactions.swift
- Tests/AblyChatTests/DefaultMessagesTests.swift
- Tests/AblyChatTests/DefaultRoomTypingTests.swift
- Sources/AblyChat/RoomReactionDTO.swift
- Tests/AblyChatTests/Mocks/MockRoomFactory.swift
- Sources/AblyChat/DefaultRoomLifecycleContributor.swift
- Sources/AblyChat/RoomFeature.swift
- Sources/AblyChat/Message.swift
- Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift
- Sources/AblyChat/Typing.swift
- Tests/AblyChatTests/Mocks/MockRoom.swift
- Sources/AblyChat/Occupancy.swift
- Sources/AblyChat/DefaultMessages.swift
- Sources/AblyChat/Messages.swift
- Sources/AblyChat/Room.swift
- Sources/AblyChat/DefaultTyping.swift
- Sources/AblyChat/ChatAPI.swift
- Sources/AblyChat/Presence.swift
- Sources/AblyChat/PaginatedResult.swift
🧰 Additional context used
🪛 LanguageTool
CONTRIBUTING.md
[uncategorized] ~43-~43: “its” (belonging to it) seems less likely than “it”
Context: ...instead return a Result and then call its .get() method. - `Dictionary.mapVal...
(AI_HYDRA_LEO_CPT_ITS_IT)
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like: do throws(InternalError) { … }. - The compiler will never infer the t...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g. let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (10)
- GitHub Check: Example app, tvOS (Xcode 16)
- GitHub Check: Example app, iOS (Xcode 16)
- GitHub Check: Example app, macOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, tvOS (Xcode 16) - GitHub Check: Xcode, tvOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, iOS (Xcode 16) - GitHub Check: SPM (Xcode 16)
- GitHub Check: Xcode, iOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, macOS (Xcode 16) - GitHub Check: Xcode, macOS (Xcode 16)
🔇 Additional comments (34)
Tests/AblyChatTests/InternalErrorTests.swift (1)
1-24: Good test coverage for InternalError to ARTErrorInfo conversionThe tests effectively verify both scenarios:
- When the underlying error is already ARTErrorInfo
- When the underlying error is a different error type
These tests align perfectly with the PR objective of ensuring the public API throws ARTErrorInfo consistently.
Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift (2)
67-80: Appropriate error handling in attach methodThe method now throws
InternalErrorinstead ofARTErrorInfoand properly converts any caught errors usingtoInternalError(). This aligns with the PR objective of standardizing error types.
82-95: Appropriate error handling in detach methodSimilar to the attach method, this implementation properly converts errors to
InternalErrorand maintains consistency with the error handling approach.Tests/AblyChatTests/Mocks/MockFeatureChannel.swift (1)
25-35: Appropriate error handling in waitToBeAbleToPerformPresenceOperations methodThe method has been updated to throw
InternalErrorinstead ofARTErrorInfoand properly converts errors using thetoInternalError()method. This implementation aligns with the PR objective of standardizing error types throughout the codebase.CONTRIBUTING.md (1)
35-47: Excellent documentation on error handling approachThe new section provides comprehensive guidance on typed throws in the SDK, clearly explaining:
- The use of
ARTErrorInfoin the public API- The use of
InternalErrorinternally- Swift's limitations with typed throws
- Workarounds for common scenarios
This documentation will be valuable for current and future contributors to understand the error handling approach.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~43-~43: “its” (belonging to it) seems less likely than “it”
Context: ...instead return aResultand then call its.get()method. - `Dictionary.mapVal...(AI_HYDRA_LEO_CPT_ITS_IT)
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like:do throws(InternalError) { … }. - The compiler will never infer the t...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g.let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...(UNLIKELY_OPENING_PUNCTUATION)
Tests/AblyChatTests/Helpers/Helpers.swift (3)
5-18: Confirm consistency in error checks.
The updated logic conditionally castsmaybeErrorto bothARTErrorInfoandInternalErrorto detect a chat error. Ensure that callsites handle both rawARTErrorInfoand wrappedInternalErrorconsistently. Also, verifying test coverage forisChatErrorwith both error forms would be beneficial.Do you already have tests that pass in an
InternalError.errorInfo(...)? If not, here's a recommended approach to add them for completeness.
35-41: ValidateisInternalErrorWrappingErrorInfousage.
This helper is concise and appears correct. However, ensure all references where anInternalErrormight embed non-matchingARTErrorInfo(e.g., different code or domain) are tested. Otherwise, you risk false positives if anARTErrorInfois unexpectedly equal.
68-75: Additional coverage forisInternalErrorWithCase.
This function elegantly checks whether an error matches a specific internal error case. Consider augmenting test scenarios that pass in other error instances, verifying it returnsfalsefor non-matching types.Sources/AblyChat/InternalError.swift (3)
33-37: Good extension for bridgingARTErrorInfotoInternalError.
This simple conversion accurately wraps externalARTErrorInfo. Ensure that places converting fromARTErrorInfofollow up with an appropriate typed error check if additional context is needed.
39-43: Verify coverage forChatAPI.ChatErrorconversion.
It’s beneficial thatChatAPI.ChatErrorcan now map toInternalError. Confirm that each variant ofChatAPI.ChatErrorhas an appropriate integration test to ensure the bridging logic is exercised.
57-61: ValidatePaginatedResultErrorpath.
MappingPaginatedResultErrorto an.other(.paginatedResultError)maintains type safety. If you discover any confusion around pagination or partial fetch errors, consider adding more explicit error codes or messages to facilitate debugging.Sources/AblyChat/Rooms.swift (6)
28-28: Typed throws provides clarity.
Changingget(roomID:options:)to throw(ARTErrorInfo)explicitly conveys runtime error types, which is a good step toward safer Swift API design. Ensure your documentation highlights this typed-throw contract.
86-89: Ensure creation task lifecycle is well-defined.
ThecreationTaskstoringResult<RoomFactory.Room, InternalError>is helpful for concurrency. Confirm that thefailCreationclosure is consistently invoked to avoid leaving any tasks hanging.
154-164: Validate mismatch logic for room options.
The new check that throws aninconsistentRoomOptionserror is clear. Confirm all code paths that might override previously storedroomOptionsare tested to avoid legitimate overrides being flagged.
182-253: Complex concurrency flow – proceed with caution.
The parallel tasks waiting for release completion or creation failure are well-coordinated withwithTaskGroup. This is powerful but can be tricky. Carefully maintain logs and test coverage to prevent subtle concurrency bugs (e.g., attempting multiplefailCreationcalls from different threads).
256-260: Re-check error translation toARTErrorInfo.
Wrappingerror.toARTErrorInfo()insidecatchensures external callers seeARTErrorInfo. Keep an eye out for internal errors that might contain additional info lost in translation.
294-294: Create room flow.
Creating the room and immediately storing it inroomStatesis correct. Just ensure a robust test that forcibly cancels the task before or duringcreateRoomto confirm safety.Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift (4)
32-46: Confirm async usage and concurrency correctness inattachAsync.
ThewithCheckedContinuationpattern to returnResult<Void, ARTErrorInfo>looks proper, and the subsequent.get()call ensures typed error propagation. Just ensure that any concurrent modifications to shared state are wrapped or guarded appropriately in the call sites.
48-62: Confirm async usage and concurrency correctness indetachAsync.
Same as withattachAsync, the concurrency model appears correct, and typed errors are consistently converted intoInternalError.
65-72: ValidatePresenceMessagestructure compliance with concurrency.
While marking it as aSendableversion ofARTPresenceMessageis correct, consider double-checking that all its fields conform to thread-safe usage, especially if they’re ever mutated after initialization.
88-171: Overall consistency in typed async presence APIs.
All new presence methods (getAsync,leaveAsync,enterClientAsync,updateAsync) correctly usewithCheckedContinuationand convertARTErrorInfointoInternalError. The usage ofpreconditionFailurefor unexpected nil branches also appears purposeful. This uniform approach strengthens clarity.Sources/AblyChat/DefaultPresence.swift (4)
22-45: Synchronized error conversion inget().
The logic properly waits for presence readiness and catches errors, translating them toARTErrorInfo. The approach is consistent with the rest of the typed-throws design.
73-97:isUserPresentaligns well with typed-throws design.
The call togetAsync(ARTRealtimePresenceQuery(clientId: …))logically complements the function’s purpose. No issues noted.
108-131: Validate test coverage forenter(optionalData:).
Enforcing typed errors and logging are good. Confirm that your test suite includes coverage for success/failure paths, ensuring that presence calling code properly awaits and handles potential errors.
297-297: Prompt consistency for error conversions.
processPresenceSubscribedirectly throwsARTErrorInfo, while other methods rely on conversion toInternalError. If uniform typed throws are desired throughout, consider converting or rethrowing asInternalErrorhere as well.Sources/AblyChat/RoomLifecycleManager.swift (4)
15-16: Typing the attach/detach operations forInternalError.
Switching fromARTErrorInfotoInternalErrorensures consistent usage across the codebase. The asynchronous approach remains coherent with the concurrency patterns in the rest of the SDK.Also applies to: 44-45, 49-49
589-590: Refined operation flow with typed continuation results.
EmbeddingInternalErrorin the continuation and wait flow is sensible for orchestrating attach/detach across multiple contributors. This improves clarity on final error states.Also applies to: 653-655, 679-679, 700-703
817-830: Graceful handling for suspended/failed states in attach/detach cycles.
This robust approach transitions the room status to suspended or failed while scheduling or executing follow-up operations. Its stepwise flow, with fallback cycles, seems thorough. A coverage check for partial failures (one channel fails while another succeeds) may help.Also applies to: 883-897, 905-905, 925-927, 940-940, 971-972
1220-1252: Verifying presence operations readiness.
The logic aroundwaitToBeAbleToPerformPresenceOperationschecks for anattachedstate or fails early if unreachable. This clarifies the state machine around presence operations.Sources/AblyChat/JSONCodable.swift (5)
8-10: Protocol method signatures properly updated for typed throwsThe update to
init(jsonValue:)to use typed throws withInternalErroris correctly implemented. This change aligns with the PR objective to standardize error handling in the public API.
25-27: Protocol method signatures properly updated for typed throwsThe update to
init(jsonObject:)to use typed throws withInternalErroris correctly implemented. This matches the approach used in theJSONDecodableprotocol.
38-44: Error conversion implementation is consistentThe implementation correctly uses the
.toInternalError()method to convertJSONValueDecodingErrortoInternalError. This ensures that all errors thrown from this protocol implementation are of the expected type.
58-68: Error handling standardization in dictionary extensionThe method signature update and error conversion implementation for
objectValueForKeyis properly implemented. Both error cases now consistently throwInternalErrorusing the.toInternalError()conversion method.
73-87: Consistent error handling across all dictionary extension methodsAll dictionary extension methods have been consistently updated to use typed throws with
InternalErrorand properly convert errors using.toInternalError(). This approach is applied uniformly across all helper methods, ensuring a consistent error handling pattern.Also applies to: 94-104, 109-123, 130-140, 145-159, 166-176, 181-195, 202-212, 219-233, 244-248, 253-259, 275-279, 286-292, 294-300
Our current usage of `realtime.request` is quite messy at the call site, and will get more so when we need to use typed throws throughout the codebase for #43. So move it to a helper (I've changed it to use typed throws whilst I'm at it). This also opens the door to us using a RoomLifecycleContributorChannel-like protocol internally when making requests, which will simplify mocking.
Motivation as in 400617f. It's nice that the presence data and extras are now expressed in terms of JSONValue, which simplifies various call sites.
Motivation as in 4c7c5a8.
Motivation as in 4c7c5a8.
Motivation as in 4c7c5a8.
37d38ac to
11d58da
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
Sources/AblyChat/DefaultTyping.swift (1)
101-102: 🛠️ Refactor suggestionEnsure
error.messageis valid for non-InternalErrorvalues.If the thrown
errorisn’t anInternalErrororARTErrorInfo, callingerror.messagemay cause runtime issues. Consider fallback toerror.localizedDescriptionto handle all error types safely.- logger.log(message: error.message, level: .error) + if let internalError = error as? InternalError { + logger.log(message: internalError.message, level: .error) + } else if let artError = error as? ARTErrorInfo { + logger.log(message: artError.message, level: .error) + } else { + logger.log(message: "\(error)", level: .error) + }
🧹 Nitpick comments (6)
CONTRIBUTING.md (1)
45-46: Consider adjusting punctuation to avoid potential style issues.The dash (“-”) following the code snippet can cause punctuation style warnings. Replacing it with a comma, semicolon, or a full stop can improve clarity and eliminate the warning.
- like: `do throws(InternalError) { … }`. - The compiler will never infer the type... + like: `do throws(InternalError) { … }`. The compiler will never infer the type...🧰 Tools
🪛 LanguageTool
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like:do throws(InternalError) { … }. - The compiler will never infer the t...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g.let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...(UNLIKELY_OPENING_PUNCTUATION)
Example/AblyChatExample/Mocks/MockClients.swift (2)
73-75: Unimplementeddetachin mock
Currently callsfatalError("Not yet implemented"). Consider returning a no-op or a made-up error for test stability rather than halting.-fatalError("Not yet implemented") +throw ARTErrorInfo.createMockError(description: "Mock detach not implemented.")
324-326:isUserPresentremains unimplemented
Marking this withfatalErrorcan disrupt test flows. Consider returning a predictable bool or throwing a mock error to facilitate testing edge cases.-fatalError("Not yet implemented") +return false // or +throw ARTErrorInfo.createMockError(description: "isUserPresent not implemented.")Sources/AblyChat/DefaultPresence.swift (2)
73-97: Add unit tests forisUserPresent(clientID:).
While the logic is straightforward, including dedicated test coverage for both present and absent client scenarios would strengthen confidence.
210-210: Possible unhandled errors within theTask.
Because errors thrown inside the Task block can be lost without ado-catch, consider wrappingtry processPresenceSubscribe(...)to handle or log failures properly.Sources/AblyChat/RoomLifecycleManager.swift (1)
764-865: Extend typed errors throughout attach cycle.
Converting attach failures intoInternalErroris coherent. Consider documenting partial attach scenarios if some contributors fail halfway through.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)
📒 Files selected for processing (41)
CONTRIBUTING.md(1 hunks)Example/AblyChatExample/Mocks/MockClients.swift(13 hunks)Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift(1 hunks)Sources/AblyChat/ChatAPI.swift(7 hunks)Sources/AblyChat/DefaultMessages.swift(6 hunks)Sources/AblyChat/DefaultOccupancy.swift(1 hunks)Sources/AblyChat/DefaultPresence.swift(5 hunks)Sources/AblyChat/DefaultRoomLifecycleContributor.swift(1 hunks)Sources/AblyChat/DefaultRoomReactions.swift(1 hunks)Sources/AblyChat/DefaultTyping.swift(3 hunks)Sources/AblyChat/Errors.swift(4 hunks)Sources/AblyChat/Extensions/Dictionary+Extensions.swift(1 hunks)Sources/AblyChat/Headers.swift(3 hunks)Sources/AblyChat/InternalError.swift(1 hunks)Sources/AblyChat/JSONCodable.swift(22 hunks)Sources/AblyChat/Message.swift(2 hunks)Sources/AblyChat/Messages.swift(6 hunks)Sources/AblyChat/Occupancy.swift(2 hunks)Sources/AblyChat/PaginatedResult.swift(3 hunks)Sources/AblyChat/Presence.swift(7 hunks)Sources/AblyChat/PresenceDataDTO.swift(1 hunks)Sources/AblyChat/Room.swift(4 hunks)Sources/AblyChat/RoomFeature.swift(2 hunks)Sources/AblyChat/RoomLifecycleManager.swift(17 hunks)Sources/AblyChat/RoomReactionDTO.swift(2 hunks)Sources/AblyChat/RoomReactions.swift(1 hunks)Sources/AblyChat/Rooms.swift(6 hunks)Sources/AblyChat/Typing.swift(2 hunks)Tests/AblyChatTests/ChatAPITests.swift(2 hunks)Tests/AblyChatTests/DefaultMessagesTests.swift(2 hunks)Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift(1 hunks)Tests/AblyChatTests/DefaultRoomsTests.swift(2 hunks)Tests/AblyChatTests/Helpers/Helpers.swift(2 hunks)Tests/AblyChatTests/InternalErrorTests.swift(1 hunks)Tests/AblyChatTests/Mocks/MockFeatureChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoom.swift(2 hunks)Tests/AblyChatTests/Mocks/MockRoomFactory.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift(2 hunks)Tests/AblyChatTests/PresenceDataDTOTests.swift(1 hunks)Tests/AblyChatTests/RoomReactionDTOTests.swift(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (31)
- Tests/AblyChatTests/PresenceDataDTOTests.swift
- Sources/AblyChat/RoomReactions.swift
- Tests/AblyChatTests/DefaultRoomsTests.swift
- Tests/AblyChatTests/Mocks/MockRoom.swift
- Sources/AblyChat/Extensions/Dictionary+Extensions.swift
- Sources/AblyChat/Headers.swift
- Tests/AblyChatTests/DefaultMessagesTests.swift
- Tests/AblyChatTests/RoomReactionDTOTests.swift
- Tests/AblyChatTests/Mocks/MockRoomFactory.swift
- Tests/AblyChatTests/ChatAPITests.swift
- Sources/AblyChat/DefaultRoomReactions.swift
- Sources/AblyChat/Typing.swift
- Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift
- Sources/AblyChat/Message.swift
- Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift
- Sources/AblyChat/Occupancy.swift
- Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift
- Sources/AblyChat/Errors.swift
- Tests/AblyChatTests/Mocks/MockFeatureChannel.swift
- Sources/AblyChat/RoomFeature.swift
- Sources/AblyChat/DefaultRoomLifecycleContributor.swift
- Sources/AblyChat/DefaultOccupancy.swift
- Sources/AblyChat/RoomReactionDTO.swift
- Sources/AblyChat/PresenceDataDTO.swift
- Tests/AblyChatTests/InternalErrorTests.swift
- Sources/AblyChat/PaginatedResult.swift
- Sources/AblyChat/Messages.swift
- Sources/AblyChat/Room.swift
- Sources/AblyChat/DefaultMessages.swift
- Sources/AblyChat/Presence.swift
- Sources/AblyChat/ChatAPI.swift
🧰 Additional context used
🪛 LanguageTool
CONTRIBUTING.md
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like: do throws(InternalError) { … }. - The compiler will never infer the t...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g. let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (8)
- GitHub Check: Example app, tvOS (Xcode 16)
- GitHub Check: Example app, iOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, tvOS (Xcode 16) - GitHub Check: Xcode, tvOS (Xcode 16)
- GitHub Check: SPM (Xcode 16)
- GitHub Check: Xcode, iOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, macOS (Xcode 16) - GitHub Check: Xcode, macOS (Xcode 16)
🔇 Additional comments (71)
Tests/AblyChatTests/Helpers/Helpers.swift (2)
8-33: Looks good!The logic for detecting and matching
ARTErrorInfoappears sound. The guard statement and subsequent checks effectively confirm appropriate error domain and codes.
35-38:Details
❓ Verification inconclusive
Verify that
ARTErrorInfosupports equality checks.You're using
if case let .errorInfo(actualErrorInfo) = internalError, expectedErrorInfo == actualErrorInfo. EnsureARTErrorInfoimplements equality or that you’ve added a custom extension to support this comparison.
🏁 Script executed:
#!/bin/bash # Description: Search for any extension or conformance of `ARTErrorInfo` to `Equatable`. fd -e swift --exec rg "struct|class|extension\s+ARTErrorInfo.*Equatable" {}Length of output: 12837
Action Required: Verify Equality Conformance for ARTErrorInfo
The code uses an equality check on ARTErrorInfo:
if let internalError = error as? InternalError, case let .errorInfo(actualErrorInfo) = internalError, expectedErrorInfo == actualErrorInfo { … }Our initial search (via the provided shell script) did not return clear evidence that ARTErrorInfo explicitly conforms to Equatable—or that there is a custom extension providing an equality implementation. Please manually verify (or update the implementation) to ensure that ARTErrorInfo supports equality comparisons as intended.
• Location: Tests/AblyChatTests/Helpers/Helpers.swift, Lines 35–38
Sources/AblyChat/InternalError.swift (1)
1-62: Structured internal error handling looks great!Defining
InternalErrorwith.errorInfoand.othervariants neatly unifies multiple error sources. Returning a well-definedARTErrorInfoensures consistent public exposure of error data.Sources/AblyChat/DefaultTyping.swift (2)
198-214: Previous concurrency concern still applies.
106-107:Details
✅ Verification successful
Validate consistency of error conversion to
ARTErrorInfo.The
catchblock rethrows usingerror.toARTErrorInfo(). Confirm that all possible errors in the do-block are indeedInternalError, to avoid runtime issues if another error type propagates.Also applies to: 148-149, 173-174
🏁 Script executed:
#!/bin/bash # Description: Search for async calls that might throw something other than `InternalError`. rg -A 4 "throws\(InternalError\)|throws\(ARTErrorInfo\)"Length of output: 75611
Ensure error conversion strictly handles InternalError.
In DefaultTyping.swift (lines 106–107, 148–149, and 173–174), the catch block rethrows errors viaerror.toARTErrorInfo(). Our verification confirms that the surrounding do blocks are declared withthrows(InternalError), ensuring that only InternalError instances are expected. Please double-check that no other error types are inadvertently introduced into these blocks—for both current implementations and any future changes—so that the conversion remains safe and consistent.Sources/AblyChat/Rooms.swift (7)
28-28: Use typed throw ingetfor clearer error handling
Designatingthrows(ARTErrorInfo)in the method signature provides explicit error semantics, making it clearer to callers what exceptions to expect.
86-89: Refined error type usage inRoomMapEntry.requestAwaitingRelease
Switching from a generic error toInternalErrorhelps unify error handling and maintain consistency with the rest of the codebase.
105-112: Consistent approach inwaitForRoom()
Usingasync throws(InternalError)and retrieving theResultviacreationTask.value.get()cleanly bridges concurrency and typed error handling. No issues noted.
154-261: Robust concurrency logic inget(roomID:options:)
The approach to synchronize room creation and release, handle in-progress states, and convertInternalErrortoARTErrorInfoensures type-safe error propagation. ThewithTaskGroupusage to wait for the first completed operation is a solid concurrency pattern.
264-283: Neat creation-failure streaming mechanism
DefiningmakeCreationFailureFunctions()to yield a failure viaAsyncStreamis an elegant way to coordinate inter-task failure signals. No concerns noted.
294-299:createRoomcomplementsgetperfectly
This helper adheres to the same error-handling policy, ensuring consistency across room creation code paths.
335-335: Consistent bridging fromARTErrorInfotoInternalError
Invoking.toInternalError()on a newly createdARTErrorInfoaligns with the rest of the file's typed-error strategy.Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift (9)
6-29:requestAsyncleverages Swift concurrency effectively
UsingwithCheckedContinuationfor callback-based APIs is appropriate. The fallback tofatalError()for programmer errors underscores the design intent that these exceptions should not typically occur in production.
32-46:attachAsyncwith typed error bridging
Attaching the channel with aResult<Void, ARTErrorInfo>continuation and converting toInternalErrorensures consistency with higher-level error handling.
48-62:detachAsyncfollows the same pattern
Again, a clear use ofwithCheckedContinuation, bridgingARTErrorInfo→InternalError. No issues noted.
65-87: NewPresenceMessagestruct
Mapping fromARTPresenceMessageinto aSendablestruct is straightforward and safe. This avoids concurrency pitfalls when sharing presence data.
88-106:getAsync()presence retrieval
Capturing presence state with explicit typed errors fits well. The usage of.get()on theResultensures typed error propagation.
107-123:getAsync(_ query:)variant
Same pattern as the no-parameter method, with typedInternalError. Implementation is consistent and clear.
125-139:leaveAsync(_:)method
No concerns: checks for error, bridges toInternalError, completes successfully otherwise.
141-155:enterClientAsyncbridging
UsingwithCheckedContinuationand bridgingARTErrorInfo→InternalErroris consistent across these concurrency extensions.
157-171:updateAsyncclarity
Retaining the callback-based logic but returningasync throws(InternalError)improves code readability and error handling uniformity.Example/AblyChatExample/Mocks/MockClients.swift (20)
26-33: Mockgetuses a typed throw
Switching tothrows(ARTErrorInfo)for thegetmethod is consistent with the updated API expectations. Implementation is straightforward.
69-71: Mockattachpartial implementation
Logging-only is fine for a mock. The typed throw aligns with the real method's signature.
125-127: Mockget(options:)
Returning a basicMockMessagesPaginatedResultis sufficient for testing scenarios.
129-145: Mocksendfor messages
Emitting the newly createdMessageto the subscription storage simulates sending behavior nicely.
147-163: Mockupdatefor messages
This approach consistently updates the action to.updateand emits a fresh message object. Looks good.
165-181: Mockdeletefor messages
Similarly sets.deleteaction and emits the new state. No issues found.
214-224: Mocksendfor reactions
Generating a newReactionand emitting it is consistent with mock patterns.
261-263: Mockgetin typing
Returning two random names fromMockStringsis a valid approach for simulation.
265-267: Mockstartin typing
Emitting a typing event with the current client ID is sufficient for basic testing.
269-271: Mockstopin typing
Emitting an emptyTypingEventis similarly adequate for tests.
328-330: Mock presenceenter()
Delegating toenter(dataForEvent: nil)is consistent with typed-error refactoring.
332-334: Mock presenceenter(data:)
Correctly funnels calls into the sharedenter(dataForEvent:)helper. Looks good.
336-345: Privateenter(dataForEvent:)
Emitting a.enterevent tomockSubscriptionsis a straightforward simulation of presence entering.
347-349: Presenceupdate()no-arg
Delegation toupdate(dataForEvent: nil)preserves consistency. No concerns.
351-353: Presenceupdate(data:)
Similarly delegates to the shared update function. Implementation is coherent.
355-364: Privateupdate(dataForEvent:)
Emitting an.updateevent ensures presence status changes can be captured.
366-368: Presenceleave()
Again, nicely delegates toleave(dataForEvent: nil).
370-372: Presenceleave(data:)
Consistent approach. No issues.
374-383: Privateleave(dataForEvent:)
Properly emits a.leavepresence event. This addresses leaving logic well for mocking scenarios.
422-424: Mockgetin occupancy
Provides a static occupancy event. Suitable for simple testing.Sources/AblyChat/DefaultPresence.swift (12)
22-44: Consistent re-throwing withARTErrorInfo.
The method correctly wrapsInternalErrorerrors and re-throws them asARTErrorInfo. Logging is also well placed for troubleshooting.
47-69: Parameterized presence retrieval is now fully utilized.
Passingparams.asARTRealtimePresenceQuery()ensures the query parameters are respected, resolving previous concerns about unused parameters.
99-104: Helper method usage is clear.
These lines simply delegate toenter(optionalData:), which improves maintainability by keeping logic centralized.
107-130: Robust async presence enter flow.
This block cleanly waits for the room to be attachable before callingenterClientAsync, then transforms and re-throws errors asARTErrorInfo.
133-139: Consistent delegation forupdate(data:).
Similar toenter(), this pattern keeps exposed methods small and maintainable.
142-164: Error conversion inupdate(optionalData:).
You are correctly logging the error and converting toARTErrorInfo, maintaining consistent error-handling patterns.
167-173: Delegation forleave(data:).
This matches the established style, increasing coherence across presence operations.
176-198: Presence leave operation.
Re-throwingInternalErrorasARTErrorInfomaintains a uniform public interface. Logging statements are appropriate for debugging.
230-230: Same potential unhandled exception in Task.
This invocation mirrors line 210’s pattern.
252-257: Graceful handling of missing data indecodePresenceDataDTO().
Throwing an internal error whenpresenceDataisnilmakes the failure state explicit and ensures consistent error conversion.
267-295: MappingPresenceMessageto domain model.
Neatly handles missing client IDs or timestamps and logs errors with context. This is a good, defensive approach.
297-297: Typed throws in subscription processing.
This move tothrows(InternalError)ensures uniform error handling throughout.Sources/AblyChat/RoomLifecycleManager.swift (14)
14-16: Transition tothrows(InternalError)in channel protocol.
Using typed errors here unifies error handling at the protocol level and clarifies expected failure modes.
44-45:RoomLifecycleManageroperations now use typed throws.
Shifting tothrows(InternalError)for attach/detach/wait operations ensures internal errors are handled consistently.Also applies to: 49-49
589-590: OperationResultContinuations now storingInternalError.
Revising continuation results toResult<Void, InternalError>centralizes error representation and prevents confusion.
653-655: Typed error throw inwaitForCompletionOfOperationWithID.
This clarifies that operation completions can propagateInternalErrorto callers.
678-680: Operation completion result withInternalError.
Consistently capturing typed errors is helpful for reliability and debugging.
700-704:performAnOperationnowthrows(InternalError).
Adopting typed throws refines the contract for all room lifecycle operations.
746-759: Typed attach operation.
Calls to_performAttachOperationare now fully typed, aligning with the broader error-handling pattern.
865-871: Refined detach error signature.
EnsuringperformDetachOperationthrowsInternalErrorkeeps operations symmetrical.
877-899: Detachment cycle now typed.
Centralizing all detach failure paths aroundInternalErrorclarifies how partial failures propagate.
924-989: Partial contributor detachment handling.
Retry logic for non-failed contributors is robust. The approach to handling concurrency is sound here.
971-972: Detachment errors rethrown asInternalError.
This final ensures consistent error form across the entire cycle.
1075-1075:performRetryOperationtyped throw.
Handling suspended channels under a uniform error type simplifies retry logic.
1178-1187:performRundownOperationerror alignment.
Equally adoptingInternalErrorfor the RUNDOWN flow fosters consistency with attach/detach.
1220-1251: Presence operation readiness checks.
ThrowingpresenceOperationRequiresRoomAttachclarifies the precondition needed (attached room) and improves developer feedback.Sources/AblyChat/JSONCodable.swift (4)
9-9: Protocols updated to throwInternalError.
Applying typed throws inJSONDecodableandJSONObjectDecodableclarifies decoding failure modes.Also applies to: 26-26, 38-38
58-220: Dictionary extensions now throwInternalError.
This uniform approach ensures decoding mistakes produce consistent internal exceptions instead of generic errors.
245-253: Date extraction with typed errors.
Interpreting Ably’s epoch-based timestamps now explicitly returns anInternalErroron invalid input.
275-286: Safe raw-value decoding with typed errors.
Providing a clear error ifinit(rawValue:)fails improves debugging and user feedback.Also applies to: 294-294
maratal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some questions.
This updates our public API to use typed throws, and specifically to always throw ARTErrorInfo. This makes us consistent with ably-cocoa, and allows users to access the error's `statusCode` to make decisions about whether they can retry the action that caused the error. I've gone for a light-touch approach of not changing any of the various error types that exist inside the SDK; inside I've hidden them all behind a common InternalError type, which can be converted to an ARTErrorInfo. We can revisit this in #32 (i.e. should we keep this rich internal Swift error types or just throw ARTErrorInfo internally?) Resolves #43.
11d58da to
c09ac03
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)
📒 Files selected for processing (41)
CONTRIBUTING.md(1 hunks)Example/AblyChatExample/Mocks/MockClients.swift(13 hunks)Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift(1 hunks)Sources/AblyChat/ChatAPI.swift(7 hunks)Sources/AblyChat/DefaultMessages.swift(6 hunks)Sources/AblyChat/DefaultOccupancy.swift(1 hunks)Sources/AblyChat/DefaultPresence.swift(5 hunks)Sources/AblyChat/DefaultRoomLifecycleContributor.swift(1 hunks)Sources/AblyChat/DefaultRoomReactions.swift(1 hunks)Sources/AblyChat/DefaultTyping.swift(3 hunks)Sources/AblyChat/Errors.swift(4 hunks)Sources/AblyChat/Extensions/Dictionary+Extensions.swift(1 hunks)Sources/AblyChat/Headers.swift(3 hunks)Sources/AblyChat/InternalError.swift(1 hunks)Sources/AblyChat/JSONCodable.swift(22 hunks)Sources/AblyChat/Message.swift(2 hunks)Sources/AblyChat/Messages.swift(6 hunks)Sources/AblyChat/Occupancy.swift(2 hunks)Sources/AblyChat/PaginatedResult.swift(3 hunks)Sources/AblyChat/Presence.swift(7 hunks)Sources/AblyChat/PresenceDataDTO.swift(1 hunks)Sources/AblyChat/Room.swift(4 hunks)Sources/AblyChat/RoomFeature.swift(2 hunks)Sources/AblyChat/RoomLifecycleManager.swift(17 hunks)Sources/AblyChat/RoomReactionDTO.swift(2 hunks)Sources/AblyChat/RoomReactions.swift(1 hunks)Sources/AblyChat/Rooms.swift(6 hunks)Sources/AblyChat/Typing.swift(2 hunks)Tests/AblyChatTests/ChatAPITests.swift(2 hunks)Tests/AblyChatTests/DefaultMessagesTests.swift(2 hunks)Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift(1 hunks)Tests/AblyChatTests/DefaultRoomsTests.swift(2 hunks)Tests/AblyChatTests/Helpers/Helpers.swift(2 hunks)Tests/AblyChatTests/InternalErrorTests.swift(1 hunks)Tests/AblyChatTests/Mocks/MockFeatureChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoom.swift(2 hunks)Tests/AblyChatTests/Mocks/MockRoomFactory.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift(1 hunks)Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift(2 hunks)Tests/AblyChatTests/PresenceDataDTOTests.swift(1 hunks)Tests/AblyChatTests/RoomReactionDTOTests.swift(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (33)
- Sources/AblyChat/Headers.swift
- Sources/AblyChat/PresenceDataDTO.swift
- Sources/AblyChat/Extensions/Dictionary+Extensions.swift
- Sources/AblyChat/Errors.swift
- Tests/AblyChatTests/PresenceDataDTOTests.swift
- Sources/AblyChat/RoomReactions.swift
- Tests/AblyChatTests/RoomReactionDTOTests.swift
- Sources/AblyChat/DefaultRoomReactions.swift
- Tests/AblyChatTests/ChatAPITests.swift
- Tests/AblyChatTests/Mocks/MockFeatureChannel.swift
- Tests/AblyChatTests/DefaultRoomsTests.swift
- Sources/AblyChat/Occupancy.swift
- Tests/AblyChatTests/Mocks/MockRoomLifecycleContributorChannel.swift
- Sources/AblyChat/RoomReactionDTO.swift
- Tests/AblyChatTests/DefaultRoomLifecycleManagerTests.swift
- Tests/AblyChatTests/DefaultMessagesTests.swift
- Tests/AblyChatTests/Mocks/MockRoom.swift
- Sources/AblyChat/Typing.swift
- Sources/AblyChat/DefaultRoomLifecycleContributor.swift
- Tests/AblyChatTests/InternalErrorTests.swift
- Tests/AblyChatTests/Mocks/MockRoomLifecycleManager.swift
- Tests/AblyChatTests/Mocks/MockRoomFactory.swift
- Sources/AblyChat/Message.swift
- Sources/AblyChat/DefaultOccupancy.swift
- Sources/AblyChat/Room.swift
- Sources/AblyChat/RoomFeature.swift
- Sources/AblyChat/DefaultMessages.swift
- Sources/AblyChat/Presence.swift
- Sources/AblyChat/RoomLifecycleManager.swift
- Example/AblyChatExample/Mocks/MockClients.swift
- Sources/AblyChat/Messages.swift
- Sources/AblyChat/PaginatedResult.swift
- Sources/AblyChat/JSONCodable.swift
🧰 Additional context used
🪛 LanguageTool
CONTRIBUTING.md
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like: do throws(InternalError) { … }. - The compiler will never infer the t...
(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g. let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (11)
- GitHub Check: Example app, tvOS (Xcode 16)
- GitHub Check: Example app, iOS (Xcode 16)
- GitHub Check: Example app, macOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, tvOS (Xcode 16) - GitHub Check: Xcode, tvOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, iOS (Xcode 16) - GitHub Check: Xcode, iOS (Xcode 16)
- GitHub Check: Xcode,
releaseconfiguration, macOS (Xcode 16) - GitHub Check: Xcode, macOS (Xcode 16)
- GitHub Check: SPM (Xcode 16)
- GitHub Check: SPM,
releaseconfiguration (Xcode 16)
🔇 Additional comments (30)
CONTRIBUTING.md (1)
35-47: Great addition of error handling documentation!This new "Throwing errors" section provides clear guidance on the error handling strategy - using
ARTErrorInfofor public API andInternalErrorinternally. The section about Swift's typed throws limitations and workarounds is particularly helpful for contributors.🧰 Tools
🪛 LanguageTool
[uncategorized] ~45-~45: Loose punctuation mark.
Context: ...ify the type of the thrown error, like:do throws(InternalError) { … }. - The compiler will never infer the t...(UNLIKELY_OPENING_PUNCTUATION)
[uncategorized] ~46-~46: Loose punctuation mark.
Context: ...ill need to specify this yourself; e.g.let items = try jsonValues.map { jsonValue throws(InternalError) in … }. ### Testing guidelines #### Exposin...(UNLIKELY_OPENING_PUNCTUATION)
Tests/AblyChatTests/Helpers/Helpers.swift (4)
5-22: Well-implemented error checking enhancementsThe improved
isChatErrorfunction now properly handles both directARTErrorInfoerrors andInternalErrorinstances that wrap anARTErrorInfo. This makes the test helpers compatible with the new error handling approach.
35-41: Good addition of specialized error checkingThe new
isInternalErrorWrappingErrorInfofunction provides a clean way to verify if an error is anInternalErrorwrapping a specificARTErrorInfo. This will make tests more specific and readable.
43-66: Well-designed error categorizationThe
InternalError.Caseenum provides a clean way to categorize different types of internal errors, enhancing testing capabilities. TheenumCaseproperty enables convenient access to the specific case of an error without complex pattern matching in tests.
68-74: Useful helper for error case checkingThe
isInternalErrorWithCasefunction complements the error case system, allowing for concise checks of error types in tests without boilerplate casting and pattern matching.Sources/AblyChat/InternalError.swift (2)
3-31: Well-structured error handling implementationThe
InternalErrorenum provides a clean, unified approach to error handling. The documentation explains the current design and future plans well. ThetoARTErrorInfo()method provides a clear conversion path from internal errors to public API errors.
33-61: Good extensions for error conversionThese extensions provide a consistent way to convert various error types to
InternalError. This approach reduces boilerplate code throughout the codebase and ensures uniform error handling.Sources/AblyChat/DefaultTyping.swift (5)
85-107: Improved error typing inget()methodThe method now correctly uses typed throws with
ARTErrorInfofor the public API and handlesInternalErrorinternally. The implementation has been simplified by usinggetAsync()directly.
111-149: Well-structured error handling instart()methodThe method now uses a continuation pattern that returns a
Result<Void, InternalError>and properly converts internal errors toARTErrorInfoat the public API boundary. The implementation is clean and consistent with the new error handling approach.
153-174: Improved error handling instop()methodThe method now properly throws typed errors (
ARTErrorInfo) and handlesInternalErrorinternally, maintaining consistency with the overall error handling approach in the SDK.
182-194: Good error handling inprocessPresenceGetThe method now properly throws
InternalErrorand convertsARTErrorInfotoInternalErrorusing the new extension method, maintaining consistency with the overall error handling approach.
198-204: Note about error propagation in TaskThis code throws an error inside a Task, but since the function isn't async, the error won't propagate to the caller. However, this is existing behavior from before this PR and outside the current scope of changes.
Is this error handling pattern intended? Since the function isn't
async, errors thrown within the Task won't propagate to the original caller. Consider adding a comment explaining this design decision or creating a separate issue to address this in the future.Sources/AblyChat/Rooms.swift (5)
28-28: The protocol method signature is correctly updated to throwARTErrorInfo.The
getmethod now explicitly throwsARTErrorInfoinstead of a genericError, which aligns with the PR objective to use typed throws in the public API.
86-88: Good update of theRoomMapEntryenum to useInternalError.The change from generic
Errorto the more specificInternalErrorin both thecreationTaskresult type and thefailCreationclosure parameter improves type safety and error handling clarity.
105-105:waitForRoom()method now throwsInternalErroras expected.This change correctly aligns with the internal error handling strategy where internal methods throw
InternalError.
154-260: Good implementation of the error handling pattern in thegetmethod.The implementation correctly uses
do throws(InternalError)for internal error handling and converts toARTErrorInfoat the public API boundary. The code correctly maintains the error conversion flow and preserves the detailed errors.
294-294:createRoommethod now throwsInternalErrorcorrectly.This internal method has been updated to specifically throw
InternalError, which aligns with the internal error handling strategy.Sources/AblyChat/AblyCocoaExtensions/Ably+Concurrency.swift (4)
6-29: Well-implementedrequestAsyncmethod with proper error handling.This new method extends
ARTRealtimeInstanceMethodsProtocolwith an asynchronous HTTP request capability that properly handles and converts errors. The implementation useswithCheckedContinuationcorrectly to bridge the callback-based API to Swift's async/await pattern.
32-63: Good update ofattachAsyncanddetachAsyncmethods to throwInternalError.Both methods now correctly use
InternalErrorfor error handling, which aligns with the internal error strategy in the codebase.
65-86: Well-designedPresenceMessagestruct to ensureSendablecompliance.The new
PresenceMessagestruct provides aSendableversion ofARTPresenceMessage, which is important for concurrency safety. The implementation correctly includes only the properties needed for the Chat SDK and provides a clean conversion method from the Ably Cocoa type.
88-171: Comprehensive set of async presence methods with proper error handling.The extension adds several asynchronous methods to
ARTRealtimePresenceProtocolthat correctly handle errors and provide a modern Swift API surface. The implementation ofupdateAsynccorrectly calls theupdatemethod as expected.Sources/AblyChat/ChatAPI.swift (4)
13-13: Public method signatures correctly updated to throwInternalError.The method signatures for
getMessages,sendMessage,updateMessage,deleteMessage, andgetOccupancyhave been properly updated to specify that they throwInternalError, which aligns with the internal error handling strategy.Also applies to: 43-43, 82-82, 134-134, 172-172
45-46: Proper error conversion toInternalErrorin client ID validation.The error handling for missing client ID now correctly converts
ARTErrorInfotoInternalErrorusing thetoInternalError()method, maintaining the error type consistency.Also applies to: 84-85
177-193: Good refactoring ofmakeRequestto userequestAsyncand proper error handling.The implementation now uses the new
requestAsyncmethod and correctly handles errors by throwingInternalErrorwhen needed. This simplifies the error handling path and maintains type consistency.
198-205: UpdatedmakePaginatedRequestwith proper error handling.The method now correctly specifies that it throws
InternalErrorand uses typed throw annotations in the mapping closure, ensuring error type consistency throughout the API.Sources/AblyChat/DefaultPresence.swift (5)
22-22: Public method signatures correctly updated to throwARTErrorInfo.All public methods in the
DefaultPresenceclass have been updated to specify that they throwARTErrorInfo, which aligns with the PR objective to use typed throws in the public API.Also applies to: 47-47, 73-73, 99-99, 103-103, 133-133, 137-137, 167-167, 171-171
23-44: Good implementation of the error handling pattern in all presence methods.Each method correctly uses
do throws(InternalError)blocks for internal error handling and converts toARTErrorInfoat the public API boundary. The implementation also properly uses the new async methods fromARTRealtimePresenceProtocol.Also applies to: 48-69, 74-96, 109-130, 143-164, 177-198
252-265: Proper error handling indecodePresenceDataDTO.The method now correctly throws
InternalErrorand converts errors appropriately, maintaining consistency with the rest of the error handling strategy.
267-295: UpdatedprocessPresenceGetto work withPresenceMessageand proper error handling.The method now accepts
PresenceMessageinstead ofARTPresenceMessageand properly throwsInternalError, aligning with the changes in the rest of the codebase.
297-297: UpdatedprocessPresenceSubscribeto work withPresenceMessage.The method signature has been updated to accept
PresenceMessagedirectly, which works well with the newPresenceMessagestruct and improves the code's clarity.
maratal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
This updates our public API to use typed throws, and specifically to always throw
ARTErrorInfo. This makes us consistent with ably-cocoa, and allows users to access the error'sstatusCodeto make decisions about whether they can retry the action that caused the error.See commit messages for more details.
Resolves #43.
Summary by CodeRabbit
Documentation
Refactor
Tests