diff --git a/README.md b/README.md index e494336..e66343a 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,10 @@ dependencies { } ``` +## Migrating from stream-chat-java? + +If you are currently using [`stream-chat-java`](https://github.com/GetStream/stream-chat-java), we have a detailed migration guide with side-by-side code examples for common Chat use cases. See the [Migration Guide](docs/migration-from-stream-chat-java/README.md). + ## ✨ Getting started ### Configuration diff --git a/docs/migration-from-stream-chat-java/01-setup-and-auth.md b/docs/migration-from-stream-chat-java/01-setup-and-auth.md new file mode 100644 index 0000000..e8d2a01 --- /dev/null +++ b/docs/migration-from-stream-chat-java/01-setup-and-auth.md @@ -0,0 +1,176 @@ +# Setup and Authentication + +This guide shows how to migrate setup and authentication code from `stream-chat-java` to `stream-sdk-java`. + +## Installation + +**Before (stream-chat-java):** + +Maven: +```xml + + io.getstream + stream-chat-java + $streamVersion + +``` + +Gradle: +```groovy +implementation 'io.getstream:stream-chat-java:$streamVersion' +``` + +**After (stream-sdk-java):** + +Maven: +```xml + + io.getstream + stream-sdk-java + $streamVersion + +``` + +Gradle: +```groovy +implementation 'io.getstream:stream-sdk-java:$streamVersion' +``` + +**Key changes:** +- Artifact ID changes from `stream-chat-java` to `stream-sdk-java` + +## Client Initialization + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.services.framework.DefaultClient; +import java.util.Properties; + +Properties props = new Properties(); +props.put("io.getstream.chat.apiKey", "your-api-key"); +props.put("io.getstream.chat.apiSecret", "your-api-secret"); + +DefaultClient client = new DefaultClient(props); +DefaultClient.setInstance(client); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); +``` + +**Key changes:** +- `DefaultClient` with singleton pattern becomes `StreamSDKClient` with direct instantiation +- Property names change from `io.getstream.chat.*` to `io.getstream.*` +- Environment variables change from `STREAM_KEY`/`STREAM_SECRET` to `STREAM_API_KEY`/`STREAM_API_SECRET` + +## Client Initialization with Environment Variables + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.services.framework.DefaultClient; + +// Reads STREAM_KEY and STREAM_SECRET from environment +DefaultClient client = new DefaultClient(); +DefaultClient.setInstance(client); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; + +// Reads STREAM_API_KEY and STREAM_API_SECRET from environment +StreamSDKClient client = new StreamSDKClient(); +``` + +**Key changes:** +- Environment variable names change: `STREAM_KEY` to `STREAM_API_KEY`, `STREAM_SECRET` to `STREAM_API_SECRET` +- No singleton pattern required; use the client instance directly + +## Token Generation + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; +import java.util.Date; +import java.util.Calendar; + +// Token with no expiry +String token = User.createToken("user-id", null, null); + +// Token with expiry +Calendar cal = Calendar.getInstance(); +cal.add(Calendar.HOUR, 24); +String tokenWithExpiry = User.createToken("user-id", cal.getTime(), null); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +// Token with no expiry +String token = client.tokenBuilder().createToken("user-id"); + +// Token with expiry (validity in seconds) +String tokenWithExpiry = client.tokenBuilder().createToken("user-id", 24 * 60 * 60); +``` + +**Key changes:** +- Token creation moves from static `User.createToken()` to `client.tokenBuilder().createToken()` +- Expiry is specified as seconds (integer) instead of a `Date` object +- No need to pass `issuedAt` separately + +## Sub-clients + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.Message; + +// All operations are static methods on model classes +User.upsert().user(...).request(); +Channel.getOrCreate("messaging", "general").request(); +Message.send("messaging", "general").message(...).request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +// Operations are on sub-client interfaces +client.updateUsers(...).execute(); // Common (user operations) +client.chat().getOrCreateChannel(...).execute(); // Chat +client.chat().sendMessage(...).execute(); // Chat +client.moderation().ban(...).execute(); // Moderation +client.video().getOrCreateCall(...).execute(); // Video +``` + +**Key changes:** +- Static methods on model classes (`User.upsert()`, `Channel.getOrCreate()`) become instance methods on sub-clients +- User and device operations are on the root client (Common interface) +- `.request()` becomes `.execute()` to run the API call + +**Available sub-clients:** + +| Sub-client | Access | Description | +|------------|--------|-------------| +| Common | `client.*` (root) | Users, devices, app settings | +| Chat | `client.chat()` | Channels, messages, reactions | +| Video | `client.video()` | Calls, call types | +| Moderation | `client.moderation()` | Ban, mute, flag | +| Feeds | `client.feeds()` | Activity feeds | diff --git a/docs/migration-from-stream-chat-java/02-users.md b/docs/migration-from-stream-chat-java/02-users.md new file mode 100644 index 0000000..dea08ee --- /dev/null +++ b/docs/migration-from-stream-chat-java/02-users.md @@ -0,0 +1,275 @@ +# Users + +This guide shows how to migrate user operations from `stream-chat-java` to `stream-sdk-java`. + +## Upsert User + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; +import io.getstream.chat.java.models.User.UserRequestObject; + +User.upsert() + .user(UserRequestObject.builder() + .id("john") + .name("John Doe") + .role("admin") + .additionalField("country", "US") + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateUsersRequest; +import io.getstream.models.UserRequest; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.updateUsers(UpdateUsersRequest.builder() + .users(Map.of("john", UserRequest.builder() + .id("john") + .name("John Doe") + .role("admin") + .custom(Map.of("country", "US")) + .build())) + .build()) + .execute(); +``` + +**Key changes:** +- `User.upsert().user(...)` becomes `client.updateUsers(UpdateUsersRequest)` with a map of users keyed by ID +- `UserRequestObject` becomes `UserRequest` +- `additionalField()` becomes `custom(Map.of(...))` +- `.request()` becomes `.execute()` + +## Batch Upsert Users + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; +import io.getstream.chat.java.models.User.UserRequestObject; + +User.upsert() + .user(UserRequestObject.builder().id("alice").name("Alice").build()) + .user(UserRequestObject.builder().id("bob").name("Bob").build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateUsersRequest; +import io.getstream.models.UserRequest; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.updateUsers(UpdateUsersRequest.builder() + .users(Map.of( + "alice", UserRequest.builder().id("alice").name("Alice").build(), + "bob", UserRequest.builder().id("bob").name("Bob").build())) + .build()) + .execute(); +``` + +**Key changes:** +- Multiple `.user()` calls become a single map passed to `UpdateUsersRequest` + +## Query Users + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; +import io.getstream.chat.java.models.User.UserListResponse; + +UserListResponse response = User.list() + .filterCondition("id", "john") + .limit(10) + .offset(0) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.QueryUsersRequest; +import io.getstream.models.QueryUsersPayload; +import io.getstream.models.QueryUsersResponse; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +var response = client.queryUsers(QueryUsersRequest.builder() + .payload(QueryUsersPayload.builder() + .filterConditions(Map.of("id", "john")) + .limit(10) + .offset(0) + .build()) + .build()) + .execute(); + +var users = response.getData().getUsers(); +``` + +**Key changes:** +- `User.list()` with chained filter methods becomes `client.queryUsers()` with `QueryUsersRequest` +- Filters are a `Map` instead of chained `.filterCondition()` calls +- Response data is accessed via `.getData().getUsers()` instead of direct response fields + +## Partial Update User + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; +import io.getstream.chat.java.models.User.UserPartialUpdateRequestObject; + +User.partialUpdate() + .user(UserPartialUpdateRequestObject.builder() + .id("john") + .setValue("role", "admin") + .unsetValue("obsolete_field") + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateUsersPartialRequest; +import io.getstream.models.UpdateUserPartialRequest; +import java.util.List; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.updateUsersPartial(UpdateUsersPartialRequest.builder() + .users(List.of(UpdateUserPartialRequest.builder() + .id("john") + .set(Map.of("role", "admin")) + .unset(List.of("obsolete_field")) + .build())) + .build()) + .execute(); +``` + +**Key changes:** +- `User.partialUpdate().user(...)` becomes `client.updateUsersPartial()` with a list of `UpdateUserPartialRequest` +- `.setValue(key, value)` becomes `.set(Map.of(key, value))` +- `.unsetValue(key)` becomes `.unset(List.of(key))` + +## Deactivate User + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.deactivate("john") + .createdById("admin-user") + .markMessagesDeleted(true) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.DeactivateUserRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.deactivateUser("john", DeactivateUserRequest.builder() + .createdByID("admin-user") + .markMessagesDeleted(true) + .build()) + .execute(); +``` + +**Key changes:** +- `User.deactivate(userId)` becomes `client.deactivateUser(userId, request)` +- Builder options become fields on `DeactivateUserRequest` + +## Reactivate User + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.reactivate("john") + .createdById("admin-user") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.ReactivateUserRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.reactivateUser("john", ReactivateUserRequest.builder() + .createdByID("admin-user") + .build()) + .execute(); +``` + +**Key changes:** +- `User.reactivate(userId)` becomes `client.reactivateUser(userId, request)` + +## Delete Users + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; +import io.getstream.chat.java.models.User.DeleteStrategy; +import java.util.Arrays; + +// Single user delete +User.delete("john") + .markMessagesDeleted(true) + .hardDelete(false) + .request(); + +// Batch delete +User.deleteMany(Arrays.asList("alice", "bob")) + .setDeleteStrategy(DeleteStrategy.HARD) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.DeleteUsersRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +// Single or batch delete (same API) +client.deleteUsers(DeleteUsersRequest.builder() + .userIds(List.of("john")) + .user("hard") + .messages("hard") + .conversations("hard") + .build()) + .execute(); +``` + +**Key changes:** +- `User.delete()` and `User.deleteMany()` are unified into `client.deleteUsers()` +- Delete strategy is specified per resource type: `user`, `messages`, `conversations` (each accepts `"hard"` or `"soft"`) +- Always uses a list of user IDs, even for a single user diff --git a/docs/migration-from-stream-chat-java/03-channels.md b/docs/migration-from-stream-chat-java/03-channels.md new file mode 100644 index 0000000..132d2ae --- /dev/null +++ b/docs/migration-from-stream-chat-java/03-channels.md @@ -0,0 +1,418 @@ +# Channels + +This guide shows how to migrate channel operations from `stream-chat-java` to `stream-sdk-java`. + +## Create or Get a Channel + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.Channel.ChannelRequestObject; +import io.getstream.chat.java.models.User.UserRequestObject; + +Channel.getOrCreate("messaging", "general") + .data(ChannelRequestObject.builder() + .createdBy(UserRequestObject.builder().id("admin").build()) + .additionalField("description", "General chat") + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.GetOrCreateChannelRequest; +import io.getstream.models.ChannelInput; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().getOrCreateChannel("messaging", "general", + GetOrCreateChannelRequest.builder() + .data(ChannelInput.builder() + .createdByID("admin") + .custom(Map.of("description", "General chat")) + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.getOrCreate(type, id)` becomes `client.chat().getOrCreateChannel(type, id, request)` +- `ChannelRequestObject` becomes `ChannelInput` +- `.createdBy(UserRequestObject)` becomes `.createdByID("admin")` (just the user ID) +- `.additionalField()` becomes `.custom(Map.of(...))` + +## Create a Channel with Members + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.Channel.ChannelRequestObject; +import io.getstream.chat.java.models.Channel.ChannelMemberRequestObject; +import io.getstream.chat.java.models.User.UserRequestObject; +import java.util.Arrays; + +Channel.getOrCreate("messaging", "team-chat") + .data(ChannelRequestObject.builder() + .createdBy(UserRequestObject.builder().id("admin").build()) + .members(Arrays.asList( + ChannelMemberRequestObject.builder().userId("alice").build(), + ChannelMemberRequestObject.builder().userId("bob").build())) + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.GetOrCreateChannelRequest; +import io.getstream.models.ChannelInput; +import io.getstream.models.ChannelMemberRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().getOrCreateChannel("messaging", "team-chat", + GetOrCreateChannelRequest.builder() + .data(ChannelInput.builder() + .createdByID("admin") + .members(List.of( + ChannelMemberRequest.builder().userID("alice").build(), + ChannelMemberRequest.builder().userID("bob").build())) + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `ChannelMemberRequestObject` becomes `ChannelMemberRequest` +- `.userId("alice")` becomes `.userID("alice")` + +## Create a Distinct (1:1) Channel + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.Channel.ChannelRequestObject; +import io.getstream.chat.java.models.Channel.ChannelMemberRequestObject; +import java.util.Arrays; + +Channel.getOrCreate("messaging") + .data(ChannelRequestObject.builder() + .members(Arrays.asList( + ChannelMemberRequestObject.builder().userId("alice").build(), + ChannelMemberRequestObject.builder().userId("bob").build())) + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.GetOrCreateDistinctChannelRequest; +import io.getstream.models.ChannelInput; +import io.getstream.models.ChannelMemberRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().getOrCreateDistinctChannel("messaging", + GetOrCreateDistinctChannelRequest.builder() + .data(ChannelInput.builder() + .members(List.of( + ChannelMemberRequest.builder().userID("alice").build(), + ChannelMemberRequest.builder().userID("bob").build())) + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.getOrCreate(type)` without an ID becomes `client.chat().getOrCreateDistinctChannel(type, request)` +- Separate method name makes the intent explicit + +## Query Channels + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.Channel.ChannelListResponse; +import io.getstream.chat.java.models.User.UserRequestObject; +import io.getstream.chat.java.models.Sort; + +ChannelListResponse response = Channel.list() + .user(UserRequestObject.builder().id("admin").build()) + .filterCondition("type", "messaging") + .sort(Sort.builder().field("last_message_at").direction(Sort.Direction.DESC).build()) + .limit(10) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.QueryChannelsRequest; +import io.getstream.models.SortParamRequest; +import java.util.List; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +var response = client.chat().queryChannels(QueryChannelsRequest.builder() + .userID("admin") + .filterConditions(Map.of("type", "messaging")) + .sort(List.of(SortParamRequest.builder() + .field("last_message_at") + .direction(-1) + .build())) + .limit(10) + .build()) + .execute(); + +var channels = response.getData().getChannels(); +``` + +**Key changes:** +- `Channel.list()` becomes `client.chat().queryChannels()` +- `.user(UserRequestObject)` becomes `.userID("admin")` +- Filters and sort are typed objects instead of chained builder calls +- Sort direction uses `-1` (descending) / `1` (ascending) instead of `Sort.Direction` enum + +## Update a Channel + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.User.UserRequestObject; +import java.util.Arrays; + +Channel.update("messaging", "general") + .user(UserRequestObject.builder().id("admin").build()) + .addModerators(Arrays.asList("alice")) + .removeModerators(Arrays.asList("bob")) + .cooldown(30) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateChannelRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().updateChannel("messaging", "general", + UpdateChannelRequest.builder() + .addModerators(List.of("alice")) + .demoteModerators(List.of("bob")) + .cooldown(30) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.update(type, id)` becomes `client.chat().updateChannel(type, id, request)` +- `.removeModerators()` becomes `.demoteModerators()` +- No user object required on the request + +## Add and Remove Members + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import java.util.Arrays; + +Channel.update("messaging", "general") + .addUserIds(Arrays.asList("charlie")) + .removeUserIds(Arrays.asList("dave")) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateChannelRequest; +import io.getstream.models.ChannelMemberRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().updateChannel("messaging", "general", + UpdateChannelRequest.builder() + .addMembers(List.of( + ChannelMemberRequest.builder().userID("charlie").build())) + .removeMembers(List.of("dave")) + .build()) + .execute(); +``` + +**Key changes:** +- `.addUserIds()` becomes `.addMembers()` with `ChannelMemberRequest` objects +- `.removeUserIds()` becomes `.removeMembers()` with a list of user ID strings + +## Partial Update a Channel + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; + +Channel.partialUpdate("messaging", "general") + .setValue("topic", "New Topic") + .unsetValue("old_field") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateChannelPartialRequest; +import java.util.List; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().updateChannelPartial("messaging", "general", + UpdateChannelPartialRequest.builder() + .set(Map.of("topic", "New Topic")) + .unset(List.of("old_field")) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.partialUpdate()` becomes `client.chat().updateChannelPartial()` +- `.setValue(key, val)` becomes `.set(Map.of(key, val))` +- `.unsetValue(key)` becomes `.unset(List.of(key))` + +## Query Members + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.Sort; + +Channel.queryMembers() + .type("messaging") + .id("general") + .filterCondition("notifications_muted", true) + .sort(Sort.builder().field("created_at").build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.QueryMembersRequest; +import io.getstream.models.QueryMembersPayload; +import io.getstream.models.SortParamRequest; +import java.util.List; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().queryMembers(QueryMembersRequest.builder() + .payload(QueryMembersPayload.builder() + .type("messaging") + .id("general") + .filterConditions(Map.of("notifications_muted", true)) + .sort(List.of(SortParamRequest.builder().field("created_at").build())) + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.queryMembers()` becomes `client.chat().queryMembers()` +- Filter conditions are a `Map` instead of chained calls + +## Delete a Channel + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; + +Channel.delete("messaging", "general").request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.DeleteChannelRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +// Soft delete +client.chat().deleteChannel("messaging", "general").execute(); + +// Hard delete +client.chat().deleteChannel("messaging", "general", + DeleteChannelRequest.builder() + .hardDelete(true) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.delete(type, id)` becomes `client.chat().deleteChannel(type, id)` +- Hard delete is specified via `DeleteChannelRequest` with `.hardDelete(true)` + +## Truncate a Channel + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import io.getstream.chat.java.models.Message.MessageRequestObject; + +Channel.truncate("messaging", "general") + .skipPush(true) + .message(MessageRequestObject.builder() + .text("Channel truncated") + .userId("admin") + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.TruncateChannelRequest; +import io.getstream.models.MessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().truncateChannel("messaging", "general", + TruncateChannelRequest.builder() + .skipPush(true) + .message(MessageRequest.builder() + .text("Channel truncated") + .userID("admin") + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.truncate()` becomes `client.chat().truncateChannel()` +- `MessageRequestObject` becomes `MessageRequest` diff --git a/docs/migration-from-stream-chat-java/04-messages-and-reactions.md b/docs/migration-from-stream-chat-java/04-messages-and-reactions.md new file mode 100644 index 0000000..e080b6c --- /dev/null +++ b/docs/migration-from-stream-chat-java/04-messages-and-reactions.md @@ -0,0 +1,422 @@ +# Messages and Reactions + +This guide shows how to migrate message and reaction operations from `stream-chat-java` to `stream-sdk-java`. + +## Send a Message + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; +import io.getstream.chat.java.models.Message.MessageRequestObject; + +Message.send("messaging", "general") + .message(MessageRequestObject.builder() + .text("Hello, world!") + .userId("john") + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.SendMessageRequest; +import io.getstream.models.MessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().sendMessage("messaging", "general", + SendMessageRequest.builder() + .message(MessageRequest.builder() + .text("Hello, world!") + .userID("john") + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `Message.send(type, id)` becomes `client.chat().sendMessage(type, id, request)` +- `MessageRequestObject` becomes `MessageRequest` +- `.userId()` becomes `.userID()` + +## Send a Message with Options + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; +import io.getstream.chat.java.models.Message.MessageRequestObject; + +Message.send("messaging", "general") + .message(MessageRequestObject.builder() + .text("Silent notification") + .userId("john") + .build()) + .skipPush(true) + .skipEnrichUrl(true) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.SendMessageRequest; +import io.getstream.models.MessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().sendMessage("messaging", "general", + SendMessageRequest.builder() + .message(MessageRequest.builder() + .text("Silent notification") + .userID("john") + .build()) + .skipPush(true) + .skipEnrichUrl(true) + .build()) + .execute(); +``` + +**Key changes:** +- Options like `skipPush` and `skipEnrichUrl` go on `SendMessageRequest` (the outer wrapper), not chained on the builder + +## Send a Thread Reply + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; +import io.getstream.chat.java.models.Message.MessageRequestObject; + +Message.send("messaging", "general") + .message(MessageRequestObject.builder() + .text("This is a reply") + .userId("john") + .parentId("parent-message-id") + .showInChannel(true) + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.SendMessageRequest; +import io.getstream.models.MessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().sendMessage("messaging", "general", + SendMessageRequest.builder() + .message(MessageRequest.builder() + .text("This is a reply") + .userID("john") + .parentID("parent-message-id") + .showInChannel(true) + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `.parentId()` becomes `.parentID()` + +## Get a Message + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; + +var response = Message.get("message-id") + .showDeletedMessages(true) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.GetMessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +var response = client.chat().getMessage("message-id", + GetMessageRequest.builder() + .ShowDeletedMessage(true) + .build()) + .execute(); + +var message = response.getData().getMessage(); +``` + +**Key changes:** +- `Message.get(id)` becomes `client.chat().getMessage(id, request)` +- Response accessed via `.getData().getMessage()` + +## Update a Message + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; +import io.getstream.chat.java.models.Message.MessageRequestObject; + +Message.update("message-id") + .message(MessageRequestObject.builder() + .text("Updated text") + .userId("john") + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateMessageRequest; +import io.getstream.models.MessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().updateMessage("message-id", + UpdateMessageRequest.builder() + .message(MessageRequest.builder() + .text("Updated text") + .userID("john") + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `Message.update(id)` becomes `client.chat().updateMessage(id, request)` + +## Partial Update a Message + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; + +Message.partialUpdate("message-id") + .setValue("custom_field", "new value") + .unsetValue("old_field") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateMessagePartialRequest; +import java.util.List; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().updateMessagePartial("message-id", + UpdateMessagePartialRequest.builder() + .set(Map.of("custom_field", "new value")) + .unset(List.of("old_field")) + .build()) + .execute(); +``` + +**Key changes:** +- `Message.partialUpdate(id)` becomes `client.chat().updateMessagePartial(id, request)` +- `.setValue()`/`.unsetValue()` becomes `.set(Map)`/`.unset(List)` + +## Delete a Message + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; + +// Soft delete +Message.delete("message-id").request(); + +// Hard delete +Message.hardDelete("message-id").request(); + +// Delete by specific user +Message.delete("message-id") + .deletedBy("admin") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.DeleteMessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +// Soft delete +client.chat().deleteMessage("message-id").execute(); + +// Hard delete +client.chat().deleteMessage("message-id", + DeleteMessageRequest.builder() + .hard(true) + .build()) + .execute(); + +// Delete by specific user +client.chat().deleteMessage("message-id", + DeleteMessageRequest.builder() + .deletedBy("admin") + .build()) + .execute(); +``` + +**Key changes:** +- `Message.delete()`/`Message.hardDelete()` are unified into `client.chat().deleteMessage()` with optional `DeleteMessageRequest` +- Hard delete is a boolean flag instead of a separate method + +## Get Replies + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Message; + +var response = Message.getReplies("parent-message-id") + .limit(25) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.GetRepliesRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +var response = client.chat().getReplies("parent-message-id", + GetRepliesRequest.builder() + .limit(25) + .build()) + .execute(); + +var replies = response.getData().getMessages(); +``` + +**Key changes:** +- `Message.getReplies(parentId)` becomes `client.chat().getReplies(parentId, request)` + +## Send a Reaction + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Reaction; +import io.getstream.chat.java.models.Reaction.ReactionRequestObject; +import io.getstream.chat.java.models.User.UserRequestObject; + +Reaction.send("message-id") + .reaction(ReactionRequestObject.builder() + .type("like") + .user(UserRequestObject.builder().id("john").build()) + .build()) + .enforceUnique(true) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.SendReactionRequest; +import io.getstream.models.ReactionRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().sendReaction("message-id", + SendReactionRequest.builder() + .reaction(ReactionRequest.builder() + .type("like") + .userID("john") + .build()) + .enforceUnique(true) + .build()) + .execute(); +``` + +**Key changes:** +- `Reaction.send(messageId)` becomes `client.chat().sendReaction(messageId, request)` +- `.user(UserRequestObject)` becomes `.userID("john")` on `ReactionRequest` +- `ReactionRequestObject` becomes `ReactionRequest` + +## List Reactions + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Reaction; + +var response = Reaction.list("message-id") + .limit(25) + .offset(0) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.GetReactionsRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +var response = client.chat().getReactions("message-id", + GetReactionsRequest.builder() + .limit(25) + .offset(0) + .build()) + .execute(); + +var reactions = response.getData().getReactions(); +``` + +**Key changes:** +- `Reaction.list(messageId)` becomes `client.chat().getReactions(messageId, request)` + +## Delete a Reaction + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Reaction; + +Reaction.delete("message-id", "like") + .userId("john") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.DeleteReactionRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().deleteReaction("message-id", "like", + DeleteReactionRequest.builder() + .userID("john") + .build()) + .execute(); +``` + +**Key changes:** +- `Reaction.delete(messageId, type)` becomes `client.chat().deleteReaction(messageId, type, request)` +- `.userId()` moves into `DeleteReactionRequest` as `.userID()` diff --git a/docs/migration-from-stream-chat-java/05-moderation.md b/docs/migration-from-stream-chat-java/05-moderation.md new file mode 100644 index 0000000..ad72c96 --- /dev/null +++ b/docs/migration-from-stream-chat-java/05-moderation.md @@ -0,0 +1,337 @@ +# Moderation + +This guide shows how to migrate moderation operations from `stream-chat-java` to `stream-sdk-java`. + +## Add Moderators + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import java.util.Arrays; + +Channel.update("messaging", "general") + .addModerators(Arrays.asList("alice", "bob")) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateChannelRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().updateChannel("messaging", "general", + UpdateChannelRequest.builder() + .addModerators(List.of("alice", "bob")) + .build()) + .execute(); +``` + +**Key changes:** +- `Channel.update()` becomes `client.chat().updateChannel()` +- Same field name `.addModerators()` on `UpdateChannelRequest` + +## Remove Moderators + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Channel; +import java.util.Arrays; + +Channel.update("messaging", "general") + .removeModerators(Arrays.asList("alice")) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UpdateChannelRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().updateChannel("messaging", "general", + UpdateChannelRequest.builder() + .demoteModerators(List.of("alice")) + .build()) + .execute(); +``` + +**Key changes:** +- `.removeModerators()` becomes `.demoteModerators()` + +## Ban a User (App-level) + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.ban() + .userId("admin") + .targetUserId("spammer") + .reason("Spamming") + .timeout(3600) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.BanRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.moderation().ban(BanRequest.builder() + .targetUserID("spammer") + .bannedByID("admin") + .reason("Spamming") + .timeout(3600) + .build()) + .execute(); +``` + +**Key changes:** +- `User.ban()` becomes `client.moderation().ban()` +- `.userId()` (the banner) becomes `.bannedByID()` +- `.targetUserId()` becomes `.targetUserID()` + +## Ban a User (Channel-level) + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.ban() + .userId("admin") + .targetUserId("spammer") + .type("messaging") + .id("general") + .reason("Off-topic") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.BanRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.moderation().ban(BanRequest.builder() + .targetUserID("spammer") + .bannedByID("admin") + .channelCid("messaging:general") + .reason("Off-topic") + .build()) + .execute(); +``` + +**Key changes:** +- `.type("messaging").id("general")` becomes `.channelCid("messaging:general")` (combined CID format) + +## Shadow Ban + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.shadowBan() + .userId("admin") + .targetUserId("troll") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.BanRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.moderation().ban(BanRequest.builder() + .targetUserID("troll") + .bannedByID("admin") + .shadow(true) + .build()) + .execute(); +``` + +**Key changes:** +- `User.shadowBan()` is no longer a separate method; use `client.moderation().ban()` with `.shadow(true)` + +## Unban a User + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.unban("spammer") + .createdBy("admin") + .request(); + +// Channel-level unban +User.unban("spammer") + .type("messaging") + .id("general") + .createdBy("admin") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UnbanRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +// App-level unban +client.moderation().unban(UnbanRequest.builder() + .targetUserID("spammer") + .build()) + .execute(); + +// Channel-level unban +client.moderation().unban(UnbanRequest.builder() + .targetUserID("spammer") + .channelCid("messaging:general") + .build()) + .execute(); +``` + +**Key changes:** +- `User.unban(targetId)` becomes `client.moderation().unban(UnbanRequest)` +- `.type().id()` becomes `.channelCid("type:id")` + +## Query Banned Users + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +var response = User.queryBanned() + .filterCondition("username", "john") + .limit(25) + .offset(0) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.QueryBannedUsersRequest; +import io.getstream.models.QueryBannedUsersPayload; +import java.util.Map; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +var response = client.moderation().queryBannedUsers(QueryBannedUsersRequest.builder() + .payload(QueryBannedUsersPayload.builder() + .filterConditions(Map.of("username", "john")) + .limit(25) + .offset(0) + .build()) + .build()) + .execute(); +``` + +**Key changes:** +- `User.queryBanned()` becomes `client.moderation().queryBannedUsers()` + +## Mute a User + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.mute() + .userId("john") + .targetUserId("noisy-user") + .timeout(60) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.MuteRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.moderation().mute(MuteRequest.builder() + .userID("john") + .targetIds(List.of("noisy-user")) + .timeout(60) + .build()) + .execute(); +``` + +**Key changes:** +- `User.mute()` becomes `client.moderation().mute()` +- `.targetUserId()` becomes `.targetIds(List.of(...))`, allowing batch muting + +## Unmute a User + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.User; + +User.unmute() + .userId("john") + .targetUserId("noisy-user") + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.UnmuteRequest; +import java.util.List; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.moderation().unmute(UnmuteRequest.builder() + .userID("john") + .targetIds(List.of("noisy-user")) + .build()) + .execute(); +``` + +**Key changes:** +- `User.unmute()` becomes `client.moderation().unmute()` +- `.targetUserId()` becomes `.targetIds(List.of(...))` + +## Method Mapping Summary + +| Operation | stream-chat-java | stream-sdk-java | +|-----------|-----------------|-----------------| +| Add moderators | `Channel.update().addModerators()` | `client.chat().updateChannel()` with `.addModerators()` | +| Remove moderators | `Channel.update().removeModerators()` | `client.chat().updateChannel()` with `.demoteModerators()` | +| Ban (app-level) | `User.ban()` | `client.moderation().ban()` | +| Ban (channel-level) | `User.ban().type().id()` | `client.moderation().ban()` with `.channelCid()` | +| Shadow ban | `User.shadowBan()` | `client.moderation().ban()` with `.shadow(true)` | +| Unban | `User.unban()` | `client.moderation().unban()` | +| Mute | `User.mute()` | `client.moderation().mute()` | +| Unmute | `User.unmute()` | `client.moderation().unmute()` | +| Query banned | `User.queryBanned()` | `client.moderation().queryBannedUsers()` | diff --git a/docs/migration-from-stream-chat-java/06-devices.md b/docs/migration-from-stream-chat-java/06-devices.md new file mode 100644 index 0000000..904a45f --- /dev/null +++ b/docs/migration-from-stream-chat-java/06-devices.md @@ -0,0 +1,179 @@ +# Devices + +This guide shows how to migrate device management operations from `stream-chat-java` to `stream-sdk-java`. + +## Add a Device (APN) + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Device; +import io.getstream.chat.java.models.Device.PushProviderType; +import io.getstream.chat.java.models.User.UserRequestObject; + +Device.create() + .id("device-token-123") + .user(UserRequestObject.builder().id("john").build()) + .pushProvider(PushProviderType.Apn) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.CreateDeviceRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.createDevice(CreateDeviceRequest.builder() + .id("device-token-123") + .userID("john") + .pushProvider("apn") + .build()) + .execute(); +``` + +**Key changes:** +- `Device.create()` becomes `client.createDevice()` +- `.user(UserRequestObject)` becomes `.userID("john")` +- `PushProviderType.Apn` enum becomes the string `"apn"` + +## Add a Device (Firebase) + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Device; +import io.getstream.chat.java.models.Device.PushProviderType; +import io.getstream.chat.java.models.User.UserRequestObject; + +Device.create() + .id("fcm-token-456") + .user(UserRequestObject.builder().id("john").build()) + .pushProvider(PushProviderType.Firebase) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.CreateDeviceRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.createDevice(CreateDeviceRequest.builder() + .id("fcm-token-456") + .userID("john") + .pushProvider("firebase") + .build()) + .execute(); +``` + +**Key changes:** +- `PushProviderType.Firebase` becomes the string `"firebase"` + +## Add a VoIP Device + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Device; +import io.getstream.chat.java.models.Device.PushProviderType; +import io.getstream.chat.java.models.User.UserRequestObject; + +// No dedicated VoIP support; same as regular APN device +Device.create() + .id("voip-token-789") + .user(UserRequestObject.builder().id("john").build()) + .pushProvider(PushProviderType.Apn) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.CreateDeviceRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.createDevice(CreateDeviceRequest.builder() + .id("voip-token-789") + .userID("john") + .pushProvider("apn") + .voipToken(true) + .build()) + .execute(); +``` + +**Key changes:** +- New SDK adds `.voipToken(true)` for Apple VoIP push tokens + +## List Devices + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Device; + +var response = Device.list("john").request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.ListDevicesRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +var response = client.listDevices(ListDevicesRequest.builder() + .userID("john") + .build()) + .execute(); + +var devices = response.getData().getDevices(); +``` + +**Key changes:** +- `Device.list(userId)` becomes `client.listDevices(ListDevicesRequest)` +- User ID moves from a positional argument to a field on the request object + +## Delete a Device + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.models.Device; + +Device.delete("device-token-123", "john").request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.DeleteDeviceRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.deleteDevice(DeleteDeviceRequest.builder() + .id("device-token-123") + .userID("john") + .build()) + .execute(); +``` + +**Key changes:** +- `Device.delete(deviceId, userId)` becomes `client.deleteDevice(DeleteDeviceRequest)` +- Positional arguments become named fields on the request object + +## Method Mapping Summary + +| Operation | stream-chat-java | stream-sdk-java | +|-----------|-----------------|-----------------| +| Add device | `Device.create()` | `client.createDevice()` | +| List devices | `Device.list(userId)` | `client.listDevices()` | +| Delete device | `Device.delete(deviceId, userId)` | `client.deleteDevice()` | diff --git a/docs/migration-from-stream-chat-java/README.md b/docs/migration-from-stream-chat-java/README.md new file mode 100644 index 0000000..ba5141b --- /dev/null +++ b/docs/migration-from-stream-chat-java/README.md @@ -0,0 +1,82 @@ +# Migrating from stream-chat-java to stream-sdk-java + +## Why Migrate? + +- `stream-sdk-java` is the actively developed, long-term-supported SDK +- Covers Chat, Video, Moderation, and Feeds in a single package +- Strongly typed models generated from the official OpenAPI spec +- `stream-chat-java` will enter maintenance mode (critical fixes only) + +## Key Differences + +| Aspect | stream-chat-java | stream-sdk-java | +|--------|-----------------|-----------------| +| Package | `io.getstream:stream-chat-java` | `io.getstream:stream-sdk-java` | +| Client class | `DefaultClient` (singleton) | `StreamSDKClient` (instance) | +| API pattern | Static methods on model classes (`User.upsert()`, `Channel.getOrCreate()`) | Instance methods on sub-clients (`client.chat()`, `client.moderation()`) | +| Models | Builder classes nested in model files (`UserRequestObject`, `ChannelRequestObject`) | Standalone generated request classes (`UserRequest`, `ChannelInput`) | +| Custom fields | `.additionalField(key, value)` | `.custom(Map.of(key, value))` | +| Execution | `.request()` | `.execute()` | +| Tokens | `User.createToken(userId, expiry, issuedAt)` | `client.tokenBuilder().createToken(userId, validitySeconds)` | +| Env vars | `STREAM_KEY`, `STREAM_SECRET` | `STREAM_API_KEY`, `STREAM_API_SECRET` | + +## Quick Example + +**Before (stream-chat-java):** + +```java +import io.getstream.chat.java.services.framework.DefaultClient; +import io.getstream.chat.java.models.Message; +import io.getstream.chat.java.models.Message.MessageRequestObject; +import java.util.Properties; + +Properties props = new Properties(); +props.put("io.getstream.chat.apiKey", "your-api-key"); +props.put("io.getstream.chat.apiSecret", "your-api-secret"); +DefaultClient client = new DefaultClient(props); +DefaultClient.setInstance(client); + +Message.send("messaging", "general") + .message(MessageRequestObject.builder() + .text("Hello!") + .userId("john") + .build()) + .request(); +``` + +**After (stream-sdk-java):** + +```java +import io.getstream.services.framework.StreamSDKClient; +import io.getstream.models.SendMessageRequest; +import io.getstream.models.MessageRequest; + +StreamSDKClient client = new StreamSDKClient("your-api-key", "your-api-secret"); + +client.chat().sendMessage("messaging", "general", + SendMessageRequest.builder() + .message(MessageRequest.builder() + .text("Hello!") + .userID("john") + .build()) + .build()) + .execute(); +``` + +## Migration Guides by Topic + +| # | Topic | File | +|---|-------|------| +| 1 | [Setup and Authentication](01-setup-and-auth.md) | Client init, tokens | +| 2 | [Users](02-users.md) | Upsert, query, update, delete | +| 3 | [Channels](03-channels.md) | Create, query, members, update | +| 4 | [Messages and Reactions](04-messages-and-reactions.md) | Send, reply, react | +| 5 | [Moderation](05-moderation.md) | Ban, mute, moderators | +| 6 | [Devices](06-devices.md) | Push device management | + +## Notes + +- `stream-chat-java` is not going away. Your existing integration will keep working. +- The new SDK uses Lombok builders for all request model creation. +- All API calls return `StreamRequest` objects; call `.execute()` to run them. +- If you find a use case missing from this guide, please open an issue. diff --git a/src/main/java/io/getstream/services/ModerationClient.java b/src/main/java/io/getstream/services/ModerationClient.java new file mode 100644 index 0000000..2ff8ce1 --- /dev/null +++ b/src/main/java/io/getstream/services/ModerationClient.java @@ -0,0 +1,16 @@ +package io.getstream.services; + +import io.getstream.services.framework.StreamSDKClient; + +public class ModerationClient extends ModerationImpl implements Moderation { + StreamSDKClient client; + + public ModerationClient(StreamSDKClient client) { + super(client.getHttpClient()); + this.client = client; + } + + public StreamSDKClient getSDKClient() { + return client; + } +} diff --git a/src/main/java/io/getstream/services/framework/StreamSDKClient.java b/src/main/java/io/getstream/services/framework/StreamSDKClient.java index 75f36ff..4134538 100644 --- a/src/main/java/io/getstream/services/framework/StreamSDKClient.java +++ b/src/main/java/io/getstream/services/framework/StreamSDKClient.java @@ -40,6 +40,10 @@ public Feeds feeds() { return new FeedsClient(this); } + public Moderation moderation() { + return new ModerationClient(this); + } + public TokenBuilder tokenBuilder() { var tb = new TokenBuilder(httpClient.getApiSecret()); return tb; diff --git a/src/test/java/io/getstream/ModerationIntegrationTest.java b/src/test/java/io/getstream/ModerationIntegrationTest.java index dfd354b..2af2bd7 100644 --- a/src/test/java/io/getstream/ModerationIntegrationTest.java +++ b/src/test/java/io/getstream/ModerationIntegrationTest.java @@ -3,7 +3,7 @@ import static org.junit.jupiter.api.Assertions.*; import io.getstream.models.*; -import io.getstream.services.ModerationImpl; +import io.getstream.services.Moderation; import java.util.*; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.MethodOrderer; @@ -49,7 +49,7 @@ void testFlagMessageAndUser() throws Exception { // Send a message to flag String msgId = sendTestMessage("messaging", channelId, userId, "Message to be flagged"); - ModerationImpl moderation = new ModerationImpl(client.getHttpClient()); + Moderation moderation = client.moderation(); // Flag the message var flagMsgResp = @@ -90,7 +90,7 @@ void testMuteUnmuteUser() throws Exception { String muterId = userIds.get(0); String targetId = userIds.get(1); - ModerationImpl moderation = new ModerationImpl(client.getHttpClient()); + Moderation moderation = client.moderation(); // Mute target user as muter (no timeout) var muteResp = @@ -146,7 +146,7 @@ void testBanUnbanUser() throws Exception { createdChannelIds.add(channelId); String cid = "messaging:" + channelId; - ModerationImpl moderation = new ModerationImpl(client.getHttpClient()); + Moderation moderation = client.moderation(); // Ban target user from channel var banResp =