-
Notifications
You must be signed in to change notification settings - Fork 192
Added channel helpers for realtime in the client sdks #1266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds Channel builders and a Channel DSL across SDK generators and templates for Android (Kotlin), Apple (Swift), Flutter (Dart), Web (TypeScript), and React Native (TypeScript). New Channel template files and tests were added; client and realtime subscribe APIs were extended to accept Channel-like types with normalization helpers. Realtime subscription overloads and WebSocket delegate signatures (Swift NIO types) were updated. Test suites and many language-specific test expectations were extended via a new CHANNEL_HELPER_RESPONSES constant. Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
tests/languages/web/node.js (1)
1-1: Critical: Channel not imported.Channel is used extensively in lines 253-273 but is never imported from the SDK. This will cause runtime errors when the tests execute.
🔎 Apply this diff to add Channel to the imports:
-const { Client, Foo, Bar, General, Query, Permission, Role, ID, Operator, Condition, MockType } = require('./dist/cjs/sdk.js'); +const { Client, Foo, Bar, General, Query, Permission, Role, ID, Channel, Operator, Condition, MockType } = require('./dist/cjs/sdk.js');tests/languages/node/test.js (1)
1-13: Critical: Channel not imported.Channel is used in lines 329-349 but is not included in the import statement. This will cause runtime errors.
🔎 Apply this diff to add Channel to the imports:
const { Client, Permission, Query, Role, ID, + Channel, Operator, Condition, MockType, Foo, Bar, General } = require('./dist/index.js');tests/languages/web/index.html (1)
24-24: Critical: Channel not destructured from Appwrite.Channel is used in lines 322-342 but is not included in the destructuring assignment. This will cause runtime errors.
🔎 Apply this diff to add Channel to the destructuring:
- const { Client, Foo, Bar, General, Realtime, Query, Permission, Role, ID, Operator, Condition, MockType } = Appwrite; + const { Client, Foo, Bar, General, Realtime, Query, Permission, Role, ID, Channel, Operator, Condition, MockType } = Appwrite;
🧹 Nitpick comments (4)
templates/dart/lib/channel.dart.twig (1)
13-24: Consider using an enum for theactionparameter for type safety.The
actionparameter accepts anyString?, but the documentation indicates only'create','update', or'delete'are valid. Consider defining an enum to enforce valid values at compile time:🔎 Example enum approach
enum ChannelAction { create, update, delete } static String database({ String databaseId = '*', String collectionId = '*', String documentId = '*', ChannelAction? action, }) { String channel = 'databases.$databaseId.collections.$collectionId.documents.$documentId'; if (action != null) { channel += '.${action.name}'; } return channel; }This would provide compile-time safety and IDE autocompletion. The current String approach is acceptable if flexibility for future action types is desired.
templates/android/library/src/main/java/io/package/Channel.kt.twig (2)
18-24: Consider using a Kotlin enum for theactionparameter.Similar to the Dart implementation, the
actionparameter accepts anyString?. Kotlin supports enums that could provide compile-time safety:🔎 Example enum approach
enum class ChannelAction { CREATE, UPDATE, DELETE; override fun toString(): String = name.lowercase() } fun database( databaseId: String = "*", collectionId: String = "*", documentId: String = "*", action: ChannelAction? = null ): String { var channel = "databases.$databaseId.collections.$collectionId.documents.$documentId" if (action != null) { channel += ".$action" } return channel }The current String approach maintains consistency with the Dart SDK if that's a design goal.
16-17: Minor: KDoc uses@return, not@returns.The KDoc standard uses
@returnfor documenting return values.@returnsis JSDoc syntax. While most tools will handle it, consider using the correct KDoc syntax for consistency.🔎 Apply this diff
- * @returns The channel string + * @return The channel stringThis applies to all methods in the class.
templates/react-native/src/channel.ts.twig (1)
1-110: Consider sharing this template with the Web SDK to reduce duplication.This file is identical to
templates/web/src/channel.ts.twig. Since both Web and React Native use TypeScript, consolidating to a single shared template would eliminate the need to maintain duplicate code.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
src/SDK/Language/Android.php(1 hunks)src/SDK/Language/Apple.php(1 hunks)src/SDK/Language/Dart.php(1 hunks)src/SDK/Language/Flutter.php(2 hunks)src/SDK/Language/ReactNative.php(1 hunks)src/SDK/Language/Web.php(1 hunks)templates/android/library/src/main/java/io/package/Channel.kt.twig(1 hunks)templates/dart/lib/channel.dart.twig(1 hunks)templates/dart/lib/package.dart.twig(1 hunks)templates/dart/test/channel_test.dart.twig(1 hunks)templates/react-native/src/channel.ts.twig(1 hunks)templates/react-native/src/index.ts.twig(1 hunks)templates/swift/Sources/Channel.swift.twig(1 hunks)templates/web/src/channel.ts.twig(1 hunks)templates/web/src/index.ts.twig(1 hunks)tests/languages/android/Tests.kt(1 hunks)tests/languages/apple/Tests.swift(1 hunks)tests/languages/flutter/tests.dart(1 hunks)tests/languages/node/test.js(1 hunks)tests/languages/swift/Tests.swift(1 hunks)tests/languages/web/index.html(1 hunks)tests/languages/web/node.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/languages/android/Tests.kt (1)
tests/languages/kotlin/Tests.kt (1)
writeToFile(271-274)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, Python312)
- GitHub Check: build (8.3, Ruby31)
- GitHub Check: build (8.3, Swift56)
- GitHub Check: build (8.3, DartBeta)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: swift (server)
- GitHub Check: python (server)
- GitHub Check: react-native (client)
- GitHub Check: flutter (client)
- GitHub Check: apple (client)
- GitHub Check: dotnet (server)
- GitHub Check: kotlin (server)
- GitHub Check: android (client)
🔇 Additional comments (18)
tests/languages/web/node.js (1)
253-273: LGTM! Comprehensive Channel helper test coverage.The test coverage for Channel helpers is thorough, testing all methods with default parameters, specific IDs, and optional actions.
tests/languages/node/test.js (1)
329-349: LGTM! Comprehensive test coverage.The Channel helper tests are well-structured and cover all the required methods with various parameter combinations.
tests/languages/web/index.html (1)
322-342: LGTM! Thorough test coverage.The Channel helper tests are comprehensive and follow the established testing patterns.
templates/dart/test/channel_test.dart.twig (1)
1-111: LGTM! Excellent test template implementation.The test template is well-structured with:
- Proper conditional logic for Dart vs Flutter test packages
- Comprehensive coverage of all Channel methods
- Multiple test cases per method (defaults, specific IDs, actions)
- Correct use of Dart/Flutter testing conventions
src/SDK/Language/Web.php (1)
83-87: LGTM!The channel.ts file generation entry is correctly configured. The template file
templates/web/src/channel.ts.twigexists and Channel is properly exported intemplates/web/src/index.ts.twig.tests/languages/flutter/tests.dart (1)
250-270: LGTM! Comprehensive Channel helper test coverage.The tests exercise all Channel helper methods with various parameter combinations (default wildcards, specific IDs, and action suffixes), consistent with the existing test patterns in this file for Query, Permission, and Role helpers.
templates/dart/lib/channel.dart.twig (1)
45-50: Account helper correctly omits action parameter.Unlike other channel types, the account channel appropriately excludes the
actionparameter, which aligns with how account subscriptions work in Appwrite realtime.src/SDK/Language/Flutter.php (2)
83-87: LGTM! Channel file generation configuration.The channel.dart generation entry follows the established pattern for other helper files (id.dart, permission.dart, role.dart, query.dart, operator.dart).
298-302: LGTM! Channel test file generation configuration.Test file generation entry follows the same pattern as existing test entries and correctly references the shared Dart test template.
templates/web/src/channel.ts.twig (1)
14-20: Good use of TypeScript union type for action parameter.The union type
'create' | 'update' | 'delete' | nullprovides compile-time type safety, which is better than the untyped String approach in Dart. This is a good pattern.templates/web/src/index.ts.twig (1)
18-18: LGTM! Channel export added to public API.The Channel class is correctly exported, making it accessible to SDK consumers.
templates/react-native/src/index.ts.twig (1)
11-11: LGTM!The Channel export follows the existing pattern and is correctly positioned among other helper utilities.
src/SDK/Language/ReactNative.php (1)
63-67: LGTM!The Channel file generation entry follows the established pattern for other helper utilities and is correctly positioned in the file list.
src/SDK/Language/Apple.php (1)
73-77: LGTM!The Channel.swift generation entry is consistent with other Swift helper file entries and correctly positioned.
tests/languages/swift/Tests.swift (1)
238-259: Comprehensive test coverage!The Channel helper tests are well-structured and cover all methods with various parameter combinations:
- Default parameters (wildcards)
- Specific IDs
- Optional action parameters
The tests follow the existing pattern in the test suite.
src/SDK/Language/Android.php (1)
123-127: LGTM!The Channel.kt generation entry is consistent with other Android helper file entries and correctly positioned in the file list.
tests/languages/android/Tests.kt (1)
272-293: Excellent test coverage!The Channel helper tests comprehensively cover all methods with various parameter combinations and match the test coverage in other language implementations. The tests follow the existing Android test pattern using
writeToFile().templates/swift/Sources/Channel.swift.twig (1)
1-108: Well-implemented Channel helper with comprehensive documentation and consistent cross-language implementation.The implementation is clean and follows consistent patterns across all seven methods. Each method correctly builds channel strings using string interpolation and conditionally appends the optional action parameter, with support for both the traditional documents/collections terminology and the new relational model with tables/rows. All language implementations (Swift, Kotlin, TypeScript for React-Native and Web, and Dart) have identical method signatures and channel string formats, confirming consistency across the SDK generator templates.
- Updated Apple and Dart SDKs to include Channel templates. - Added Channel class in Swift template for Apple SDK. - Included Channel in Dart SDK template and test files. - Updated test cases across various platforms to incorporate Channel responses. - Modified web and node.js files to import Channel functionality.
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 (1)
templates/apple/Sources/Channel.swift.twig (1)
1-107: Consider optional action parameter validation.The documentation suggests that the action parameter should be "create", "update", or "delete", but the implementation accepts any string. While this provides flexibility, you might consider adding validation to ensure only valid actions are used, especially if the realtime API rejects invalid action values.
Example validation approach:
You could add an enum for valid actions:
public enum ChannelAction: String { case create = "create" case update = "update" case delete = "delete" }Then update method signatures to accept
ChannelAction?instead ofString?:public static func database(databaseId: String = "*", collectionId: String = "*", documentId: String = "*", action: ChannelAction? = nil) -> String { var channel = "databases.\(databaseId).collections.\(collectionId).documents.\(documentId)" if let action = action { channel += ".\(action.rawValue)" } return channel }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
src/SDK/Language/Apple.php(1 hunks)src/SDK/Language/Dart.php(2 hunks)templates/apple/Sources/Channel.swift.twig(1 hunks)templates/dart/test/channel_test.dart.twig(1 hunks)templates/flutter/lib/package.dart.twig(1 hunks)tests/Android14Java11Test.php(1 hunks)tests/Android14Java17Test.php(1 hunks)tests/Android14Java8Test.php(1 hunks)tests/Android5Java17Test.php(1 hunks)tests/AppleSwift56Test.php(1 hunks)tests/Base.php(1 hunks)tests/FlutterBetaTest.php(1 hunks)tests/FlutterStableTest.php(1 hunks)tests/WebChromiumTest.php(1 hunks)tests/WebNodeTest.php(1 hunks)tests/languages/android/Tests.kt(2 hunks)tests/languages/node/test.js(2 hunks)tests/languages/web/index.html(2 hunks)tests/languages/web/node.js(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- tests/languages/web/node.js
- src/SDK/Language/Dart.php
- templates/dart/test/channel_test.dart.twig
🧰 Additional context used
🧬 Code graph analysis (9)
tests/WebChromiumTest.php (1)
tests/Base.php (1)
Base(17-349)
tests/Android14Java17Test.php (1)
tests/Base.php (1)
Base(17-349)
tests/AppleSwift56Test.php (1)
tests/Base.php (1)
Base(17-349)
tests/languages/android/Tests.kt (1)
tests/languages/kotlin/Tests.kt (1)
writeToFile(271-274)
tests/FlutterBetaTest.php (1)
tests/Base.php (1)
Base(17-349)
tests/WebNodeTest.php (1)
tests/Base.php (1)
Base(17-349)
tests/Android5Java17Test.php (1)
tests/Base.php (1)
Base(17-349)
tests/Android14Java8Test.php (1)
tests/Base.php (1)
Base(17-349)
tests/FlutterStableTest.php (1)
tests/Base.php (1)
Base(17-349)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: build (8.3, Node18)
- GitHub Check: build (8.3, Python39)
- GitHub Check: build (8.3, Swift56)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, Python312)
- GitHub Check: build (8.3, WebChromium)
- GitHub Check: build (8.3, Python311)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, PHP83)
- GitHub Check: build (8.3, KotlinJava8)
- GitHub Check: build (8.3, PHP80)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, CLINode16)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, DartStable)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: swift (server)
- GitHub Check: apple (client)
- GitHub Check: android (client)
🔇 Additional comments (24)
tests/languages/node/test.js (2)
7-7: LGTM!The Channel import is correctly added to the destructured require statement.
330-350: Comprehensive test coverage for Channel helpers.The test calls cover all seven Channel helper methods with appropriate parameter variations (defaults, specific IDs, and actions). The test patterns align with the expected responses defined in Base.php.
templates/apple/Sources/Channel.swift.twig (7)
11-17: LGTM!The database channel helper correctly constructs the channel string with proper parameter defaults and optional action handling.
28-34: LGTM!The tablesdb channel helper follows the same pattern as database() and correctly constructs the channel string for table-based operations.
42-44: LGTM!The account channel helper is correctly implemented with appropriate simplicity for account-based subscriptions.
54-60: LGTM!The files channel helper correctly constructs the channel string for bucket/file operations with proper action handling.
70-76: LGTM!The executions channel helper correctly constructs the channel string for function execution subscriptions.
85-91: LGTM!The teams channel helper correctly constructs the channel string with appropriate simplicity and optional action handling.
100-106: LGTM!The memberships channel helper is correctly implemented and follows the established pattern.
tests/Android5Java17Test.php (1)
35-35: LGTM!The expectedOutput array is correctly extended to include Channel helper responses, aligning with the new Channel functionality across the SDK.
tests/Android14Java11Test.php (1)
36-36: LGTM!The expectedOutput array is correctly extended to include Channel helper responses, consistent with the test data expansion across all language test suites.
tests/Android14Java17Test.php (1)
35-35: LGTM!The expectedOutput array is correctly extended to include Channel helper responses, maintaining consistency with other test files in the PR.
tests/FlutterBetaTest.php (1)
34-34: LGTM!The expectedOutput array is correctly extended to include Channel helper responses, properly aligned with the Flutter SDK's Channel helper implementation.
tests/Android14Java8Test.php (1)
36-36: LGTM!The expectedOutput array is correctly extended to include Channel helper responses, consistent with the test expectations across all Android SDK variants.
tests/WebNodeTest.php (1)
38-38: LGTM!The expectedOutput array is correctly extended to include Channel helper responses, completing the test coverage expansion for the Web SDK.
tests/AppleSwift56Test.php (1)
34-34: LGTM!The addition of
CHANNEL_HELPER_RESPONSESto the expected output is consistent with the broader PR changes adding Channel helpers across SDK languages. The placement between ID and Operator helper responses maintains a logical test ordering.src/SDK/Language/Apple.php (1)
73-77: LGTM!The Channel.swift file entry is correctly structured and positioned logically in the manifest. The use of the
apple/Sources/Channel.swift.twigtemplate path aligns with the Apple-specific implementation strategy.templates/flutter/lib/package.dart.twig (1)
33-33: LGTM!The
part 'channel.dart';directive is correctly positioned and follows proper Dart syntax for library part declarations.tests/Base.php (1)
166-187: LGTM!The
CHANNEL_HELPER_RESPONSESconstant provides comprehensive test coverage for all Channel helper methods. The patterns are well-structured with:
- Wildcard patterns for defaults (e.g.,
databases.*.collections.*.documents.*)- Specific ID patterns (e.g.,
databases.db1.collections.col1.documents.doc1)- Action-specific patterns covering create, update, and delete operations
The inclusion of "tablesdb" patterns alongside "databases" suggests backwards compatibility support, which is appropriate.
tests/languages/android/Tests.kt (1)
10-10: LGTM!The Channel import is correctly added alongside other helper imports (Permission, Role, ID, Query, Operator).
tests/WebChromiumTest.php (1)
38-38: LGTM!The addition of
CHANNEL_HELPER_RESPONSESmaintains consistency with other test files and is positioned correctly in the expected output sequence.tests/FlutterStableTest.php (1)
34-34: LGTM!The addition of
CHANNEL_HELPER_RESPONSESfollows the same pattern as other test files and maintains proper ordering in the expected output array.tests/languages/web/index.html (2)
24-24: LGTM!Channel is correctly added to the destructured imports, positioned logically alongside other helper classes (Query, Permission, Role, ID, Operator).
322-342: LGTM! Excellent cross-platform test consistency.The Channel helper tests mirror the Android implementation exactly, testing all seven methods with identical arguments:
- database, tablesdb, account, files, executions, teams, memberships
- Each with default args, specific IDs, and action-suffixed variants
The test structure demonstrates excellent consistency across SDK platforms, which will make maintenance easier and ensure uniform behavior across client libraries.
…Channel helper tests from node and swift
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (2)
templates/apple/Sources/Channel.swift.twig (2)
13-19: Consider validating the action parameter.The documentation specifies that
actionshould be "create", "update", or "delete", but there's no validation to enforce this. While the server likely validates channel strings, client-side validation would provide better developer experience by failing fast with clear error messages rather than silently creating invalid subscriptions.🔎 View suggested validation approach:
You could add validation in each method, for example in the
databasemethod:public static func database(databaseId: String = "*", collectionId: String = "*", documentId: String = "*", action: String? = nil) -> String { + if let action = action, !["create", "update", "delete"].contains(action) { + preconditionFailure("Invalid action '\(action)'. Must be 'create', 'update', or 'delete'.") + } var channel = "databases.\(databaseId).collections.\(collectionId).documents.\(documentId)" if let action = action { channel += ".\(action)" } return channel }Apply similar validation to the other methods with action parameters.
Also applies to: 30-36, 56-62, 72-78, 87-93, 102-108
4-12: Consider using Swift-standard documentation syntax.The documentation uses
@paramand@returns, which are not standard Swift documentation markers. Swift documentation typically uses- Parameter(or- Parameters:) and- Returns:for better integration with Xcode and documentation generation tools like jazzy.🔎 Example with Swift-standard syntax:
/** * Generate a database channel string. * - * @param databaseId The database ID (default: "*") - * @param collectionId The collection ID (default: "*") - * @param documentId The document ID (default: "*") - * @param action Optional action: "create", "update", or "delete" (default: nil) - * @returns The channel string + * - Parameter databaseId: The database ID (default: "*") + * - Parameter collectionId: The collection ID (default: "*") + * - Parameter documentId: The document ID (default: "*") + * - Parameter action: Optional action: "create", "update", or "delete" (default: nil) + * - Returns: The channel string */Also applies to: 21-29, 38-43, 48-55, 64-71, 80-86, 95-101
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
templates/apple/Sources/Channel.swift.twig(1 hunks)templates/swift/Sources/WebSockets/WebSocketClient.swift.twig(7 hunks)templates/swift/Sources/WebSockets/WebSocketClientDelegate.swift.twig(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
- GitHub Check: build (8.3, Swift56)
- GitHub Check: build (8.3, Ruby31)
- GitHub Check: build (8.3, WebChromium)
- GitHub Check: build (8.3, WebNode)
- GitHub Check: apple (client)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, Ruby27)
- GitHub Check: build (8.3, Python311)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: kotlin (server)
- GitHub Check: build (8.3, KotlinJava8)
- GitHub Check: build (8.3, Node20)
- GitHub Check: android (client)
- GitHub Check: build (8.3, DotNet80)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: swift (server)
- GitHub Check: build (8.3, CLINode18)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, KotlinJava11)
🔇 Additional comments (4)
templates/swift/Sources/WebSockets/WebSocketClient.swift.twig (3)
35-43: Property type qualification is correct and thread-safe.The channel property and its backing field
_channelhave been consistently updated to useNIOCore.Channel?. The synchronized access pattern usingchannelQueueensures thread safety.
64-90: Callback storage updates are consistent and thread-safe.The callback storage for
onOpenandonClosehas been properly updated to useNIOCore.Channelin their function signatures. The synchronization using thelockerqueue ensures thread-safe access to the callback storage.
265-265: Internal method signatures correctly updated.The private methods
openChannelandupgradePipelineHandlerhave been updated to useNIOCore.Channel, maintaining internal consistency with the property types and callback signatures. The delegate call at line 302 will work correctly since the protocol has been updated accordingly.Also applies to: 293-293
templates/swift/Sources/WebSockets/WebSocketClientDelegate.swift.twig (1)
7-7: Consistent namespace qualification to prevent naming conflicts.The refactoring from
ChanneltoNIOCore.Channelis consistent across the protocol declaration and default extension implementations. NIO is an umbrella module exporting NIOCore, NIOEmbedded and NIOPosix, soNIOCore.Channelis accessible via the existingimport NIOon line 2. All four method signatures (lines 7, 10, 16, 22) are properly updated. This is a breaking change to the public API but necessary for avoiding type name collisions with new Channel helpers for realtime subscriptions.
693fe53 to
fd57b65
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
templates/apple/Sources/Services/Realtime.swift.twig (1)
254-254: QualifyChannelparameter asNIOCore.Channelin delegate method to avoid naming conflict.The
onOpen(channel: Channel)andonClose(channel: Channel, ...)delegate methods in Realtime.swift.twig (line 254+) use an unqualifiedChanneltype. Since Channel.swift.twig defines a newChannelhelper class for subscription channels, this creates ambiguity. The delegate parameter should explicitly useNIOCore.Channelto match the pattern in WebSocketClient.swift.twig (which consistently qualifies all Channel references asNIOCore.Channel), ensuring the correct network channel type is referenced and avoiding resolution to the subscription helper class.
🧹 Nitpick comments (10)
tests/Base.php (3)
283-290: Consider removing verbose debug logging before merging.The extensive
[LOG]statements throughout this method appear to be debug instrumentation. If these were added to troubleshoot specific CI issues, consider removing them before merging to keep test output clean, or wrap them in a conditional flag (e.g.,$verboseor environment variable check) if you want them available on-demand.
295-322: Duplicate build directory cleanup logic.The build directory is cleaned twice with identical logic (lines 295-300 and 317-322). If both cleanups are truly necessary to avoid PCH cache issues, consider extracting this into a helper method to reduce duplication.
🔎 Proposed refactor
+ private function cleanBuildDirectory(string $context = ''): void + { + $buildDir = __DIR__ . '/sdks/' . $this->language . '/.build'; + if (is_dir($buildDir)) { + echo "[LOG] Cleaning build directory{$context}: {$buildDir}\n"; + $this->rmdirRecursive($buildDir); + } + }Then replace both cleanup blocks with:
$this->cleanBuildDirectory(); // ... build commands ... $this->cleanBuildDirectory(' before test');
364-366: Minor: Usecount()for consistency.The file uses
count()everywhere else (lines 332, 341, 354, 363, 370, 371, 405), butsizeof()here. While functionally equivalent, prefercount()for consistency.- } while ($removed != 'Test Started' && sizeof($output) != 0); + } while ($removed != 'Test Started' && count($output) != 0);templates/flutter/lib/src/realtime_mixin.dart.twig (1)
171-177: Consider documenting expected channel types.The
_channelToStringhelper correctly converts channel values to strings. However, since the parameter isObject, any value could be passed at runtime (in Dart, type checking is not always enforced). Consider adding a doc comment explaining that channels should beStringor implementtoString()meaningfully.💡 Optional: Add documentation
+ /// Convert channel value to string. + /// Accepts String or Channel builder instances that implement toString(). String _channelToString(Object channel) { if (channel is String) { return channel; } return channel.toString(); }templates/web/src/services/realtime.ts.twig (2)
248-257: Simplify thechannelToStringhelper.The
toStringmethod exists on all JavaScript objects, making the explicit check on lines 253-254 and the fallback on line 256 redundant. The helper can be simplified.🔎 Suggested simplification
private channelToString(channel: string | ChannelValue): string { if (typeof channel === 'string') { return channel; } - // Channel builder instances have toString() method - if (channel && typeof channel.toString === 'function') { - return channel.toString(); - } - return String(channel); + return channel.toString(); }
266-269: Type signature mismatch with JSDoc.The JSDoc on line 262 states the parameter accepts "string or Channel builder instance", but the type signature only allows
ChannelValue. For consistency with the array overloads and the documentation, consider acceptingstring | ChannelValue.🔎 Proposed fix
public async subscribe( - channel: ChannelValue, + channel: string | ChannelValue, callback: (event: RealtimeResponseEvent<any>) => void ): Promise<RealtimeSubscription>;Apply the same change to the generic single-channel overload on line 291:
public async subscribe<T>( - channel: ChannelValue, + channel: string | ChannelValue, callback: (event: RealtimeResponseEvent<T>) => void ): Promise<RealtimeSubscription>;templates/android/library/src/main/java/io/package/Channel.kt.twig (1)
179-188: Consider consistency:accountreturnsStringwhile other methods return channel builders.The
account()method returns aStringdirectly, unlike other companion methods which return channel builder objects. This works but creates an inconsistent API surface. If intentional (since account has no sub-resources), consider adding a brief doc note explaining this difference.templates/apple/Sources/Channel.swift.twig (2)
46-64: Consider removing unused stored properties.The
databaseIdandcollectionIdproperties are stored but only used during initialization to constructbase. If they're not needed for future extensions, they could be removed to reduce memory footprint.🔎 Proposed refactor
public class CollectionChannel { private let base: String - private let databaseId: String - private let collectionId: String init(databaseId: String, collectionId: String) { - self.databaseId = databaseId - self.collectionId = collectionId self.base = "databases.\(databaseId).collections.\(collectionId)" }
192-200: Consider using Swift-style documentation comments.The current documentation uses Java-style
@param/@returnsannotations. Swift convention uses- Parameter:and- Returns:with triple-slash comments.🔎 Swift-idiomatic documentation example
- /** - * Generate a database channel builder. - * - * @param databaseId The database ID (default: "*") - * @returns DatabaseChannel - */ + /// Generate a database channel builder. + /// + /// - Parameter databaseId: The database ID (default: "*") + /// - Returns: A `DatabaseChannel` instance public static func database(_ databaseId: String = "*") -> DatabaseChannel {templates/flutter/lib/channel.dart.twig (1)
181-181: Consider ifChannelValuetype alias provides sufficient type safety.The
typedef ChannelValue = Objectis very broad and doesn't constrain what can be passed. While Dart lacks TypeScript's union types, you could consider a marker interface or sealed class if stronger type safety is desired. However, this matches the SDK's lightweight helper philosophy.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
src/SDK/Language/Flutter.php(2 hunks)templates/android/library/src/main/java/io/package/Channel.kt.twig(1 hunks)templates/android/library/src/main/java/io/package/services/Realtime.kt.twig(2 hunks)templates/apple/Sources/Channel.swift.twig(1 hunks)templates/apple/Sources/Services/Realtime.swift.twig(3 hunks)templates/flutter/lib/channel.dart.twig(1 hunks)templates/flutter/lib/src/realtime.dart.twig(1 hunks)templates/flutter/lib/src/realtime_base.dart.twig(1 hunks)templates/flutter/lib/src/realtime_browser.dart.twig(1 hunks)templates/flutter/lib/src/realtime_io.dart.twig(1 hunks)templates/flutter/lib/src/realtime_mixin.dart.twig(1 hunks)templates/web/src/channel.ts.twig(1 hunks)templates/web/src/client.ts.twig(3 hunks)templates/web/src/services/realtime.ts.twig(2 hunks)tests/Base.php(2 hunks)tests/languages/android/Tests.kt(2 hunks)tests/languages/apple/Tests.swift(1 hunks)tests/languages/flutter/tests.dart(1 hunks)tests/languages/web/index.html(2 hunks)tests/languages/web/node.js(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/languages/web/index.html
- src/SDK/Language/Flutter.php
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:30.593Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:14.446Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:14.446Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:14.446Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/flutter/lib/src/realtime_io.dart.twigtemplates/flutter/lib/src/realtime_mixin.dart.twigtemplates/web/src/client.ts.twigtemplates/android/library/src/main/java/io/package/services/Realtime.kt.twigtemplates/flutter/lib/src/realtime_base.dart.twigtemplates/flutter/lib/src/realtime.dart.twigtemplates/apple/Sources/Channel.swift.twigtests/languages/apple/Tests.swifttemplates/flutter/lib/channel.dart.twigtemplates/flutter/lib/src/realtime_browser.dart.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Services/Realtime.swift.twigtemplates/web/src/channel.ts.twigtemplates/web/src/services/realtime.ts.twig
📚 Learning: 2025-12-18T18:43:30.593Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:30.593Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
tests/languages/web/node.jstests/languages/flutter/tests.darttemplates/apple/Sources/Channel.swift.twigtests/languages/apple/Tests.swifttemplates/flutter/lib/channel.dart.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/web/src/channel.ts.twigtests/languages/android/Tests.kt
🧬 Code graph analysis (1)
tests/languages/android/Tests.kt (1)
tests/languages/kotlin/Tests.kt (1)
writeToFile(271-274)
🔇 Additional comments (36)
tests/languages/android/Tests.kt (2)
10-10: LGTM!The import for the new
Channelhelper class is correctly added alongside the existing helper imports.
273-293: Comprehensive Channel helper test coverage.The 20 test cases systematically exercise all Channel helper methods with appropriate variations:
- Default wildcards (e.g.,
Channel.database().collection().document())- Specific IDs (e.g.,
Channel.database("db1").collection("col1").document("doc1"))- Action methods (e.g.,
.create(),.update(),.delete())The fluent builder API is well-tested across
database,tablesdb,buckets,functions,teams, andmemberships, whileaccountcorrectly returns a String directly. Based on learnings, the design intentionally accepts IDs without validation, consistent with other SDK helpers like Query.tests/Base.php (1)
166-188: LGTM!The
CHANNEL_HELPER_RESPONSESconstant is well-structured with 20 entries covering all the channel helper patterns (databases, tables, buckets, functions, teams, memberships, account). The patterns follow a consistent naming convention and include variations with wildcards, specific IDs, and action suffixes.templates/flutter/lib/src/realtime_io.dart.twig (1)
46-48: LGTM! Signature broadened to support Channel builders.The method signature correctly accepts
List<Object>to support both string channels and Channel builder instances, delegating conversion logic to the mixin.tests/languages/flutter/tests.dart (1)
250-271: LGTM! Comprehensive Channel helper test coverage.The tests appropriately exercise the Channel builder API across all resource types (database, tablesdb, account, buckets, functions, teams, memberships) with various parameter combinations and action modifiers.
templates/flutter/lib/src/realtime_browser.dart.twig (1)
38-40: LGTM! Consistent signature update for browser platform.The signature change matches the IO platform implementation, correctly delegating to the mixin for channel conversion.
templates/flutter/lib/src/realtime_base.dart.twig (1)
6-6: LGTM! Abstract contract correctly broadened.The abstract method signature properly defines the contract for platform implementations to accept both string and Channel builder types.
tests/languages/apple/Tests.swift (1)
251-271: LGTM! Channel helper tests for Apple SDK.The tests comprehensively exercise the Channel builder API with appropriate coverage of all resource types and action variants. The previous concern about Channel class availability was addressed in commit 3f13cb1.
templates/flutter/lib/src/realtime.dart.twig (1)
45-53: LGTM! Clear documentation with practical Channel builder examples.The updated signature and documentation effectively demonstrate how to use Channel builders alongside traditional string channels. The examples are practical and show mixed usage patterns.
templates/web/src/client.ts.twig (1)
585-613: LGTM! Robust channel type normalization logic.The implementation correctly handles the union type
string | string[] | ChannelValue | ChannelValue[]by:
- Normalizing to array form
- Converting each channel to string via
toString()method orString()fallback- Maintaining internal consistency with string-based channel storage
The defensive
typeof ch.toString === 'function'check ensures safe handling of edge cases, and the documentation clearly demonstrates Channel builder usage.templates/flutter/lib/src/realtime_mixin.dart.twig (1)
179-201: LGTM! Clean channel type normalization in subscription logic.The implementation correctly:
- Accepts
List<Object>to support both strings and Channel builders- Normalizes all channels to strings using
_channelToString- Maintains string-based internal storage for consistency
- Uses
channelStringsthroughout for subscription tracking and cleanuptemplates/web/src/services/realtime.ts.twig (1)
311-317: LGTM!The implementation correctly normalizes input to an array, converts all channels to strings, and creates a Set for deduplication. The logic integrates well with the existing subscription management.
templates/android/library/src/main/java/io/package/Channel.kt.twig (3)
1-7: LGTM!The
ResolvedChannelwrapper is a clean approach for representing finalized channel strings with action suffixes.
9-25: LGTM!The
ActionChannelabstract class provides a clean abstraction for channels that support CRUD action suffixes. The pattern correctly separates the base channel path from action qualifiers.
27-54: LGTM!The database channel hierarchy correctly models the Appwrite resource structure with a fluent API:
Channel.database().collection().document().tests/languages/web/node.js (2)
1-1: LGTM!The
Channelimport is correctly added alongside other helper classes.
253-273: LGTM!Comprehensive test coverage for the Channel helper API. Tests verify:
- Default wildcard parameters
- Specific ID parameters
- Nested path construction (database → collection → document)
- Action methods (create, update, delete)
- All channel types (database, tablesdb, account, buckets, functions, teams, memberships)
templates/android/library/src/main/java/io/package/services/Realtime.kt.twig (2)
112-120: LGTM!The
channelToStringhelper is clean and idiomatic Kotlin. Using awhenexpression provides clear handling for String passthrough and fallback totoString()for other types.
122-150: LGTM!The new overloads correctly extend the API to accept channel builder objects while maintaining backward compatibility with existing String-based signatures. The delegation pattern keeps the implementation DRY.
templates/apple/Sources/Services/Realtime.swift.twig (3)
6-17: LGTM!The
ChannelValueprotocol is a clean Swift idiom for abstracting channel types. ExtendingStringto conform allows seamless backward compatibility with existing string-based API usage.
147-198: LGTM!The subscribe method overloads are well-structured:
channelToStringhelper encapsulates the conversion- Public API accepts
ChannelValuefor flexibility- Internal implementation uses
Set<String>for deduplication- All overloads correctly delegate to the core implementation
19-31: No action required. All channel types shown in the extensions already implement thetoString() -> Stringmethod inChannel.swift.twig, confirming the empty extensions toChannelValueprotocol are valid.templates/apple/Sources/Channel.swift.twig (4)
1-37: LGTM!The
ResolvedChannelwrapper andActionChannelbase class are well-structured. The use ofopen classforActionChannelappropriately allows subclassing, and the fluentcreate()/update()/delete()methods provide a clean API.
84-127: LGTM!The TablesDB hierarchy follows the same consistent builder pattern as the Database hierarchy. The implementation is correct and enables fluent channel construction like
Channel.tablesdb("db").table("tbl").row("*").create().
129-177: LGTM!The Buckets and Functions hierarchies are correctly implemented following the established builder pattern.
179-189: LGTM!Simple and correct implementation for team and membership channels as leaf-level builders.
templates/flutter/lib/channel.dart.twig (4)
1-34: LGTM!Clean Dart implementation of the base channel classes. Using
abstract classforActionChannelis appropriate, and the@overrideannotations ontoString()are correct since all Dart classes extendObject.
36-77: LGTM!The Database → Collection → Document hierarchy is well-implemented using Dart's initializer list syntax. The builder pattern enables fluent channel construction.
79-170: LGTM!Consistent implementation across all resource hierarchies (TablesDB, Buckets, Functions) following the established builder pattern.
183-239: LGTM!The
Channelfacade is well-implemented with proper Dart-style documentation comments. The static factory methods provide a clean public API for channel construction.templates/web/src/channel.ts.twig (6)
1-37: LGTM!The base channel classes are well-implemented.
ResolvedChannelis appropriately exported whileActionChannelremains internal. The empty lines at the start of the file (lines 1-2) appear intentional for template rendering.
39-81: LGTM!Good use of TypeScript's parameter property shorthand (
private databaseId: string). The non-exported classes provide proper encapsulation, forcing users to access them through theChannelfacade.
83-175: LGTM!Consistent implementation across TablesDB, Buckets, and Functions hierarchies. The builder pattern enables fluent construction like
Channel.tablesdb('db').table('tb').row('*').create().
177-187: LGTM!Simple and correct implementation for team and membership channels.
189-194: LGTM!The
ChannelValueunion type provides excellent compile-time type safety, allowing consumers to use any channel type or raw strings.
196-266: LGTM!The
Channelfacade provides a clean public API with well-documented static factory methods. The builder pattern implementation addresses the style requested in previous reviews, enabling fluent construction likeChannel.database('db').collection('col').document('doc').create().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
templates/flutter/lib/src/realtime_mixin.dart.twig (1)
179-201: Type broadening implemented correctly.The changes successfully broaden the API to accept
List<Object>channels and convert them consistently to strings for internal processing. The conversion is done upfront and applied uniformly throughout the subscription lifecycle.Optional: Remove redundant cast on line 181.
Since
_channelToStringreturnsString, the.map()operation already produces anIterable<String>, and.toList()yields aList<String>. The.cast<String>()call is redundant.🔎 Suggested simplification
- final channelStrings = channels.map((ch) => _channelToString(ch)).toList().cast<String>(); + final channelStrings = channels.map((ch) => _channelToString(ch)).toList();templates/apple/Sources/Services/Realtime.swift.twig (1)
147-152: Consider inlining or removing this helper.The
channelToStringmethod is a trivial wrapper aroundchannel.toString(). It could be inlined at call sites (e.g.,channels.map { $0.toString() }), reducing indirection. However, keeping it is acceptable if you prefer a single conversion point for maintainability.templates/web/src/client.ts.twig (1)
556-612: Well-implemented ChannelValue support in subscribe method.The implementation properly extends the subscribe method to accept both string and ChannelValue types, with clean normalization logic that converts Channel builder instances to strings via toString(). The fallback handling and documentation are appropriate.
💡 Optional: Extract channel normalization helper
The channel normalization logic (lines 588-596) could be extracted to a private helper method similar to the pattern used in templates/web/src/services/realtime.ts.twig (lines 248-257). This would improve consistency and reusability, though the current inline implementation is perfectly acceptable.
+ private channelToString(channel: string | ChannelValue): string { + if (typeof channel === 'string') { + return channel; + } + if (channel && typeof channel.toString === 'function') { + return channel.toString(); + } + return String(channel); + } + subscribe<T extends unknown>(channels: string | string[] | ChannelValue | ChannelValue[], callback: (payload: RealtimeResponseEvent<T>) => void): () => void { const channelArray = Array.isArray(channels) ? channels : [channels]; - // Convert Channel instances to strings - const channelStrings = channelArray.map(ch => { - if (typeof ch === 'string') { - return ch; - } - // Channel builder instances have toString() method - if (ch && typeof ch.toString === 'function') { - return ch.toString(); - } - return String(ch); - }); + const channelStrings = channelArray.map(ch => this.channelToString(ch));
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (19)
src/SDK/Language/Flutter.php(2 hunks)templates/android/library/src/main/java/io/package/Channel.kt.twig(1 hunks)templates/android/library/src/main/java/io/package/services/Realtime.kt.twig(2 hunks)templates/apple/Sources/Channel.swift.twig(1 hunks)templates/apple/Sources/Services/Realtime.swift.twig(3 hunks)templates/flutter/lib/channel.dart.twig(1 hunks)templates/flutter/lib/src/realtime.dart.twig(1 hunks)templates/flutter/lib/src/realtime_base.dart.twig(1 hunks)templates/flutter/lib/src/realtime_browser.dart.twig(1 hunks)templates/flutter/lib/src/realtime_io.dart.twig(1 hunks)templates/flutter/lib/src/realtime_mixin.dart.twig(1 hunks)templates/web/src/channel.ts.twig(1 hunks)templates/web/src/client.ts.twig(3 hunks)templates/web/src/services/realtime.ts.twig(2 hunks)tests/languages/android/Tests.kt(2 hunks)tests/languages/apple/Tests.swift(1 hunks)tests/languages/flutter/tests.dart(1 hunks)tests/languages/web/index.html(2 hunks)tests/languages/web/node.js(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- templates/flutter/lib/src/realtime_io.dart.twig
- templates/flutter/lib/src/realtime_base.dart.twig
- tests/languages/apple/Tests.swift
- src/SDK/Language/Flutter.php
- templates/web/src/channel.ts.twig
- templates/flutter/lib/channel.dart.twig
- templates/flutter/lib/src/realtime.dart.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:30.593Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:14.446Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:14.446Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:14.446Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/flutter/lib/src/realtime_browser.dart.twigtemplates/web/src/client.ts.twigtemplates/flutter/lib/src/realtime_mixin.dart.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/android/library/src/main/java/io/package/services/Realtime.kt.twigtemplates/web/src/services/realtime.ts.twigtemplates/apple/Sources/Services/Realtime.swift.twigtemplates/apple/Sources/Channel.swift.twig
📚 Learning: 2025-12-18T18:43:30.593Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:30.593Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
tests/languages/flutter/tests.darttests/languages/web/node.jstemplates/android/library/src/main/java/io/package/Channel.kt.twigtests/languages/web/index.htmltests/languages/android/Tests.kttemplates/apple/Sources/Channel.swift.twig
🧬 Code graph analysis (1)
tests/languages/android/Tests.kt (1)
tests/languages/kotlin/Tests.kt (1)
writeToFile(271-274)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: build (8.3, Swift56)
- GitHub Check: build (8.3, Go118)
- GitHub Check: build (8.3, Node20)
- GitHub Check: build (8.3, Node18)
- GitHub Check: build (8.3, Go112)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, KotlinJava8)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: build (8.3, CLINode18)
- GitHub Check: build (8.3, CLINode16)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: android (client)
- GitHub Check: swift (server)
- GitHub Check: apple (client)
🔇 Additional comments (25)
templates/flutter/lib/src/realtime_browser.dart.twig (1)
38-40: LGTM! Type broadening aligns with Channel helper support.The signature change from
List<String>toList<Object>allows this method to accept Channel helper objects alongside plain strings, which is the core objective of this PR. The delegation tosubscribeToremains unchanged.templates/flutter/lib/src/realtime_mixin.dart.twig (1)
171-177: LGTM! Clean conversion helper.The
_channelToStringhelper appropriately handles both string and non-string channel values by delegating to.toString()for Channel objects. This aligns with the established pattern for helper classes in this SDK.templates/android/library/src/main/java/io/package/services/Realtime.kt.twig (3)
112-120: LGTM! Clean channel conversion helper.The
channelToStringimplementation correctly handles both String and other channel types (like Channel helper objects). The String check is a good optimization to avoid unnecessarytoString()calls.As per learnings, no validation or escaping is performed on IDs, which aligns with the intentional design pattern across the SDK.
122-129: LGTM! Backward-compatible channel helper support.This overload cleanly enables developers to pass Channel helper objects (or other types) to
subscribe()while maintaining full backward compatibility. The delegation to the existing String-based implementation ensures consistent behavior.Kotlin's type resolution will prefer the
Stringoverload when strings are passed directly, and thisAnyoverload when Channel objects are used.
140-150: LGTM! Type-safe channel helper integration.This typed overload correctly extends the Channel helper support to include custom payload types while preserving type safety. The delegation pattern cleanly maps channels to strings and forwards to the existing typed implementation, properly returning the
RealtimeSubscriptionhandle.This allows developers to write type-safe subscriptions like:
realtime.subscribe( Channel.database("db123", "col456"), payloadType = MyDocument::class.java ) { event -> // event.payload is MyDocument }templates/apple/Sources/Services/Realtime.swift.twig (7)
6-11: LGTM!The
ChannelValueprotocol is clean and minimal. UsingtoString()rather than Swift'sCustomStringConvertibleis acceptable here for cross-SDK consistency.
13-17: LGTM!The
Stringextension ensures backward compatibility for existing callers passing string channels directly.
154-163: LGTM!The signature change to
ChannelValueis backward compatible, and the delegation logic is correct.
165-174: Breaking API change:Set<String>→[ChannelValue].Changing the parameter type from
Set<String>to[ChannelValue]is a breaking change for callers using theSettype. While migration is straightforward, this is worth noting in release documentation.The implementation correctly converts to
Set<String>internally, preserving deduplication behavior.
176-186: LGTM!The generic overload correctly handles the
ChannelValueparameter and delegates appropriately.
188-198: LGTM!This new overload completes the API surface, allowing multi-channel subscriptions with typed payloads using
ChannelValue. Implementation is consistent with other overloads.
19-31: No action required. All Channel types (ResolvedChannel,DatabaseChannel, etc.) already implement thetoString() -> Stringmethod in their base definitions, satisfying theChannelValueprotocol requirements. The empty extensions correctly declare protocol conformance.templates/apple/Sources/Channel.swift.twig (1)
1-261: LGTM! Well-structured Channel DSL for Swift.The implementation provides a clean, fluent API for constructing channel strings with proper type safety and default wildcard support. The class hierarchy (ResolvedChannel, ActionChannel, resource-specific channels) is well-organized and follows Swift conventions. Based on learnings, this intentionally follows the SDK pattern of accepting IDs as-is without validation or escaping.
tests/languages/flutter/tests.dart (1)
250-270: Excellent test coverage for Channel helpers.The Channel helper tests comprehensively exercise all factory methods (database, tablesdb, account, buckets, functions, teams, memberships) with various scenarios: default wildcards, specific IDs, nested builders, and action methods. Test patterns are consistent with other helper tests in the file.
tests/languages/web/index.html (2)
24-24: Import updated correctly.Channel properly added to the public API imports for testing.
322-342: Comprehensive Channel helper test coverage.Tests thoroughly exercise all Channel factory methods and builders with appropriate scenarios including default wildcards, specific IDs, nested chains, and action methods (create/update/delete). Coverage aligns with other language test implementations.
tests/languages/web/node.js (2)
1-1: Import correctly updated for Node.js.Channel added to CommonJS require imports.
253-273: Complete Channel helper test coverage.Node.js tests mirror the browser test coverage, ensuring Channel helpers work correctly in both environments. All factory methods and builder patterns are validated.
tests/languages/android/Tests.kt (2)
10-10: Import added correctly.Channel class imported for test usage.
273-293: Complete Channel helper test coverage.The 20 Channel helper test cases comprehensively cover all factory methods (database, tablesdb, account, buckets, functions, teams, memberships) with default wildcards, specific IDs, and actions. Coverage is consistent with other language implementations.
templates/web/src/client.ts.twig (1)
2-2: Import added correctly.ChannelValue imported for type support in subscribe method.
templates/android/library/src/main/java/io/package/Channel.kt.twig (1)
1-190: Excellent Kotlin Channel DSL implementation.The implementation provides a clean, idiomatic Kotlin API with proper use of default parameters, companion object for factory methods, and a well-organized class hierarchy. The design is consistent with other language implementations while following Kotlin best practices. Based on learnings, this correctly follows the SDK pattern of accepting IDs without validation or escaping.
templates/web/src/services/realtime.ts.twig (3)
2-2: Import added correctly.ChannelValue imported with proper relative path from service subdirectory.
241-257: Clean channel normalization helper.The channelToString helper method provides a clean, reusable way to normalize both string and ChannelValue inputs. The logic handles all cases appropriately with proper type checking and fallback.
259-348: Well-designed subscribe overloads with ChannelValue support.The implementation provides excellent type safety through multiple overloads, allowing users to pass single or multiple channels as either strings or Channel builder instances. The normalization logic (lines 311-317) cleanly converts all inputs to a Set for internal handling. Documentation is comprehensive and the use of the channelToString helper keeps the code maintainable.
93d0b02 to
3e2402d
Compare
| part of '{{ language.params.packageName }}.dart'; | ||
|
|
||
| class ResolvedChannel { | ||
| final String _value; | ||
|
|
||
| ResolvedChannel(this._value); | ||
|
|
||
| String toString() { | ||
| return _value; | ||
| } | ||
| } | ||
|
|
||
| abstract class ActionChannel { | ||
| final String base; | ||
|
|
||
| ActionChannel(this.base); | ||
|
|
||
| ResolvedChannel create() { | ||
| return ResolvedChannel('$base.create'); | ||
| } | ||
|
|
||
| ResolvedChannel update() { | ||
| return ResolvedChannel('$base.update'); | ||
| } | ||
|
|
||
| ResolvedChannel delete() { | ||
| return ResolvedChannel('$base.delete'); | ||
| } | ||
|
|
||
| @override | ||
| String toString() { | ||
| return base; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * ---------------------------- | ||
| * Database → Collection → Document | ||
| * ---------------------------- | ||
| */ | ||
| class DocumentChannel extends ActionChannel { | ||
| DocumentChannel(String base) : super(base); | ||
| } | ||
|
|
||
| class CollectionChannel { | ||
| final String base; | ||
| final String databaseId; | ||
| final String collectionId; | ||
|
|
||
| CollectionChannel(this.databaseId, this.collectionId) | ||
| : base = 'databases.$databaseId.collections.$collectionId'; | ||
|
|
||
| DocumentChannel document([String documentId = '*']) { | ||
| return DocumentChannel('$base.documents.$documentId'); | ||
| } | ||
|
|
||
| @override | ||
| String toString() { | ||
| return base; | ||
| } | ||
| } | ||
|
|
||
| class DatabaseChannel { | ||
| final String base; | ||
| final String databaseId; | ||
|
|
||
| DatabaseChannel(this.databaseId) : base = 'databases.$databaseId'; | ||
|
|
||
| CollectionChannel collection([String collectionId = '*']) { | ||
| return CollectionChannel(databaseId, collectionId); | ||
| } | ||
|
|
||
| @override | ||
| String toString() { | ||
| return base; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * ---------------------------- | ||
| * TablesDB → Table → Row | ||
| * ---------------------------- | ||
| */ | ||
| class RowChannel extends ActionChannel { | ||
| RowChannel(String base) : super(base); | ||
| } | ||
|
|
||
| class TableChannel { | ||
| final String base; | ||
| final String databaseId; | ||
| final String tableId; | ||
|
|
||
| TableChannel(this.databaseId, this.tableId) | ||
| : base = 'tablesdb.$databaseId.tables.$tableId'; | ||
|
|
||
| RowChannel row([String rowId = '*']) { | ||
| return RowChannel('$base.rows.$rowId'); | ||
| } | ||
|
|
||
| @override | ||
| String toString() { | ||
| return base; | ||
| } | ||
| } | ||
|
|
||
| class TablesDBChannel { | ||
| final String base; | ||
| final String databaseId; | ||
|
|
||
| TablesDBChannel(this.databaseId) : base = 'tablesdb.$databaseId'; | ||
|
|
||
| TableChannel table([String tableId = '*']) { | ||
| return TableChannel(databaseId, tableId); | ||
| } | ||
|
|
||
| @override | ||
| String toString() { | ||
| return base; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * ---------------------------- | ||
| * Buckets → File | ||
| * ---------------------------- | ||
| */ | ||
| class FileChannel extends ActionChannel { | ||
| FileChannel(String base) : super(base); | ||
| } | ||
|
|
||
| class BucketChannel { | ||
| final String base; | ||
| final String bucketId; | ||
|
|
||
| BucketChannel(this.bucketId) : base = 'buckets.$bucketId'; | ||
|
|
||
| FileChannel file([String fileId = '*']) { | ||
| return FileChannel('$base.files.$fileId'); | ||
| } | ||
|
|
||
| @override | ||
| String toString() { | ||
| return base; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * ---------------------------- | ||
| * Functions → Execution | ||
| * ---------------------------- | ||
| */ | ||
| class ExecutionChannel extends ActionChannel { | ||
| ExecutionChannel(String base) : super(base); | ||
| } | ||
|
|
||
| class FunctionChannel { | ||
| final String base; | ||
| final String functionId; | ||
|
|
||
| FunctionChannel(this.functionId) : base = 'functions.$functionId'; | ||
|
|
||
| ExecutionChannel execution([String executionId = '*']) { | ||
| return ExecutionChannel('$base.executions.$executionId'); | ||
| } | ||
|
|
||
| @override | ||
| String toString() { | ||
| return base; | ||
| } | ||
| } | ||
|
|
||
| class TeamChannel extends ActionChannel { | ||
| TeamChannel([String teamId = '*']) : super('teams.$teamId'); | ||
| } | ||
|
|
||
| class MembershipChannel extends ActionChannel { | ||
| MembershipChannel([String membershipId = '*']) | ||
| : super('memberships.$membershipId'); | ||
| } | ||
|
|
||
| typedef ChannelValue = Object; | ||
|
|
||
| class Channel { | ||
| /// Generate a database channel builder. | ||
| /// | ||
| /// [databaseId] The database ID (default: "*") | ||
| /// Returns [DatabaseChannel] | ||
| static DatabaseChannel database([String databaseId = '*']) { | ||
| return DatabaseChannel(databaseId); | ||
| } | ||
|
|
||
| /// Generate a tables database channel builder. | ||
| /// | ||
| /// [databaseId] The database ID (default: "*") | ||
| /// Returns [TablesDBChannel] | ||
| static TablesDBChannel tablesdb([String databaseId = '*']) { | ||
| return TablesDBChannel(databaseId); | ||
| } | ||
|
|
||
| /// Generate a buckets channel builder. | ||
| /// | ||
| /// [bucketId] The bucket ID (default: "*") | ||
| /// Returns [BucketChannel] | ||
| static BucketChannel buckets([String bucketId = '*']) { | ||
| return BucketChannel(bucketId); | ||
| } | ||
|
|
||
| /// Generate a functions channel builder. | ||
| /// | ||
| /// [functionId] The function ID (default: "*") | ||
| /// Returns [FunctionChannel] | ||
| static FunctionChannel functions([String functionId = '*']) { | ||
| return FunctionChannel(functionId); | ||
| } | ||
|
|
||
| /// Generate a teams channel builder. | ||
| /// | ||
| /// [teamId] The team ID (default: "*") | ||
| /// Returns [TeamChannel] | ||
| static TeamChannel teams([String teamId = '*']) { | ||
| return TeamChannel(teamId); | ||
| } | ||
|
|
||
| /// Generate a memberships channel builder. | ||
| /// | ||
| /// [membershipId] The membership ID (default: "*") | ||
| /// Returns [MembershipChannel] | ||
| static MembershipChannel memberships([String membershipId = '*']) { | ||
| return MembershipChannel(membershipId); | ||
| } | ||
|
|
||
| /// Generate an account channel string. | ||
| /// | ||
| /// [userId] The user ID (default: "*") | ||
| /// Returns The channel string | ||
| static String account([String userId = '*']) { | ||
| return 'account.$userId'; | ||
| } | ||
| } No newline at end of file |
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.
It was interesting to look at the PR, and I noticed signs of Class Explosion and a violation of the DRY principle.
I propose a version with a single Builder and a system of interface constraints. It preserves strict typing of calls, ridding the project of unnecessary classes and duplication of logic.
part of appwrite_channel;
// The result of building the channel.
final class ResolvedChannel {
final String value;
const ResolvedChannel(this.value);
@override
String toString() => value;
}
// Helper function for normalizing ID
String _normalize(String id) => id.trim().isEmpty ? '*' : id;
// State interfaces
abstract interface class Actionable {
ResolvedChannel create();
ResolvedChannel update();
ResolvedChannel delete();
String get channel;
}
abstract interface class IDatabase {
ICollection collection([String id = '*']);
}
abstract interface class ICollection {
IDocument document([String id = '*']);
}
abstract interface class IDocument implements Actionable {}
abstract interface class ITablesDB {
ITable table([String id = '*']);
}
abstract interface class ITable {
IRow row([String id = '*']);
}
abstract interface class IRow implements Actionable {}
abstract interface class IBucket {
IFile file([String id = '*']);
}
abstract interface class IFile implements Actionable {}
abstract interface class IFunction {
IExecution execution([String id = '*']);
}
abstract interface class IExecution implements Actionable {}
// Builder implementation
class _ChannelBuilder implements
IDatabase, ICollection, IDocument,
ITablesDB, ITable, IRow,
IBucket, IFile,
IFunction, IExecution, Actionable {
final List<String> _segments;
_ChannelBuilder._(this._segments);
_ChannelBuilder _next(String segment, String id) {
return _ChannelBuilder._([
..._segments,
segment,
_normalize(id),
]);
}
@override
ICollection collection([String id = '*']) => _next('collections', id);
@override
IDocument document([String id = '*']) => _next('documents', id);
@override
ITable table([String id = '*']) => _next('tables', id);
@override
IRow row([String id = '*']) => _next('rows', id);
@override
IFile file([String id = '*']) => _next('files', id);
@override
IExecution execution([String id = '*']) => _next('executions', id);
@override
ResolvedChannel create() => _resolve('create');
@override
ResolvedChannel update() => _resolve('update');
@override
ResolvedChannel delete() => _resolve('delete');
@override
String get channel => _segments.join('.');
@override
String toString() => channel;
ResolvedChannel _resolve(String action) => ResolvedChannel('$channel.$action');
}
// Entry point
abstract final class Channel {
static IDatabase database([String id = '*']) =>
_ChannelBuilder._(['databases', _normalize(id)]);
static ITablesDB tablesdb([String id = '*']) =>
_ChannelBuilder._(['tablesdb', _normalize(id)]);
static IBucket buckets([String id = '*']) =>
_ChannelBuilder._(['buckets', _normalize(id)]);
static IFunction functions([String id = '*']) =>
_ChannelBuilder._(['functions', _normalize(id)]);
static Actionable teams([String id = '*']) =>
_ChannelBuilder._(['teams', _normalize(id)]);
static Actionable memberships([String id = '*']) =>
_ChannelBuilder._(['memberships', _normalize(id)]);
static String account([String userId = '']) =>
userId.isEmpty ? 'account' : 'account.${_normalize(userId)}';
// Global events (without ID)
static String get documents => 'documents';
static String get rows => 'rows';
static String get files => 'files';
static String get executions => 'executions';
}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.
Thanks for the suggestion. It really makes sense. Will surely apply this
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.
Glad it helped,
I also looked at the classes, and there is no single builder used for Kotlin and Swift.
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.
Glad it helped, I also looked at the classes, and there is no single builder used for Kotlin and Swift.
I just pushed swift and kotlin channel builder. Should be good now I think, waiting for the tests
…lates - Removed deprecated channel types and streamlined channel value handling in Realtime service. - Introduced Actionable and ResolvedChannel interfaces for better type safety. - Updated database, tablesdb, buckets, functions, teams, and memberships channel builders to use new interfaces. - Enhanced test cases to reflect changes in channel creation and subscription methods. - Improved documentation for channel subscription methods to clarify expected types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (4)
templates/apple/Sources/Services/Realtime.swift.twig (1)
136-153: Consider simplifying the channel conversion logic.The explicit check for
ResolvedChannelat lines 148-150 appears redundant. SinceResolvedChannelconforms toChannelValue, callingchannel.toString()in the fallback (line 152) would produce the same result.The code could be simplified to:
private func channelToString(_ channel: ChannelValue) -> String { // Check if it's an Actionable instance (has channel property) if let actionable = channel as? Actionable { return actionable.channel } // Use toString() for all ChannelValue types return channel.toString() }This eliminates the redundant branch while maintaining the special handling for
Actionabletypes.templates/flutter/lib/src/realtime_mixin.dart.twig (1)
171-185: Redundant type check and cast.The check
if (channel is ResolvedChannel)on line 181 is redundant because line 184 already handles this case viachannel.toString(). All Dart objects have atoString()method, so ResolvedChannel will be handled correctly by the fallback.Additionally, the
.cast<String>()on line 189 is unnecessary sincemap((ch) => _channelToString(ch))already returnsIterable<String>, andtoList()preserves that type.🔎 Suggested simplification
/// Convert channel value to string String _channelToString(Object channel) { if (channel is String) { return channel; } // Check if it's an Actionable instance (has channel getter) if (channel is Actionable) { return channel.channel; } - // Check if it's a ResolvedChannel (has toString() method) - if (channel is ResolvedChannel) { - return channel.toString(); - } return channel.toString(); } RealtimeSubscription subscribeTo(List<Object> channels) { StreamController<RealtimeMessage> controller = StreamController.broadcast(); - final channelStrings = channels.map((ch) => _channelToString(ch)).toList().cast<String>(); + final channelStrings = channels.map((ch) => _channelToString(ch)).toList();templates/web/src/client.ts.twig (1)
585-601: Redundant type check fortoString.The check on line 597
typeof (ch as ResolvedChannel).toString === 'function'is always true since all JavaScript objects inherittoStringfromObject.prototype. This branch will handle all non-string, non-Actionable inputs, making theString(ch)fallback on line 600 unreachable.Consider simplifying by removing the redundant check:
🔎 Suggested simplification
const channelStrings = channelArray.map(ch => { if (typeof ch === 'string') { return ch; } // Check if it's an Actionable instance (has channel() method) if (ch && typeof (ch as Actionable).channel === 'function') { return (ch as Actionable).channel(); } - // Check if it's a ResolvedChannel (has toString() method) - if (ch && typeof (ch as ResolvedChannel).toString === 'function') { - return (ch as ResolvedChannel).toString(); - } - return String(ch); + return ch.toString(); });templates/web/src/services/realtime.ts.twig (1)
248-261: Same redundanttoStringcheck as in client.ts.Lines 256-259 check for
toStringmethod existence, but all objects have this method. The check will always pass, making line 260'sString(channel)unreachable.🔎 Suggested simplification
private channelToString(channel: string | Actionable | ResolvedChannel): string { if (typeof channel === 'string') { return channel; } // Check if it's an Actionable instance (has channel() method) if (channel && typeof (channel as Actionable).channel === 'function') { return (channel as Actionable).channel(); } - // Check if it's a ResolvedChannel (has toString() method) - if (channel && typeof (channel as ResolvedChannel).toString === 'function') { - return (channel as ResolvedChannel).toString(); - } - return String(channel); + return channel.toString(); }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/android/library/src/main/java/io/package/services/Realtime.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/apple/Sources/Services/Realtime.swift.twigtemplates/dart/test/channel_test.dart.twigtemplates/flutter/lib/channel.dart.twigtemplates/flutter/lib/src/realtime.dart.twigtemplates/flutter/lib/src/realtime_base.dart.twigtemplates/flutter/lib/src/realtime_mixin.dart.twigtemplates/react-native/src/channel.ts.twigtemplates/web/src/channel.ts.twigtemplates/web/src/client.ts.twigtemplates/web/src/services/realtime.ts.twig
🚧 Files skipped from review as they are similar to previous changes (2)
- templates/dart/test/channel_test.dart.twig
- templates/android/library/src/main/java/io/package/services/Realtime.kt.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/flutter/lib/src/realtime_mixin.dart.twigtemplates/flutter/lib/src/realtime_base.dart.twigtemplates/web/src/client.ts.twigtemplates/flutter/lib/src/realtime.dart.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/flutter/lib/channel.dart.twigtemplates/react-native/src/channel.ts.twigtemplates/apple/Sources/Services/Realtime.swift.twigtemplates/web/src/services/realtime.ts.twigtemplates/web/src/channel.ts.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/flutter/lib/channel.dart.twigtemplates/react-native/src/channel.ts.twigtemplates/web/src/channel.ts.twig
🔇 Additional comments (18)
templates/apple/Sources/Services/Realtime.swift.twig (3)
6-17: LGTM! Clean abstraction for channel types.The ChannelValue protocol provides a simple, extensible contract for channel representation. String conformance ensures backward compatibility, allowing existing code using String channels to work seamlessly with the new API.
19-20: ResolvedChannel and ActionChannel correctly implement the required ChannelValue protocol.Both types already define
toString() -> Stringmethods in Channel.swift.twig (ResolvedChannel at lines 11-13, ActionChannel at lines 54-56), making the empty protocol conformance extensions valid.
155-199: LGTM! Well-structured API expansion with backward compatibility.The subscribe overloads correctly accept
ChannelValuetypes while maintaining internalSet<String>logic. Key strengths:
- Backward compatible: Existing String-based calls continue to work seamlessly
- Consistent pattern: All overloads convert ChannelValue → String via
channelToStringbefore forwarding- Complete API surface: New
channels: [ChannelValue], payloadType:overload (lines 189-199) fills a gap in the generic API- Properly typed:
Actionableprotocol is correctly defined in Channel.swift.twig with the.channelproperty, ensuring type-safe conversionsThe clean separation between the public ChannelValue-based interface and internal String-based storage ensures no breaking changes.
templates/flutter/lib/src/realtime.dart.twig (1)
45-53: LGTM!The updated documentation with Channel builder examples is clear and helpful. The API change from
List<String>toList<Object>maintains backward compatibility since strings are still accepted, while enabling the new Channel builder pattern.templates/flutter/lib/src/realtime_base.dart.twig (1)
4-6: LGTM!The signature change is consistent with the parent
Realtimeclass interface.templates/web/src/client.ts.twig (1)
575-582: Good documentation addition.The Channel builder examples in the JSDoc are clear and demonstrate the various builder patterns available.
templates/android/library/src/main/java/io/package/Channel.kt.twig (1)
1-196: Well-structured Channel DSL for Android/Kotlin.The implementation provides good type safety with separate classes for each hierarchy level. The
ActionChannelbase class effectively reduces duplication for action methods. Thenormalizehelper correctly handles empty/whitespace IDs by defaulting to"*".Note: The Flutter implementation (in
channel.dart.twig) uses a single_ChannelBuilderclass with interfaces, which is more compact. Both approaches are valid - this one trades more classes for clearer static typing at each builder step.templates/flutter/lib/channel.dart.twig (2)
131-132: Consider edge case for whitespace-only userId.The
accountmethod checksuserId.isEmptybut if a user passes whitespace like" ", it won't be considered empty and will result inaccount.*(after normalization). This differs from other entry points where the ID is normalized first.Is this the intended behavior? If consistency is desired:
🔎 Potential fix for consistency
static String account([String userId = '']) => - userId.isEmpty ? 'account' : 'account.${_normalize(userId)}'; + userId.trim().isEmpty ? 'account' : 'account.${_normalize(userId)}';
58-108: Well-implemented consolidated builder pattern.The
_ChannelBuilderclass implementing all interfaces via a segment list is clean and follows DRY principles. This addresses the "class explosion" concern raised in the past review discussion.templates/web/src/services/realtime.ts.twig (1)
311-321: LGTM!The subscribe implementation correctly normalizes mixed channel types to a
Set<string>before registering with the subscription system.templates/react-native/src/channel.ts.twig (1)
1-195: LGTM - consistent Channel builder implementation.The React Native implementation follows the same consolidated builder pattern as Flutter, with a single
ChannelBuilderclass implementing all level interfaces. Theaccount()method correctly handles whitespace withtrim()check (line 173), which is consistent with how other platforms should behave.Minor note: The file has unusual indentation (extra leading spaces on most lines), which may be a template formatting artifact.
templates/web/src/channel.ts.twig (3)
1-13: LGTM! Clean foundation utilities.The
ResolvedChannelwrapper andnormalizehelper are well-implemented. The immutable design ofResolvedChanneland the whitespace-to-wildcard normalization logic are both sound.
17-54: LGTM! Well-structured type-safe interfaces.The interface hierarchy correctly models the resource relationships and ensures type-safe chaining. The separation of concerns between chainable interfaces and the
Actionableinterface for terminal operations is clean.
58-143: LGTM! Solid builder implementation.The immutable builder pattern with
next()creating new instances is a good design choice. The approach of havingChannelBuilderimplement all interfaces works well in TypeScript's structural type system, keeping the implementation DRY while the interface types enforce correct usage at the API boundary.templates/apple/Sources/Channel.swift.twig (4)
1-20: LGTM! Solid foundation matching TypeScript implementation.The
ResolvedChannelandnormalizeutilities correctly mirror the TypeScript implementation. The immutability ofResolvedChanneland the whitespace normalization logic are both sound.Based on learnings, the lack of ID validation is intentional design for SDK helper utilities.
23-57: LGTM! Appropriate Swift design pattern.The
Actionableprotocol withActionChannelbase class is a clean Swift pattern that provides code reuse while maintaining type safety. This is a good language-specific adaptation compared to the TypeScript interface-based approach.
59-199: LGTM! Consistent and well-structured channel hierarchy.All resource-specific channel classes follow a consistent pattern:
- Intermediate builders (CollectionChannel, TableChannel, BucketChannel, FunctionChannel) provide chaining methods
- Terminal channels (DocumentChannel, RowChannel, FileChannel, ExecutionChannel, TeamChannel, MembershipChannel) extend
ActionChannelfor CRUD actions- Each class properly normalizes IDs and constructs correct dot-delimited channel paths
The verbose class-per-resource approach is appropriate for Swift's type system and provides excellent type safety. The channel strings generated match the TypeScript implementation (except for the account method, flagged separately).
236-239: LGTM! Global event constants match TypeScript implementation.The static constants for global events (
documents,rows,files,executions) are consistent with the TypeScript implementation and provide a clean API for subscribing to global resource events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
templates/flutter/lib/channel.dart.twig (1)
112-138: Clean public API with appropriate type guidance.The
Channelclass provides intuitive static entry points that return typed interfaces guiding users through valid builder chains. The distinction between structured resources (database, buckets, etc.) returning builders and simpler resources (account, global events) returning strings directly makes sense given their different structures.Optional: More idiomatic Dart pattern
While the abstract class with static members works correctly, a more idiomatic Dart pattern would use a private constructor to prevent instantiation:
-abstract class Channel { +class Channel { + // Private constructor prevents instantiation + Channel._(); + static IDatabase database([String id = '*']) => _ChannelBuilder._(['databases', _normalize(id)]); // ... rest of static methodsThis is purely stylistic and doesn't affect functionality.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
templates/flutter/lib/channel.dart.twigtemplates/flutter/lib/src/realtime_mixin.dart.twigtests/Base.php
🚧 Files skipped from review as they are similar to previous changes (1)
- templates/flutter/lib/src/realtime_mixin.dart.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/flutter/lib/channel.dart.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
templates/flutter/lib/channel.dart.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: swift (server)
- GitHub Check: dart (server)
- GitHub Check: kotlin (server)
- GitHub Check: react-native (client)
- GitHub Check: php (server)
- GitHub Check: node (server)
- GitHub Check: android (client)
- GitHub Check: build (8.3, CLINode18)
- GitHub Check: build (8.3, WebChromium)
- GitHub Check: build (8.3, Ruby31)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, CLINode20)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, DotNet60)
- GitHub Check: build (8.3, Swift56)
- GitHub Check: build (8.3, Ruby30)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, KotlinJava11)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, Android14Java17)
🔇 Additional comments (4)
tests/Base.php (1)
166-187: LGTM! Comprehensive test data for channel helpers.The
CHANNEL_HELPER_RESPONSESconstant provides thorough coverage of channel patterns across different resource types (databases, tablesdb, account, buckets, functions, teams, memberships) with wildcards, specific IDs, and action variants. The patterns correctly follow the dot-notation format expected by Appwrite realtime channels.templates/flutter/lib/channel.dart.twig (3)
3-13: Well-designed value types and normalization.The
ResolvedChannelwrapper provides semantic distinction for channels with actions, and the_normalizehelper correctly implements the minimal ID transformation pattern (empty → '*'). Based on learnings, the lack of ID validation or escaping is intentional across SDK helpers.
17-54: Excellent use of interfaces for type-safe fluent API.The interface hierarchy enforces valid call sequences at compile time while avoiding class explosion. Each interface exposes only the appropriate next steps in the builder chain, with terminal types implementing
Actionableto provide action methods and channel access. This directly addresses the previous review feedback.
58-108: Solid single-builder implementation addressing previous feedback.The
_ChannelBuilderclass elegantly implements all interfaces while maintaining type safety through return types. The immutable segment list and_next()pattern prevent accidental mutations. This design directly implements the suggestion from the previous review to use "a single Builder and a system of interface constraints" rather than multiple classes, successfully avoiding class explosion while preserving strict typing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
templates/flutter/lib/src/realtime_mixin.dart.twig (1)
194-194: Remove redundant cast operation.The
.cast<String>()is unnecessary sincemap(_channelToString)already producesList<String>after.toList().🔎 Simplified implementation
- final channelStrings = channels.map((ch) => _channelToString(ch)).toList().cast<String>(); + final channelStrings = channels.map((ch) => _channelToString(ch)).toList();
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
templates/flutter/lib/src/realtime_mixin.dart.twig
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/flutter/lib/src/realtime_mixin.dart.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
- GitHub Check: build (8.3, WebChromium)
- GitHub Check: build (8.3, KotlinJava11)
- GitHub Check: build (8.3, Ruby31)
- GitHub Check: build (8.3, Node16)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, Python39)
- GitHub Check: build (8.3, Node20)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, DartBeta)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: flutter (client)
- GitHub Check: kotlin (server)
- GitHub Check: android (client)
- GitHub Check: swift (server)
- GitHub Check: apple (client)
🔇 Additional comments (3)
templates/flutter/lib/src/realtime_mixin.dart.twig (3)
171-190: LGTM! Dynamic channel conversion implementation is appropriate.The three-tier approach (String → Actionable interface → toString fallback) correctly handles multiple channel representations. The dynamic property access avoids import conflicts with part file types, which is a pragmatic solution given Dart's part/library constraints.
192-192: LGTM! Backward-compatible signature change.Broadening the parameter type from
List<String>toList<Object>enables Channel helper objects while maintaining backward compatibility with existing string-based callers.
195-204: LGTM! Consistent use of normalized channel strings.The normalized
channelStringsare used consistently throughout the method, ensuring type safety for internal storage, subscription creation, and cleanup operations.
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
♻️ Duplicate comments (1)
templates/apple/Sources/Channel.swift.twig (1)
151-154: Cross-platform API inconsistency with TypeScript implementation remains.This was flagged in a previous review: when
userIdis empty or whitespace (normalized to"*"), Swift returns"account"while TypeScript returns"account.*". Please coordinate with the Web SDK to align behavior.
🧹 Nitpick comments (1)
templates/apple/Sources/Channel.swift.twig (1)
4-14: Consider conforming toCustomStringConvertiblefor Swift idiom.The
toString()method works, but Swift convention prefersCustomStringConvertibleconformance with adescriptionproperty. This allowsResolvedChannelto work naturally with string interpolation and print statements.🔎 Suggested enhancement (optional)
-public final class ResolvedChannel { +public final class ResolvedChannel: CustomStringConvertible { private let value: String init(value: String) { self.value = value } public func toString() -> String { value } + + public var description: String { + value + } }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twig
🚧 Files skipped from review as they are similar to previous changes (1)
- templates/android/library/src/main/java/io/package/Channel.kt.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/apple/Sources/Channel.swift.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
templates/apple/Sources/Channel.swift.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
- GitHub Check: build (8.3, Go118)
- GitHub Check: build (8.3, Python311)
- GitHub Check: build (8.3, KotlinJava11)
- GitHub Check: build (8.3, Ruby30)
- GitHub Check: build (8.3, Python39)
- GitHub Check: build (8.3, Python312)
- GitHub Check: build (8.3, PHP83)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, Node16)
- GitHub Check: build (8.3, DartBeta)
- GitHub Check: build (8.3, Python313)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: apple (client)
- GitHub Check: swift (server)
- GitHub Check: android (client)
🔇 Additional comments (3)
templates/apple/Sources/Channel.swift.twig (3)
16-20: LGTM!The normalize function correctly handles trimming and defaults empty/whitespace-only inputs to
"*".
22-60: LGTM!The protocol hierarchy is well-designed, enabling type-safe fluent chaining for channel construction. The separation between navigation protocols (IDatabase, ICollection, etc.) and terminal actionable protocols (IDocument, IRow, IFile, IExecution) is clean.
125-149: LGTM!The public API is well-designed with appropriate return types that hide the internal
ChannelBuilderimplementation. The static factory methods provide a clean entry point for channel construction, and the global event constants are appropriately defined.Also applies to: 156-161
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)
templates/apple/Sources/Channel.swift.twig (1)
208-211: Cross-platform inconsistency: account() behavior still differs from TypeScript.The
account()method continues to return"account"when the normalized input is"*", while the TypeScript implementation returns"account.*". This creates inconsistent channel strings across SDKs:
- Swift:
Channel.account("*")→"account"- TypeScript:
Channel.account("*")→"account.*"This was flagged as critical in a previous review and remains unresolved.
Based on the previous review thread, the expected fix is to return
"account.*"when the normalized ID is"*", aligning with the Web SDK behavior.
🧹 Nitpick comments (2)
tests/AppleSwift56Test.php (2)
138-154: Consider adding error handling for filesystem operations.The
rmdirRecursive()implementation is correct, but filesystem operations likeunlink(),rmdir(), andscandir()can fail due to permission issues or other errors. Consider wrapping these operations in a try-catch block and logging or throwing exceptions on failure to make debugging easier if cleanup fails.🔎 Proposed enhancement with error handling
private function rmdirRecursive($dir): void { if (!\is_dir($dir)) { return; } - foreach (\scandir($dir) as $file) { - if ('.' === $file || '..' === $file) { - continue; - } - if (\is_dir("$dir/$file")) { - $this->rmdirRecursive("$dir/$file"); - } else { - \unlink("$dir/$file"); + try { + foreach (\scandir($dir) as $file) { + if ('.' === $file || '..' === $file) { + continue; + } + if (\is_dir("$dir/$file")) { + $this->rmdirRecursive("$dir/$file"); + } else { + \unlink("$dir/$file"); + } } + \rmdir($dir); + } catch (\Exception $e) { + echo "Warning: Failed to remove directory $dir: " . $e->getMessage() . "\n"; } - \rmdir($dir); }
38-136: Consider refactoring this method to improve maintainability.The
testHTTPSuccess()method handles multiple distinct responsibilities sequentially:
- SDK setup and configuration (lines 43-69)
- Directory cleanup and generation (lines 71-75)
- Building (lines 77-83)
- Test execution and output capture (lines 85-97)
- Output validation (lines 99-135)
While the enhanced logging for debugging is valuable, extracting helper methods like
setupSdk(),buildSdk(),captureTestOutput(), andvalidateTestOutput()would improve readability and testability.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
templates/apple/Sources/Channel.swift.twigtemplates/apple/Sources/Services/Realtime.swift.twigtests/AppleSwift56Test.php
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/apple/Sources/Services/Realtime.swift.twigtemplates/apple/Sources/Channel.swift.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
templates/apple/Sources/Channel.swift.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
- GitHub Check: build (8.3, Ruby31)
- GitHub Check: node (server)
- GitHub Check: swift (server)
- GitHub Check: build (8.3, Python313)
- GitHub Check: build (8.3, WebChromium)
- GitHub Check: build (8.3, Swift56)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, Node18)
- GitHub Check: cli (console)
- GitHub Check: flutter (client)
- GitHub Check: build (8.3, Python39)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, DotNet80)
- GitHub Check: android (client)
- GitHub Check: react-native (client)
- GitHub Check: build (8.3, Android5Java17)
🔇 Additional comments (6)
tests/AppleSwift56Test.php (2)
19-19: LGTM! Improved error capture.The addition of
2>&1to capture both stdout and stderr is a good improvement for debugging compilation errors during SDK testing.
34-34: Addition of CHANNEL_HELPER_RESPONSES is correct and complete.The constant
Base::CHANNEL_HELPER_RESPONSESis properly defined in the Base test class, and AppleSwift56Test.php correctly includes it alongside other platform test files that support channel helpers (Web, Flutter, and Android). No additional updates are required.templates/apple/Sources/Channel.swift.twig (1)
169-179: LGTM! Thevalue:argument label fix has been applied.The ResolvedChannel initializations now correctly include the
value:argument label, resolving the compilation error flagged in the previous review.templates/apple/Sources/Services/Realtime.swift.twig (3)
120-125: LGTM! Clean abstraction for channel conversion.The
channelToStringhelper provides a clear conversion point from the publicChannelValueprotocol to the internalStringrepresentation used by the WebSocket layer.
161-171: Good addition: typed multi-channel subscription with ChannelValue.This new overload completes the API surface by allowing subscriptions to multiple channels with a specific payload type using
ChannelValue. The conversion from[ChannelValue]toSet<String>is consistent with other overloads and properly removes duplicates.
227-227: LGTM! Explicit NIO.Channel qualification avoids naming conflict.The explicit
NIO.Channelqualification prevents ambiguity with the newChannelhelper enum for realtime subscriptions. This is the same type, just explicitly scoped.Based on learnings, this qualification pattern is intentional to avoid naming collisions.
templates/android/library/src/main/java/io/package/Channel.kt.twig
Outdated
Show resolved
Hide resolved
templates/android/library/src/main/java/io/package/Channel.kt.twig
Outdated
Show resolved
Hide resolved
templates/android/library/src/main/java/io/package/services/Realtime.kt.twig
Outdated
Show resolved
Hide resolved
templates/android/library/src/main/java/io/package/Channel.kt.twig
Outdated
Show resolved
Hide resolved
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
🤖 Fix all issues with AI agents
In @templates/web/src/client.ts.twig:
- Around line 588-601: The current type-guard in the channelArray ->
channelStrings mapping wrongly treats any object as ResolvedChannel because
every object has toString; update the checks so ResolvedChannel is detected
before generic toString and avoid relying on Object.prototype.toString:
specifically, in the map that builds channelStrings, check for ResolvedChannel
first using a robust test (e.g., instanceof ResolvedChannel or a unique
property/method that only ResolvedChannel exposes) and only then fall back to
Actionable duck-typing (checking typeof (ch as Actionable).channel ===
'function') and finally use String(ch) as the last fallback; this keeps the
channel() detection correct and prevents false positives from toString().
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/dart/test/channel_test.dart.twigtemplates/flutter/lib/channel.dart.twigtemplates/flutter/test/src/channel_test.dart.twigtemplates/web/src/channel.ts.twigtemplates/web/src/client.ts.twigtests/languages/android/Tests.kttests/languages/apple/Tests.swifttests/languages/flutter/tests.darttests/languages/web/index.htmltests/languages/web/node.js
🚧 Files skipped from review as they are similar to previous changes (6)
- tests/languages/flutter/tests.dart
- tests/languages/web/node.js
- templates/dart/test/channel_test.dart.twig
- tests/languages/apple/Tests.swift
- templates/flutter/test/src/channel_test.dart.twig
- tests/languages/android/Tests.kt
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
tests/languages/web/index.htmltemplates/web/src/client.ts.twigtemplates/flutter/lib/channel.dart.twigtemplates/web/src/channel.ts.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
tests/languages/web/index.htmltemplates/flutter/lib/channel.dart.twigtemplates/web/src/channel.ts.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: build (8.3, Ruby30)
- GitHub Check: build (8.3, PHP83)
- GitHub Check: go (server)
- GitHub Check: kotlin (server)
- GitHub Check: android (client)
- GitHub Check: build (8.3, Go118)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, DotNet90)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, KotlinJava11)
- GitHub Check: build (8.3, DartBeta)
- GitHub Check: swift (server)
- GitHub Check: apple (client)
🔇 Additional comments (33)
tests/languages/web/index.html (2)
24-24: LGTM!The Channel import is correctly added to the destructured Appwrite exports, consistent with other helper utilities like Query, Permission, and ID.
322-342: LGTM!Channel helper tests are comprehensive, covering all major API surfaces: database, tablesdb, account, buckets, function, team, and membership. The tests correctly exercise both parameterless and parameterized calls, as well as CRUD actions.
templates/apple/Sources/Channel.swift.twig (9)
6-15: LGTM!The ChannelValue protocol and String extension provide a clean abstraction for channel values. The String conformance enables seamless interoperability between plain strings and Channel builders.
18-28: LGTM!ResolvedChannel is well-designed as a final value wrapper with internal initialization. This ensures instances are only created through the Channel DSL, maintaining API integrity.
31-34: LGTM!The normalize helper appropriately converts empty or whitespace-only IDs to wildcards. As per learnings, the lack of additional validation or escaping is an intentional design pattern for these lightweight helper utilities.
37-42: LGTM!The Actionable protocol cleanly defines the contract for resources that support CRUD actions. The design correctly returns ResolvedChannel for actions while exposing the raw channel string.
44-74: LGTM!The resource protocol hierarchy accurately models the Appwrite resource structure. Leaf nodes correctly implement Actionable, while parent nodes provide typed navigation methods, ensuring type safety throughout the fluent API.
79-113: LGTM!The protocol extensions correctly work around Swift's limitation on default parameters in protocol requirements. The overloads provide an ergonomic API where calls like
collection()default to wildcards.
115-180: LGTM!ChannelBuilder implements an immutable fluent builder pattern correctly. The implementation handles path construction, navigation, and CRUD actions appropriately, with segments joined by dots to form valid channel strings.
208-211: Verify the account() empty string default behavior.The
account()method treats an emptyuserIdparameter as "account" (no suffix), whereas other Channel methods default to "". Line 209 normalizes an empty string to "", but Line 210 checks if the normalized result equals "*" and returns plain "account" in that case.This appears intentional based on the test expectations, but please confirm this design choice is correct: should
Channel.account()return "account" or "account.*"?Based on learnings, the lack of validation is intentional. However, the different default behavior warrants confirmation.
182-207: LGTM!The Channel factory methods and static constants are well-designed. Each method correctly normalizes IDs and returns the appropriate protocol type, enabling type-safe channel construction.
Also applies to: 212-218
templates/web/src/client.ts.twig (3)
2-2: LGTM!The import correctly brings in Actionable and ResolvedChannel types needed for the enhanced subscribe() signature.
556-582: LGTM!The documentation is thoroughly updated to reflect the new Channel builder support. Examples clearly demonstrate both traditional string channels and the new Channel DSL, providing good developer guidance.
602-617: LGTM (pending type guard fix)!The subscription management correctly uses the normalized channel strings throughout. The flow from channel addition through subscription record creation to cleanup is well-structured and maintains consistency.
templates/flutter/lib/channel.dart.twig (6)
4-10: LGTM!ResolvedChannel is well-designed as an immutable value object using Dart's const constructor. The toString() override provides clean string conversion.
13-13: LGTM!The _normalize helper is concisely implemented and follows the same logic as other language implementations. Based on learnings, the lack of validation/escaping is intentional.
17-54: LGTM!The interface definitions correctly model the resource hierarchy using Dart's abstract classes. The use of optional parameters with defaults provides an ergonomic API consistent with the design in other languages.
58-108: LGTM!The _ChannelBuilder correctly implements an immutable fluent builder pattern. All navigation and action methods are properly implemented, maintaining the builder chain with each step returning a new instance.
131-132: Verify the account() empty string default behavior.Similar to the Swift implementation, the Dart
account()method treats an emptyuserIdas "account" without a suffix, while other methods default to "*". Line 131-132 returns "account" whenuserId.isEmpty, otherwise "account.{normalized}".This is consistent with the Swift version but differs from the wildcard pattern used elsewhere. Please confirm this is the intended behavior.
Based on learnings, the design choice should be consistent across languages, but the deviation from the "*" pattern warrants confirmation.
113-130: LGTM!The Channel factory methods and static getters are well-designed and consistent with implementations in other languages. Each method properly normalizes IDs and returns the appropriate type.
Also applies to: 133-138
templates/web/src/channel.ts.twig (6)
2-7: LGTM!ResolvedChannel is a clean value wrapper with appropriate visibility. The exported class enables type-safe channel resolution in the subscribe API.
10-13: LGTM!The normalize helper correctly converts empty/whitespace IDs to wildcards. As per learnings, the minimal validation is intentional for these lightweight utilities.
17-54: LGTM!The interface hierarchy correctly models the resource structure. The exported Actionable interface enables type-safe channel handling in the client, while internal resource interfaces maintain encapsulation.
58-143: LGTM!ChannelBuilder correctly implements the immutable fluent builder pattern. All navigation and action methods properly create new instances, maintaining the builder chain while constructing valid channel paths.
172-176: Verify the account() empty string default behavior.Consistent with Swift and Dart implementations, the TypeScript
account()method returns "account" for empty/whitespace userId, while other methods default to "*". Lines 173-175 use a ternary to return "account" when userId is empty after trimming.This design is consistent across languages but deviates from the wildcard pattern. Please confirm this is intentional.
The cross-language consistency suggests this is deliberate, but explicit confirmation would be valuable.
147-171: LGTM!The Channel class provides a well-designed entry point with static factory methods returning appropriately typed builders. The implementation is consistent with other language templates, maintaining the same API surface.
Also applies to: 177-195
templates/android/library/src/main/java/io/package/Channel.kt.twig (7)
3-10: LGTM! Clean wrapper design.The ResolvedChannel class provides a lightweight wrapper for the channel string with proper toString() support, enabling seamless integration with the DSL pattern.
12-18: LGTM! Proper normalization logic.The normalize function correctly handles edge cases by trimming whitespace and defaulting empty strings to "*" wildcard. As per learnings, no additional validation or escaping is applied, which is the intentional design pattern for helper classes in this repository.
20-60: LGTM! Well-structured DSL interfaces.The interface hierarchy provides a clean, type-safe foundation for the channel builder DSL. The use of default parameters (
id: String = "*") offers flexibility, and the Actionable interface appropriately marks endpoints that support CRUD operations.
62-108: LGTM! Excellent immutable builder implementation.The ChannelBuilder demonstrates solid design principles:
- Immutability:
next()creates new instances rather than mutating state- Encapsulation: Private class prevents external instantiation
- Type safety: Multi-interface implementation enables fluent, type-safe chaining
- Clean string building: Segments joined with "." and CRUD operations properly append action suffixes
110-131: LGTM! Consistent factory methods.The Channel companion object provides a clean, consistent API surface. The private constructor enforces controlled instantiation, and all factory methods follow a uniform pattern: normalize the ID and start the builder chain with appropriate segments.
132-135: Note: Intentional API difference for account.The
accountmethod returns aStringdirectly (unlike other factory methods that return builders), and has distinct behavior:
account(),account(""), oraccount("*")all return"account"(current user)account("userId")returns"account.userId"(specific user)This design prevents constructing
"account.*"which may not be a valid channel format. The API difference appears intentional to match account channel semantics.
137-142: LGTM! Clean global channel constants.The global event channel constants (
documents,rows,files,executions) provide convenient access to top-level channels and align with the overall channel naming conventions.
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
🤖 Fix all issues with AI agents
In @templates/react-native/src/channel.ts.twig:
- Around line 160-170: The public API on Channel uses plural method names
(functions, teams, memberships) which conflicts with Flutter/Dart's singular
names; rename these static methods to function(id = "*"), team(id = "*"), and
membership(id = "*") and update any internal references to call
ChannelBuilder.start(["functions", normalize(id)]) etc. (keep the path segments
as-is if the backend expects plural resource names) and update
exports/usages/tests to the new method names so consumers on React Native match
the Flutter/Dart naming.
🧹 Nitpick comments (2)
templates/web/src/client.ts.twig (1)
585-617: TheResolvedChanneldetection relies ontoString()which exists on all objects.The check at line 597 (
typeof (ch as ResolvedChannel).toString === 'function') will always be true for any non-null object sincetoString()is inherited fromObject.prototype. However, since:
- The TypeScript type signature constrains valid inputs
Actionableis checked first (line 593)- The fallback
String(ch)at line 600 produces the same resultThis works correctly at runtime but could be more explicit. Consider checking for a discriminator property or using
instanceofifResolvedChannelis a class.♻️ Optional: More explicit type discrimination
- // Check if it's a ResolvedChannel (has toString() method) - if (ch && typeof (ch as ResolvedChannel).toString === 'function') { - return (ch as ResolvedChannel).toString(); - } - return String(ch); + // For ResolvedChannel or any other object, convert to string + return String(ch);Since
ResolvedChannel.toString()returns the channel string,String(ch)will invoke it correctly. The explicit check is redundant.templates/web/src/channel.ts.twig (1)
160-162: Minor: Inconsistent indentation.The
static functionmethod is missing the leading indentation that other methods have.🔧 Suggested fix
- static function(id: string = "*"): IFunction { + static function(id: string = "*"): IFunction { return ChannelBuilder.start(["functions", normalize(id)]); }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/dart/test/channel_test.dart.twigtemplates/flutter/lib/channel.dart.twigtemplates/flutter/lib/src/realtime.dart.twigtemplates/flutter/test/src/channel_test.dart.twigtemplates/react-native/src/channel.ts.twigtemplates/web/src/channel.ts.twigtemplates/web/src/client.ts.twigtests/languages/android/Tests.kttests/languages/apple/Tests.swifttests/languages/flutter/tests.darttests/languages/web/index.htmltests/languages/web/node.js
🚧 Files skipped from review as they are similar to previous changes (2)
- templates/flutter/lib/src/realtime.dart.twig
- templates/flutter/test/src/channel_test.dart.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
tests/languages/flutter/tests.darttests/languages/web/node.jstemplates/react-native/src/channel.ts.twigtests/languages/web/index.htmltests/languages/apple/Tests.swifttemplates/web/src/channel.ts.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtests/languages/android/Tests.kttemplates/flutter/lib/channel.dart.twigtemplates/apple/Sources/Channel.swift.twig
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/web/src/client.ts.twigtemplates/react-native/src/channel.ts.twigtests/languages/web/index.htmltests/languages/apple/Tests.swifttemplates/web/src/channel.ts.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/flutter/lib/channel.dart.twigtemplates/apple/Sources/Channel.swift.twig
🧬 Code graph analysis (2)
tests/languages/web/node.js (1)
tests/languages/node/test.js (3)
require(1-13)require(14-14)require(15-15)
tests/languages/android/Tests.kt (1)
tests/languages/kotlin/Tests.kt (1)
writeToFile(271-274)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: build (8.3, Node16)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, KotlinJava8)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, KotlinJava11)
- GitHub Check: swift (server)
- GitHub Check: android (client)
- GitHub Check: apple (client)
🔇 Additional comments (28)
tests/languages/flutter/tests.dart (1)
250-270: LGTM!The Channel helper tests comprehensively cover the Channel DSL surface including database, tablesdb, account, bucket, function, team, and membership builders with their respective actions (create, update, delete). The test structure is consistent with other helper tests in this file.
templates/dart/test/channel_test.dart.twig (2)
1-6: LGTM!The conditional import logic correctly distinguishes between pure Dart (
package:test/test.dart) and Flutter (package:flutter_test/flutter_test.dart) test frameworks based on the package name.
9-157: LGTM!The test template provides comprehensive coverage for the Channel DSL including:
- Builder patterns with default wildcards and specific IDs
- Nested path construction (database → collection → document, etc.)
- Action methods (create, update, delete) returning
ResolvedChannel- Global event getters returning plain strings
templates/web/src/client.ts.twig (1)
2-2: LGTM!The import correctly brings in
ActionableandResolvedChanneltypes from the new channel module.templates/react-native/src/channel.ts.twig (2)
58-143: LGTM!The
ChannelBuilderimplementation is well-structured:
- Immutable chaining via new instances in
next()- Clean separation of segment building and action resolution
- Proper implementation of all state interfaces
1-7: No action needed. The React Native implementation uses a different pattern than the web template. Thesubscribemethod in React Native accepts rawstring | string[]channels directly, not theActionableorResolvedChanneltypes. Since React Native doesn't use the Channel builder pattern and has no realtime service template that would import these types, exporting them is unnecessary.Likely an incorrect or invalid review comment.
templates/flutter/lib/channel.dart.twig (2)
1-13: LGTM!The file structure follows Dart conventions:
part ofdirective for library integration- Private helper
_normalizewith underscore prefix- Clean
ResolvedChannelwrapper with propertoString()override
112-138: LGTM!The
Channelclass is well-designed:
abstract classprevents instantiation (idiomatic Dart pattern for utility classes)- Consistent singular method naming (
function,team,membership)account()correctly handles the special case of returning plain"account"vs"account.{userId}"- Static getters for global events (
documents,rows,files,executions) are cleantests/languages/web/node.js (2)
1-1: LGTM!The import correctly includes
Channelin the destructured imports from the SDK.
253-273: LGTM!The Channel helper tests are comprehensive and use singular method naming (
Channel.function(),Channel.team(),Channel.membership()) consistent with the Flutter/Dart templates.tests/languages/web/index.html (2)
24-24: LGTM!The destructuring correctly includes
Channelfrom theAppwriteglobal namespace.
322-342: LGTM!The Channel helper tests are consistent with the Node.js test file and cover the complete Channel API surface.
tests/languages/apple/Tests.swift (1)
251-271: LGTM! Comprehensive test coverage for Channel helpers.The tests exercise the full Channel DSL API surface including database, tablesdb, account, bucket, function, team, and membership builders with various operations (create, update, delete) and chained calls. The test structure follows the established patterns for Query and Permission helper tests in this file.
tests/languages/android/Tests.kt (2)
10-10: Import correctly added.
273-293: LGTM! Channel helper tests align with the Swift test suite.The tests provide consistent coverage across the Channel DSL API, matching the patterns established in the Swift tests and following the existing
writeToFileconvention used throughout this test file.templates/android/library/src/main/java/io/package/Channel.kt.twig (4)
1-10: Clean wrapper implementation.
ResolvedChannelprovides a straightforward value wrapper with propertoString()override for seamless string conversion in realtime subscription contexts.
12-60: Well-structured interface hierarchy.The normalize helper and interface definitions provide a clean, type-safe API. The
Actionableinterface correctly exposeschannelfor intermediate string access and action methods returningResolvedChannel.
62-108: Solid builder implementation with immutable pattern.The
ChannelBuildercorrectly uses an immutable approach (creating new instances vianext()) and provides clean segment composition. Thechannelproperty and action methods properly construct the final path strings.
110-143: Clean public API design.The
Channelcompanion object provides intuitive factory methods. Theaccount()method correctly handles the special case where an empty/whitespace userId should return just"account"rather than"account.*". Global event constants are appropriately exposed asconst val.templates/apple/Sources/Channel.swift.twig (5)
1-28: Well-designed protocol hierarchy for Swift interoperability.The
ChannelValueprotocol withStringextension enables seamless use of both raw strings andResolvedChannelinstances in APIs that accept channel values. This is a clean Swift-idiomatic approach.
30-74: Protocol hierarchy mirrors the Kotlin implementation.The protocol definitions maintain cross-language consistency while being Swift-idiomatic. The inheritance structure (
IDocument: Actionable, etc.) correctly models the channel path composition.
76-113: Correct Swift pattern for default parameter simulation.Since Swift protocols don't support default parameter values, these extensions properly provide argument-less overloads that delegate to the wildcard
"*". The inline comment at lines 76-78 helpfully documents this design decision.
115-180: Builder implementation is correctly encapsulated.
ChannelBuilderuses Swift's default internal access level, keeping it hidden from the public API whileChannelremains the sole entry point. The immutable pattern and segment composition are consistent with the Kotlin implementation.
182-218: Public API is clean and consistent.Using a Swift
enumwith only static members is the idiomatic way to create a namespace that can't be instantiated. Theaccount()method correctly handles the empty userId case, and global event constants are properly exposed.templates/web/src/channel.ts.twig (4)
1-13: Clean TypeScript implementation.The
ResolvedChannelwrapper andnormalizehelper follow the same patterns established in the Kotlin and Swift implementations.
15-54: Interface exports are appropriately scoped.Only
Actionableis exported (needed for typing in consumer code), while the intermediate interfaces remain internal. This keeps the public API surface minimal.
56-143: Builder implementation is consistent across languages.The non-exported
ChannelBuildermaintains the immutable builder pattern with segment composition via spread operator. The privateresolve()helper cleanly abstracts action suffix appending.
145-195: Public API is well-designed.The
Channelclass provides a clean entry point with static factory methods. Using getters for global event constants ensures they're accessed as properties (Channel.documents) rather than method calls, which is more idiomatic for TypeScript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
templates/web/src/client.ts.twig (1)
585-585: Consider broadening the type signature to allow mixed arrays.The implementation (lines 588-602) correctly handles mixed arrays containing strings alongside Channel helpers, but the current type signature doesn't explicitly allow this pattern. Users might want to pass arrays like
[Channel.account(), "documents", Channel.database('db')].♻️ Proposed refinement to support mixed arrays
-subscribe<T extends unknown>(channels: string | string[] | Actionable | ResolvedChannel | (Actionable | ResolvedChannel)[], callback: (payload: RealtimeResponseEvent<T>) => void): () => void { +subscribe<T extends unknown>(channels: string | Actionable | ResolvedChannel | (string | Actionable | ResolvedChannel)[], callback: (payload: RealtimeResponseEvent<T>) => void): () => void {templates/react-native/src/channel.ts.twig (1)
145-194: LGTM! Clean public API with minor optimization opportunity.The Channel entry point provides a clear, consistent API for constructing realtime channel subscriptions. Factory methods, special-case handling for account channels, and global event getters all work correctly.
♻️ Optional: Eliminate redundant trim in account() method
The
account()method callstrim()twice—once for the conditional check and again insidenormalize(). Caching the trimmed value would be slightly more efficient:static account(userId: string = ""): string { - return userId.trim() - ? `account.${normalize(userId)}` - : "account"; + const trimmed = userId.trim(); + return trimmed + ? `account.${normalize(userId)}` + : "account"; }Or more directly:
static account(userId: string = ""): string { - return userId.trim() - ? `account.${normalize(userId)}` - : "account"; + const normalized = normalize(userId); + return normalized !== "*" + ? `account.${normalized}` + : "account"; }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
templates/react-native/src/channel.ts.twigtemplates/web/src/channel.ts.twigtemplates/web/src/client.ts.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/web/src/client.ts.twigtemplates/react-native/src/channel.ts.twigtemplates/web/src/channel.ts.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
templates/react-native/src/channel.ts.twigtemplates/web/src/channel.ts.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: build (8.3, WebNode)
- GitHub Check: build (8.3, Swift56)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, WebChromium)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, Node16)
- GitHub Check: build (8.3, KotlinJava8)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: apple (client)
- GitHub Check: swift (server)
- GitHub Check: android (client)
🔇 Additional comments (12)
templates/web/src/client.ts.twig (4)
2-2: LGTM!The imports are necessary for the Channel helper support in the subscribe method.
586-602: LGTM!The normalization logic correctly handles all Channel helper types with appropriate fallbacks. The order of checks (ResolvedChannel, then Actionable, then string conversion) is correct since ChannelBuilder instances implement Actionable but not ResolvedChannel.
556-584: LGTM!The documentation clearly explains both the legacy string-based channel syntax and the new Channel builder API with practical examples.
603-617: LGTM!The normalized channel strings are consistently used throughout the subscription lifecycle (registration, storage, and cleanup), ensuring the realtime internals work exclusively with string channels.
templates/web/src/channel.ts.twig (5)
1-7: LGTM!The ResolvedChannel class provides a clean wrapper for completed channel paths with actions, distinguishing them from in-progress builders.
9-13: LGTM!The normalize function follows the SDK's intentional design pattern of accepting IDs without validation or escaping. The empty-to-wildcard conversion provides sensible default behavior for optional parameters.
Based on learnings, this lightweight approach is consistent across the SDK.
15-54: LGTM!The interface design provides a clean, type-safe fluent API. Terminal interfaces appropriately extend Actionable to provide action methods, while intermediate interfaces guide users through the valid chaining paths.
58-143: LGTM!The ChannelBuilder implementation correctly uses an immutable builder pattern with segment-based path construction. The use of default wildcard parameters provides sensible defaults for optional IDs.
147-195: LGTM!The Channel factory methods provide appropriate entry points for different resource types. The design variations (account returning string, team/membership returning Actionable, and others returning chainable interfaces) align with the different API patterns for each resource type.
templates/react-native/src/channel.ts.twig (3)
1-13: LGTM! Clean helper types and normalization.The
ResolvedChannelwrapper andnormalizefunction are well-implemented. The normalization logic correctly handles empty and whitespace-only IDs by converting them to wildcard "*". Per learnings, the intentional lack of validation or escaping aligns with the repository's design pattern for lightweight helper utilities.
15-92: LGTM! Well-structured builder pattern with strong type safety.The interface hierarchy and ChannelBuilder implementation elegantly enforce valid channel construction paths through TypeScript's type system. The builder returns specific interfaces (IDatabase, ICollection, etc.) that constrain which methods can be called at each stage, preventing invalid channel structures. The immutable chaining via
next()is a solid design choice.
94-143: LGTM! Consistent method implementations.All builder methods follow a consistent pattern using
next()for chaining andresolve()for terminal actions. The default parameter "*" provides a sensible wildcard for subscriptions. The implementation correctly satisfies the optional parameters in the interfaces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
templates/android/library/src/main/java/io/package/services/Realtime.kt.twig (1)
129-145: LGTM - Channel DSL overloads implemented correctly.Both overloads properly convert DSL channel types to strings using
channelToStringand delegate to the existing String-based subscribe implementation. The vararg array handling and type conversions are correct.The return type is correctly inferred as
RealtimeSubscriptionfrom the delegate chain, maintaining consistency with the existing non-typed String overload pattern at lines 147-154.Optional: Consider explicit return type for consistency
While the current implicit return type is correct, explicitly declaring it could improve readability and API documentation:
fun subscribe( vararg channels: Actionable, callback: (RealtimeResponseEvent<Any>) -> Unit, -) = subscribe( +): RealtimeSubscription = subscribe( channels = channels.map { channelToString(it) }.toTypedArray(), Any::class.java, callback ) fun subscribe( vararg channels: ResolvedChannel, callback: (RealtimeResponseEvent<Any>) -> Unit, -) = subscribe( +): RealtimeSubscription = subscribe( channels = channels.map { channelToString(it) }.toTypedArray(), Any::class.java, callback )However, since the existing String overload at line 147 follows the same pattern without explicit return types, the current approach maintains consistency with the codebase style.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
templates/android/library/src/main/java/io/package/services/Realtime.kt.twigtests/AppleSwift56Test.php
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/AppleSwift56Test.php
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/android/library/src/main/java/io/package/services/Realtime.kt.twig
🔇 Additional comments (3)
templates/android/library/src/main/java/io/package/services/Realtime.kt.twig (3)
5-6: LGTM - Imports correctly added for Channel DSL support.The new imports for
ActionableandResolvedChannelare properly placed and necessary for the Channel helper functionality being added to the Realtime service.
114-127: LGTM - Well-designed channel normalization helper.The
channelToStringfunction correctly handles the type hierarchy with appropriate precedence:
- Direct string pass-through
- Actionable → extracts
.channelproperty- ResolvedChannel → uses
.toString()- Fallback to
.toString()for any unexpected typesThe defensive design and clear documentation make this helper robust and maintainable.
156-178: LGTM - Generic typed overloads correctly preserve type safety.The typed subscribe overloads properly:
- Preserve the generic type parameter
<T>through the delegation chain- Convert DSL channel types using
channelToStringand map operations- Explicitly declare
RealtimeSubscriptionreturn type for clarity- Delegate to the existing typed String-based implementation at lines 180-208
The implementation maintains type safety while providing a cleaner API for Channel DSL users.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
templates/web/src/channel.ts.twig (1)
1-14: UnusedRootinterface.The
Rootinterface is declared but never used in the code. If it's intended for future use, consider adding a comment; otherwise, it can be removed.templates/web/src/client.ts.twig (1)
585-598: ThetoStringfunction check is always true for objects.The check
typeof (ch as Channel<any>).toString === 'function'will always be true for any object since all objects inherittoString()fromObject.prototype. The current logic works correctly but the condition is redundant.Consider simplifying to check for non-null objects directly, or keep the current defensive approach if you prefer explicitness.
♻️ Optional simplification
const channelStrings = channelArray.map(ch => { if (typeof ch === 'string') { return ch; } - // All Channel instances have toString() method - if (ch && typeof (ch as Channel<any>).toString === 'function') { - return (ch as Channel<any>).toString(); - } - // Fallback to generic string conversion - return String(ch); + // Convert Channel instances to strings + return ch.toString(); });templates/web/src/services/realtime.ts.twig (1)
241-257: Same observation: thetoStringcheck is redundant.Similar to
client.ts.twig, the checktypeof (channel as Channel<any>).toString === 'function'is always true for objects. Consider the same simplification for consistency.♻️ Optional simplification
private channelToString(channel: string | Channel<any> | ActionableChannel | ResolvedChannel): string { if (typeof channel === 'string') { return channel; } - // All Channel instances have toString() method - if (channel && typeof (channel as Channel<any>).toString === 'function') { - return (channel as Channel<any>).toString(); - } - return String(channel); + // Convert Channel instances to strings + return channel.toString(); }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
templates/react-native/src/channel.ts.twigtemplates/web/src/channel.ts.twigtemplates/web/src/client.ts.twigtemplates/web/src/services/realtime.ts.twig
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/web/src/client.ts.twigtemplates/web/src/services/realtime.ts.twigtemplates/web/src/channel.ts.twigtemplates/react-native/src/channel.ts.twig
🔇 Additional comments (13)
templates/web/src/channel.ts.twig (6)
18-21: LGTM!The
normalizefunction correctly trims whitespace and converts empty strings to the wildcard*, which aligns with the channel path semantics.
23-38: LGTM!The
Channel<T>class is well-structured with a private constructor to enforce factory usage. The_typedeclaration provides phantom type information for type narrowing without runtime overhead.
40-68: LGTM!The use of TypeScript's
thisparameter for type-safe method chaining is a clean pattern. Each navigation method correctly constrains the caller type and produces the appropriate next state type.
70-82: LGTM!Terminal actions (
create,update,delete) are correctly restricted to theActionableunion type, preventing invalid method chains at compile time.
109-112: Inconsistent return type foraccount()compared to other factories.
account()returns astringdirectly, while all other factory methods (database,bucket, etc.) returnChannel<T>instances. This asymmetry may surprise users expecting uniform behavior.If this is intentional (e.g.,
accountdoesn't support further chaining), consider documenting this distinction in a comment.
84-129: LGTM!The static factory methods and global event getters are well-implemented. The factories correctly normalize IDs and construct the initial segment arrays.
templates/react-native/src/channel.ts.twig (1)
1-134: LGTM!This file is a direct copy of the web Channel implementation, which is appropriate for the SDK generator template architecture. The same observations apply (unused
Rootinterface,account()returning a string instead of aChannelinstance), but these are consistent with the web template.templates/web/src/client.ts.twig (3)
2-2: LGTM!The import correctly brings in the Channel types needed for the extended subscribe signature.
556-584: LGTM!The JSDoc has been updated with clear examples of Channel builder usage, which will help users understand the new API.
599-614: LGTM!The normalized
channelStringsarray is correctly used for adding to the channels set, storing in subscriptions, and cleanup operations.templates/web/src/services/realtime.ts.twig (3)
2-2: LGTM!The import correctly brings in the Channel types for the Realtime service.
259-305: LGTM!The subscribe overloads are well-documented with updated JSDoc comments reflecting the new Channel-compatible signatures. The type definitions properly support both single channel and array inputs with optional typed payloads.
307-348: LGTM!The subscribe implementation correctly:
- Normalizes input to an array
- Converts all channels to strings via
channelToString()- Deduplicates using a
Set- Stores string-based channel references for subscription matching and cleanup
The implementation is consistent with the Client's subscribe method.
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
templates/apple/Sources/Services/Realtime.swift.twig (1)
228-233: ChangeNIO.ChanneltoNIOCore.Channelin delegate method signatures to match the protocol.The
WebSocketClientDelegateprotocol (line 7 & 10 in WebSocketClientDelegate.swift.twig) definesonOpen(channel: NIOCore.Channel)andonClose(channel: NIOCore.Channel, data: Data), but the Realtime implementation usesNIO.Channelat lines 228 and 248. This is a protocol conformance mismatch.The
ChannelValueprotocol andStringconformance are correctly defined and working as expected; no changes needed there.
🧹 Nitpick comments (11)
templates/web/src/client.ts.twig (1)
611-624: Consider simplifying the Channel-to-string conversion logic.The
toStringmethod check on line 619 is redundant since all JavaScript objects inherittoString()fromObject.prototype, making line 623 unreachable dead code.♻️ Suggested simplification
subscribe<T extends unknown>(channels: string | string[] | Channel<any> | ActionableChannel | ResolvedChannel | (Channel<any> | ActionableChannel | ResolvedChannel)[], callback: (payload: RealtimeResponseEvent<T>) => void): () => void { const channelArray = Array.isArray(channels) ? channels : [channels]; // Convert Channel instances to strings const channelStrings = channelArray.map(ch => { if (typeof ch === 'string') { return ch; } - // All Channel instances have toString() method - if (ch && typeof (ch as Channel<any>).toString === 'function') { - return (ch as Channel<any>).toString(); - } - // Fallback to generic string conversion - return String(ch); + // Channel instances use toString() to return the channel string + return ch.toString(); });templates/apple/Sources/Services/Realtime.swift.twig (1)
120-172: Forward the passedpayloadTypeinstead of hardcodingT.self(avoids confusion).Right now the generic overloads accept
payloadType: T.Typebut ignore the parameter (Line 150-171). It’s functionally equivalent, but reads like a bug.Proposed diff
public func subscribe<T : Codable>( channel: ChannelValue, payloadType: T.Type, callback: @escaping (RealtimeResponseEvent) -> Void ) async throws -> RealtimeSubscription { return try await subscribe( channels: Set([channelToString(channel)]), - payloadType: T.self, + payloadType: payloadType, callback: callback ) } public func subscribe<T : Codable>( channels: [ChannelValue], payloadType: T.Type, callback: @escaping (RealtimeResponseEvent) -> Void ) async throws -> RealtimeSubscription { return try await subscribe( channels: Set(channels.map { channelToString($0) }), - payloadType: T.self, + payloadType: payloadType, callback: callback ) }templates/android/library/src/main/java/io/package/Channel.kt.twig (1)
134-243: Consider collapsing the duplicatedcreate/update/deleteextensions via a realActionablemarker interface.
typealias Actionable = Documentdoesn’t actually help here, and the current approach repeats the same three methods for each type.(One possible direction: introduce
interface Actionable, haveDocument/Row/File/Execution/Team/Membership : Actionable, then addfun <T : Actionable> Channel<T>.create()/update()/delete()once.)templates/flutter/lib/channel.dart.twig (1)
19-70: Optional: make global eventsstatic constinstead of getters (const-friendly).Today:
static String get documents => 'documents';Could be:
static const String documents = 'documents';templates/flutter/lib/src/realtime_base.dart.twig (1)
4-6: TheList<Object>parameter with the inline comment adequately documents the expected types. The implementation correctly normalizes both String and Channel objects to strings via the_channelToString()method:String _channelToString(Object channel) { return channel is String ? channel : channel.toString(); }A typedef alias to
Objectwould not meaningfully improve type safety or discoverability in Dart—it's functionally equivalent to the current approach and provides no compile-time benefit over the inline comment. The current pattern is lightweight and works well for this helper API.templates/flutter/lib/src/realtime_mixin.dart.twig (2)
171-175:_channelToStringcan be simplified (String special-case is redundant).
String.toString()already returns itself, so the type check doesn’t buy much.Proposed simplification
- String _channelToString(Object channel) { - return channel is String ? channel : channel.toString(); - } + String _channelToString(Object channel) => channel.toString();
177-190: Remove redundant.cast<String>()when buildingchannelStrings.
_channelToStringalready returnsString, so the extra cast is unnecessary.Proposed change
- final channelStrings = channels.map((ch) => _channelToString(ch)).toList().cast<String>(); + final channelStrings = channels.map(_channelToString).toList(growable: false);templates/android/library/src/main/java/io/package/services/Realtime.kt.twig (2)
113-123:channelToStringbranches are redundant; simplify tochannel.toString().The
StringandChannel<*>branches don’t change behavior vstoString().Proposed simplification
- private fun channelToString(channel: Any): String { - return when { - channel is String -> channel - channel is Channel<*> -> channel.toString() - else -> channel.toString() - } - } + private fun channelToString(channel: Any): String = channel.toString()
125-133: Channel overloads look correct; consider explicit return type on the non-generic overload.It should currently infer
RealtimeSubscription, but making it explicit avoids accidental signature drift during future edits.Optional tweak
- fun subscribe( + fun subscribe( vararg channels: Channel<*>, callback: (RealtimeResponseEvent<Any>) -> Unit, - ) = subscribe( + ): RealtimeSubscription = subscribe( channels = channels.map { channelToString(it) }.toTypedArray(), Any::class.java, callback )Also applies to: 143-153
templates/apple/Sources/Channel.swift.twig (2)
19-47: ConsiderstructforRealtimeChannel<T>(it’s immutable) + addCustomStringConvertiblefor smoother interop.Right now consumers must remember to call
.toString();descriptionhelps logs/debugging and anyString(describing:)usage.Optional ergonomic additions
public class RealtimeChannel<T> { private let segments: [String] @@ public func toString() -> String { return segments.joined(separator: ".") } } + +extension RealtimeChannel: CustomStringConvertible { + public var description: String { toString() } +}
83-88: Usestatic letfor global events (they’re constants).Proposed change
- public static var documents: String { "documents" } - public static var rows: String { "rows" } - public static var files: String { "files" } - public static var executions: String { "executions" } + public static let documents = "documents" + public static let rows = "rows" + public static let files = "files" + public static let executions = "executions"
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (29)
src/SDK/Language/Android.phpsrc/SDK/Language/Apple.phpsrc/SDK/Language/Flutter.phpsrc/SDK/Language/ReactNative.phpsrc/SDK/Language/Web.phptemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/android/library/src/main/java/io/package/services/Realtime.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/apple/Sources/Services/Realtime.swift.twigtemplates/flutter/lib/channel.dart.twigtemplates/flutter/lib/src/realtime.dart.twigtemplates/flutter/lib/src/realtime_base.dart.twigtemplates/flutter/lib/src/realtime_mixin.dart.twigtemplates/web/src/client.ts.twigtests/Android14Java11Test.phptests/Android14Java17Test.phptests/Android14Java8Test.phptests/Android5Java17Test.phptests/AppleSwift56Test.phptests/Base.phptests/FlutterBetaTest.phptests/FlutterStableTest.phptests/WebChromiumTest.phptests/WebNodeTest.phptests/languages/android/Tests.kttests/languages/apple/Tests.swifttests/languages/flutter/tests.darttests/languages/web/index.htmltests/languages/web/node.js
🚧 Files skipped from review as they are similar to previous changes (6)
- tests/WebNodeTest.php
- tests/Base.php
- src/SDK/Language/ReactNative.php
- templates/flutter/lib/src/realtime.dart.twig
- tests/languages/flutter/tests.dart
- tests/Android5Java17Test.php
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
src/SDK/Language/Apple.phptemplates/flutter/lib/src/realtime_base.dart.twigtests/languages/apple/Tests.swifttests/languages/web/index.htmltemplates/web/src/client.ts.twigtests/languages/web/node.jstests/AppleSwift56Test.phptemplates/flutter/lib/src/realtime_mixin.dart.twigtemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/flutter/lib/channel.dart.twigtemplates/android/library/src/main/java/io/package/services/Realtime.kt.twigtemplates/apple/Sources/Services/Realtime.swift.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
tests/languages/apple/Tests.swifttests/languages/web/index.htmltests/languages/web/node.jstemplates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twigtemplates/flutter/lib/channel.dart.twigtemplates/android/library/src/main/java/io/package/services/Realtime.kt.twigtests/languages/android/Tests.kt
🧬 Code graph analysis (8)
tests/FlutterStableTest.php (1)
tests/Base.php (1)
Base(17-369)
tests/languages/web/node.js (1)
tests/languages/node/test.js (3)
require(1-13)require(14-14)require(15-15)
tests/Android14Java8Test.php (1)
tests/Base.php (1)
Base(17-369)
tests/Android14Java11Test.php (1)
tests/Base.php (1)
Base(17-369)
tests/Android14Java17Test.php (1)
tests/Base.php (1)
Base(17-369)
tests/languages/android/Tests.kt (1)
tests/languages/kotlin/Tests.kt (1)
writeToFile(282-285)
tests/WebChromiumTest.php (1)
tests/Base.php (1)
Base(17-369)
tests/FlutterBetaTest.php (1)
tests/Base.php (1)
Base(17-369)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
- GitHub Check: build (8.3, Node18)
- GitHub Check: build (8.3, Python310)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, Go112)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, PHP80)
- GitHub Check: build (8.3, KotlinJava8)
- GitHub Check: build (8.3, DotNet90)
- GitHub Check: build (8.3, WebChromium)
- GitHub Check: build (8.3, Ruby31)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, KotlinJava11)
- GitHub Check: build (8.3, DotNet80)
- GitHub Check: build (8.3, DartBeta)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: android (client)
- GitHub Check: kotlin (server)
- GitHub Check: apple (client)
- GitHub Check: swift (server)
🔇 Additional comments (23)
tests/WebChromiumTest.php (1)
40-40: LGTM!The addition of
CHANNEL_HELPER_RESPONSESfollows the established pattern and is correctly placed in the expected output sequence.tests/AppleSwift56Test.php (1)
35-35: LGTM!Consistent with the broader test-suite updates for channel helper coverage.
tests/FlutterBetaTest.php (1)
35-35: LGTM!Consistent addition of channel helper test coverage for Flutter beta.
tests/FlutterStableTest.php (1)
35-35: LGTM!Consistent addition of channel helper test coverage for Flutter stable.
templates/web/src/client.ts.twig (3)
2-2: LGTM!Import correctly brings in the new Channel types needed for the subscribe method signature.
582-610: LGTM!Good documentation update with clear examples showing both traditional string channels and the new Channel builder API.
625-637: LGTM!Correctly updates channel registration, subscription storage, and cleanup to use the converted string array.
src/SDK/Language/Android.php (1)
123-127: LGTM: generator now emitsChannel.ktfor Android.tests/Android14Java8Test.php (1)
22-39: LGTM: adds Channel helper expectations to the Android Java 8 matrix.src/SDK/Language/Web.php (1)
83-87: LGTM!The new channel.ts file generation entry follows the established pattern for helper files (permission.ts, role.ts, id.ts). The scope, destination, and template path are consistent with the existing structure.
tests/Android14Java11Test.php (1)
37-37: LGTM!The addition of
CHANNEL_HELPER_RESPONSESto the expected output follows the established pattern and is consistently positioned betweenID_HELPER_RESPONSESandOPERATOR_HELPER_RESPONSES.tests/Android14Java17Test.php (1)
36-36: LGTM!Consistent addition of
CHANNEL_HELPER_RESPONSESmatching the pattern in other Android test files.src/SDK/Language/Apple.php (1)
73-77: LGTM!The Channel.swift generation entry follows the established pattern for Apple SDK helper files. The template correctly uses the
apple/prefix for Apple-specific implementation, and the destination path is consistent with other helper files likeID.swiftandQuery.swift.src/SDK/Language/Flutter.php (2)
83-87: LGTM!The channel.dart generation entry follows the established pattern and is consistently positioned between id.dart and query.dart, matching the structure in other SDK languages.
303-307: LGTM!Good practice adding the corresponding test file for the new channel helper. The test template path and destination follow the existing test file conventions.
tests/languages/apple/Tests.swift (1)
261-281: LGTM! Comprehensive Channel helper test coverage.The tests exercise the Channel DSL thoroughly, covering all resource types (database, tablesdb, account, bucket, function, team, membership) with both default and custom parameters, as well as action methods (create, update, delete). The test structure follows the established patterns for other helpers like Query and Permission.
tests/languages/android/Tests.kt (2)
10-10: LGTM!Import correctly added alongside other helper imports.
284-304: LGTM! Channel helper tests are consistent with other platforms.The Android tests mirror the Apple/Swift Channel tests exactly, ensuring cross-platform API consistency. The test structure follows the existing
writeToFile()pattern used throughout the test file.tests/languages/web/node.js (2)
1-1: LGTM!Channel correctly added to the SDK import.
278-298: LGTM! Channel helper tests match cross-platform consistency.The Node.js tests follow the identical pattern as Android and Apple tests, ensuring the Channel DSL API is consistent across all client SDKs.
tests/languages/web/index.html (2)
24-24: LGTM!Channel correctly added to the Appwrite destructuring for browser tests.
347-367: LGTM! Browser Channel tests consistent with Node.js tests.The browser tests mirror the Node.js Channel helper tests, ensuring complete web SDK test coverage for both execution environments.
templates/apple/Sources/Channel.swift.twig (1)
234-249:ChannelValuecompatibility layer looks good.This keeps the API flexible while still allowing typed builder chaining.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
templates/android/library/src/main/java/io/package/Channel.kt.twig (2)
19-20: Unused and misleading typealias.The comment describes this as a "union type for actionable channels," but it's simply an alias to
_Document. Additionally, this typealias doesn't appear to be used anywhere in the file. Consider removing it or clarifying its purpose if it's intended for external use.
40-50: Consider makingnextandresolveinternal to preserve type safety.These methods are marked public "for extension function access," but in Kotlin,
internalvisibility is sufficient for extension functions within the same module. Making them public allows SDK consumers to bypass the type-safe DSL by callingchannel.next<AnyType>("arbitrary", "id")directly.♻️ Proposed fix
- fun <N> next(segment: String, id: String = "*"): Channel<N> { + internal fun <N> next(segment: String, id: String = "*"): Channel<N> { return Channel(segments + listOf(segment, normalize(id))) } - fun resolve(action: String): Channel<_Resolved> { + internal fun resolve(action: String): Channel<_Resolved> { return Channel(segments + listOf(action)) }templates/flutter/lib/channel.dart.twig (1)
60-63: Consider returning aChanneltype for API consistency.The
account()method returns aStringdirectly, while other factory methods (database(),bucket(), etc.) returnChannel<T>. Although this works correctly since the string is the final channel path, it creates a slight API inconsistency.If account is intentionally terminal with no further chaining, this is acceptable. Otherwise, consider returning a
Channel<_Account>for uniform behavior.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/flutter/lib/channel.dart.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/flutter/lib/channel.dart.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/flutter/lib/channel.dart.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
- GitHub Check: build (8.3, Ruby27)
- GitHub Check: build (8.3, Ruby31)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, AppleSwift56)
- GitHub Check: build (8.3, Go118)
- GitHub Check: build (8.3, Node20)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, Python313)
- GitHub Check: build (8.3, DotNet80)
- GitHub Check: android (client)
- GitHub Check: build (8.3, CLIBun10)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, DartStable)
- GitHub Check: build (8.3, Android5Java17)
- GitHub Check: build (8.3, DartBeta)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: kotlin (server)
- GitHub Check: swift (server)
- GitHub Check: apple (client)
🔇 Additional comments (9)
templates/android/library/src/main/java/io/package/Channel.kt.twig (5)
1-17: LGTM!The package templating and marker interfaces are well-structured. Using
internalvisibility for marker interfaces appropriately encapsulates the type-state pattern within the SDK.
22-28: LGTM!The
normalizehelper correctly handles empty/whitespace IDs by defaulting to"*". Based on learnings, the intentional design pattern is to accept IDs without validation or escaping, which this implementation follows.
57-86: LGTM!Factory methods are well-organized. The
account()method intentionally returns aStringdirectly (rather thanChannel<T>) to match the expected output format whereaccountdoesn't have child routes. The global event constants provide convenient shortcuts.
89-132: LGTM!The extension functions correctly implement type-safe method chaining. Each route transition is properly restricted by the receiver type, ensuring compile-time safety (e.g.,
document()is only callable onChannel<_Collection>).
134-243: LGTM!Terminal actions are correctly implemented with proper type restrictions. Each actionable type (
_Document,_Row,_File,_Execution,_Team,_Membership) has the expectedcreate(),update(), anddelete()operations returningChannel<_Resolved>.Note: The comment on line 135 references "Actionable types" but the
Actionabletypealias on line 20 only maps to_Document. Consider updating the comment or typealias for consistency.templates/flutter/lib/channel.dart.twig (4)
3-17: Well-designed phantom type markers for type-safe chaining.The private marker classes effectively restrict method availability at compile time through the generic type parameter. This is a clean implementation of the phantom type pattern in Dart.
19-20: LGTM!The
_normalizefunction correctly handles empty and whitespace-only inputs by defaulting to the wildcard'*'.
72-109: LGTM!The navigation extensions are correctly typed to their respective
Channel<T>receivers, ensuring compile-time safety. The consistent use of_next<N>and default wildcard'*'provides a clean, predictable API.
111-154: LGTM!The terminal action extensions correctly restrict
create(),update(), anddelete()methods to actionable resource types. TheChannel<_Resolved>return type effectively prevents further invalid chaining. While the code is repetitive, this is acceptable given Dart's extension limitations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
templates/android/library/src/main/java/io/package/Channel.kt.twig (2)
3-17:_Rootinterface appears unused.The
_Rootmarker interface is declared but never referenced in the Channel DSL. If it's intended for future use, consider adding a comment; otherwise, remove it to avoid dead code.
19-20: Misleading and unused typealias.The comment describes a "union type for actionable channels," but Kotlin doesn't support union types this way—this only aliases
_Document. Additionally,Actionableis never used in the file. Consider removing this dead code or replacing it with a documentation comment listing the actionable types.🔧 Suggested fix
-// Union type for actionable channels -typealias Actionable = _Document +// Actionable types (supporting create/update/delete): +// _Document, _Row, _File, _Execution, _Team, _Membershiptemplates/apple/Sources/Channel.swift.twig (2)
25-47: Consider addingCustomStringConvertibleconformance.The
toString()method works fine, but conforming toCustomStringConvertiblewould makeRealtimeChannelmore idiomatic in Swift, enabling direct use in string interpolation and print statements.♻️ Optional enhancement
/// Channel class with generic type parameter for type-safe method chaining -public class RealtimeChannel<T> { +public class RealtimeChannel<T>: CustomStringConvertible { private let segments: [String] internal init(_ segments: [String]) { self.segments = segments } + public var description: String { + return segments.joined(separator: ".") + } + /// Internal helper to transition to next state with segment and ID internal func next<N>(_ segment: String, _ id: String = "*") -> RealtimeChannel<N> { return RealtimeChannel<N>(segments + [segment, normalize(id)]) } /// Internal helper for terminal actions (no ID segment) internal func resolve(_ action: String) -> RealtimeChannel<_Resolved> { return RealtimeChannel<_Resolved>(segments + [action]) } /// Convert channel to string representation public func toString() -> String { - return segments.joined(separator: ".") + return description } }
3-17: Remove or document the unused_Rootmarker struct.The
_Rootstruct is defined but never referenced by any factory method or extension in this file. AllChannelfactory methods produce typed channels starting from_Database,_TablesDB,_Bucket, etc., never transitioning through_Root.If reserved for future use, add a clarifying comment; otherwise, remove it.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twig
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
📚 Learning: 2025-12-18T18:42:20.227Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/swift/Sources/WebSockets/WebSocketClient.swift.twig:140-140
Timestamp: 2025-12-18T18:42:20.227Z
Learning: In templates/swift/Sources/WebSockets/WebSocketClient.swift.twig, the Channel type from NIOCore is explicitly qualified as `NIOCore.Channel` to avoid naming conflicts with the new Channel helper class for realtime subscriptions. This is not a breaking change - it's the same type, just explicitly qualified in the source.
Applied to files:
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twig
📚 Learning: 2025-12-18T18:43:35.419Z
Learnt from: ArnabChatterjee20k
Repo: appwrite/sdk-generator PR: 1266
File: templates/apple/Sources/Channel.swift.twig:13-19
Timestamp: 2025-12-18T18:43:35.419Z
Learning: In the appwrite/sdk-generator repository, helper classes like Channel and Query accept IDs without validation or escaping. These are lightweight helper utilities that construct strings directly from provided parameters without sanitizing or encoding them. This is an intentional design pattern across the SDK.
Applied to files:
templates/android/library/src/main/java/io/package/Channel.kt.twigtemplates/apple/Sources/Channel.swift.twig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
- GitHub Check: build (8.3, KotlinJava17)
- GitHub Check: build (8.3, Node16)
- GitHub Check: build (8.3, Go112)
- GitHub Check: build (8.3, KotlinJava8)
- GitHub Check: build (8.3, PHP80)
- GitHub Check: build (8.3, DotNet90)
- GitHub Check: build (8.3, FlutterStable)
- GitHub Check: build (8.3, DotNet80)
- GitHub Check: build (8.3, CLIBun11)
- GitHub Check: build (8.3, DartStable)
- GitHub Check: build (8.3, FlutterBeta)
- GitHub Check: build (8.3, CLIBun13)
- GitHub Check: build (8.3, Android14Java17)
- GitHub Check: build (8.3, DartBeta)
- GitHub Check: swift (server)
- GitHub Check: apple (client)
- GitHub Check: android (client)
🔇 Additional comments (9)
templates/android/library/src/main/java/io/package/Channel.kt.twig (4)
22-28: LGTM!The normalize helper correctly handles whitespace trimming and defaults empty IDs to the wildcard
*. Based on learnings, the intentional lack of validation/escaping aligns with the SDK's design pattern for lightweight helper utilities.
30-87: LGTM!The Channel class design is well-structured:
- Covariant
out Tis correctly applied since the type parameter is only used in output positions.- The
nextandresolvemethods are intentionally public for extension function access, as documented.- The
accountmethod returningStringdirectly (rather thanChannel) is a reasonable design choice since accounts don't follow the same nested resource pattern.
89-133: LGTM!The navigation extension functions provide clean, type-safe state transitions. The receiver type constraints ensure compile-time validation of valid channel paths (e.g., you can only call
.document()on aChannel<_Collection>).
134-261: LGTM with a minor note.The terminal action extensions are well-implemented with proper
@JvmNameannotations for JVM bytecode disambiguation. The type-restricted extension functions ensure only valid resource types can have terminal actions.Note: The comment at line 135 references "Actionable types" which relates to the misleading typealias flagged earlier—consider updating both together.
templates/apple/Sources/Channel.swift.twig (5)
19-23: LGTM!The normalize helper correctly handles empty/whitespace-only strings by defaulting to the wildcard
"*". Based on learnings, the intentional omission of validation/escaping aligns with the SDK's design pattern.
49-88: LGTM!The factory methods correctly construct channel paths. The
account()method returningStringdirectly (rather thanRealtimeChannel) is a reasonable design choice since the account channel doesn't support further chaining or terminal actions.The global event constants (
documents,rows,files,executions) provide convenient shortcuts for broad subscriptions.
90-139: LGTM!The constrained extensions correctly implement the type-state pattern, ensuring compile-time safety for valid channel paths. The routing hierarchy (Database→Collection→Document, TablesDB→Table→Row, etc.) is well-structured.
141-232: LGTM!The terminal action extensions correctly restrict
create(),update(), anddelete()to actionable channel types. While the code is repetitive, this is a necessary trade-off in Swift to achieve compile-time type safety with phantom types.
234-249: LGTM!The
ChannelValueprotocol provides a clean abstraction enabling subscribe APIs to accept both rawStringchannels andRealtimeChannelinstances uniformly. The conformances are straightforward and correct.
What does this PR do?
Here is a code example for the databases channel builder with realtime subscription
Test Plan
(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)
Related PRs and Issues
(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)
Have you read the Contributing Guidelines on issues?
(Write your answer here.)
Summary by CodeRabbit
New Features
API Changes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.