diff --git a/.github/workflows/publish-release-version.yml b/.github/workflows/publish-release-version.yml
index 993c931..7d6c94b 100644
--- a/.github/workflows/publish-release-version.yml
+++ b/.github/workflows/publish-release-version.yml
@@ -30,7 +30,7 @@ jobs:
- name: Build and Publish
env:
- TIMEMATES_SDK_VERSION: ${{ github.ref }}
+ TIMEMATES_SDK_VERSION: ${{ github.ref_name }}
TIMEMATES_SSH_DEPLOY_PATH: ${{ secrets.TIMEMATES_SSH_DEPLOY_PATH }}
TIMEMATES_SSH_HOST: ${{ secrets.TIMEMATES_SSH_HOST }}
TIMEMATES_SSH_PASSWORD: ${{ secrets.TIMEMATES_SSH_PASSWORD }}
diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml
index a6ea7ce..e8ebb4b 100644
--- a/.github/workflows/run-tests.yml
+++ b/.github/workflows/run-tests.yml
@@ -17,4 +17,4 @@ jobs:
distribution: 'corretto'
java-version: '17'
cache: 'gradle'
- - run: ./gradlew test --no-daemon
+ - run: ./gradlew build --no-daemon
diff --git a/README.md b/README.md
index d6fafaf..0b05aed 100644
--- a/README.md
+++ b/README.md
@@ -11,8 +11,9 @@ platform and integrate its features into your own applications.
To demonstrate the usage of the SDK, consider the following example:
```kotlin
-val engineBuilder = DefaultGrpcEngineBuilder()
-val engine = GrpcTimeMatesRequestsEngine(engineBuilder)
+val engine = RSocketTimeMatesRequestsEngine(
+ coroutineScope = Dispatchers.IO,
+)
val emailAuth = AccountLoginApi(engineBuilder).email
val email = EmailAddress.create("developer@y9vad9.com").getOrElse { return }
@@ -24,12 +25,6 @@ val authorizationResult = emailAuth.authorize(email)
// until we complete our registration
.map { (isNewAccount, authorization) -> ... }
```
-> **Note**
-> For android use [AndroidGrpcEngineBuilder](/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt)
->```kotlin
-> val engineBuilder = AndroidGrpcEngineBuilder(applicationContext)
->```
-
In the provided code snippet, the SDK utilizes the Kotlin Result API extensively.
It's important to note that the SDK's value objects, such as `EmailAddress`
@@ -77,9 +72,7 @@ repositories {
dependencies {
implementation("io.timemates:sdk:$version")
- implementation("io.timemates:grpc-engine:$version")
- // for android
- implementation("io.timemates:grpc-engine-android:$version")
+ implementation("io.timemates:rsocket-engine:$version")
}
```
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b0098e7..362fe81 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,5 @@
[versions]
-kotlin = "1.8.21"
+kotlin = "1.9.20-Beta"
kotlinx-coroutines = "1.6.4"
kotlinx-serialization = "1.4.1"
ktor = "2.0.1"
@@ -7,7 +7,7 @@ kafka = "3.3.1"
jupiter = "5.4.0"
exposed = "0.41.1"
kmongo = "4.8.0"
-androidGradlePlugin = "8.2.0-alpha13"
+androidGradlePlugin = "8.3.0-alpha05"
androidComposeVersion = "1.4.0-alpha02"
grpc = "1.3.0"
protobuf = "3.22.0"
@@ -15,6 +15,7 @@ protobuf-plugin = "0.9.2"
grpc-netty = "1.55.1"
android-target = "33"
android-min = "24"
+rsproto = "0.3.2"
[libraries]
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
@@ -66,6 +67,11 @@ grpc-android = { module = "io.grpc:grpc-android", version.require = "1.56.1" }
protobuf-kotlin = { module = "com.google.protobuf:protobuf-kotlin", version.ref = "protobuf" }
protobuf-java = { module = "com.google.protobuf:protobuf-java", version.ref = "protobuf" }
+rsocket-client = { module = "io.rsocket.kotlin:rsocket-ktor-client", version.require = "0.15.4" }
+
+timemates-rsproto-client = { module = "io.timemates.rsproto:client-core", version.ref = "rsproto" }
+timemates-rsproto-common = { module = "io.timemates.rsproto:common-core", version.ref = "rsproto" }
+
[plugins]
kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
@@ -76,3 +82,4 @@ android-library = { id = "com.android.library", version.ref = "androidGradlePlug
android-application = { id = "com.android.library", version.ref = "androidGradlePlugin" }
google-protobuf = { id = "com.google.protobuf", version.ref = "protobuf-plugin" }
library-publish = { id = "publish-library", version.require = "SNAPSHOT" }
+timemates-rsproto = { id = "io.timemates.rsproto", version.ref = "rsproto" }
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 15de902..b982b3c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-rc-2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/grpc-engine/android/build.gradle.kts b/grpc-engine/android/build.gradle.kts
deleted file mode 100644
index 27b1883..0000000
--- a/grpc-engine/android/build.gradle.kts
+++ /dev/null
@@ -1,48 +0,0 @@
-plugins {
- alias(libs.plugins.android.library)
- alias(libs.plugins.kotlin.android)
- alias(libs.plugins.library.publish)
-}
-
-android {
- compileSdk = libs.versions.android.target.get().toInt()
-
- defaultConfig {
- minSdk = libs.versions.android.min.get().toInt()
- }
-
- compileOptions {
- targetCompatibility = JavaVersion.VERSION_17
- sourceCompatibility = JavaVersion.VERSION_17
- }
-
- namespace = "io.timemates.android.grpc"
-}
-
-dependencies {
- implementation(projects.grpcEngine)
-
- implementation(libs.grpc.android)
-}
-
-kotlin {
- jvmToolchain(17)
-}
-
-deployLibrary {
- ssh(tag = "maven.timemates.io") {
- host = System.getenv("TIMEMATES_SSH_HOST")
- user = System.getenv("TIMEMATES_SSH_USER")
- password = System.getenv("TIMEMATES_SSH_PASSWORD")
- deployPath = System.getenv("TIMEMATES_SSH_DEPLOY_PATH")
-
- group = "io.timemates"
- componentName = "release"
- artifactId = "grpc-engine-android"
- name = "grpc-engine-android"
-
- description = "TimeMates android grpc adapter for SDK"
-
- version = System.getenv("TIMEMATES_SDK_VERSION")
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt b/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt
deleted file mode 100644
index 377b055..0000000
--- a/grpc-engine/android/src/main/kotlin/io/timemates/android/grpc/AndroidGrpcEngineBuilder.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.timemates.android.grpc
-
-import android.content.Context
-import io.grpc.ManagedChannel
-import io.grpc.android.AndroidChannelBuilder
-import io.timemates.api.grpc.factory.GrpcEngineBuilder
-
-class AndroidGrpcEngineBuilder(private val context: Context) : GrpcEngineBuilder {
- override fun createGrpcEngine(endpoint: String): ManagedChannel {
- return AndroidChannelBuilder.forTarget(endpoint)
- .useTransportSecurity()
- .context(context)
- .build()
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/build.gradle.kts b/grpc-engine/build.gradle.kts
deleted file mode 100644
index cae6d30..0000000
--- a/grpc-engine/build.gradle.kts
+++ /dev/null
@@ -1,72 +0,0 @@
-import org.gradle.kotlin.dsl.dependencies
-import org.gradle.kotlin.dsl.implementation
-import org.gradle.kotlin.dsl.projects
-import com.google.protobuf.gradle.id
-
-plugins {
- alias(libs.plugins.kotlin.jvm)
- alias(libs.plugins.google.protobuf)
- alias(libs.plugins.library.publish)
-}
-
-dependencies {
- implementation(libs.kotlinx.coroutines)
- implementation(libs.grpc.kotlin.stub)
- implementation(libs.grpc.protobuf)
- implementation(libs.grpc.netty)
- implementation(libs.protobuf.kotlin)
- implementation(libs.protobuf.java)
-
- implementation(libs.kotlinx.datetime)
- implementation(projects.sdk)
-}
-
-kotlin {
- explicitApi()
- jvmToolchain(17)
-}
-
-protobuf {
- protoc {
- artifact = "com.google.protobuf:protoc:3.22.2"
- }
- plugins {
- id("grpc") {
- artifact = "io.grpc:protoc-gen-grpc-java:1.54.0"
- }
- id("grpckt") {
- artifact = "io.grpc:protoc-gen-grpc-kotlin:1.3.0:jdk8@jar"
- }
- }
- generateProtoTasks {
- all().forEach {
- it.plugins {
- id("grpc")
- id("grpckt")
- }
- it.builtins {
- id("kotlin")
- }
- }
- }
-}
-
-group = "io.timemates"
-
-deployLibrary {
- ssh(tag = "maven.timemates.io") {
- host = System.getenv("TIMEMATES_SSH_HOST")
- user = System.getenv("TIMEMATES_SSH_USER")
- password = System.getenv("TIMEMATES_SSH_PASSWORD")
- deployPath = System.getenv("TIMEMATES_SSH_DEPLOY_PATH")
-
- group = "io.timemates"
- componentName = "kotlin"
- artifactId = "grpc-engine"
- name = "grpc-engine"
-
- description = "TimeMates grpc adapter for SDK"
-
- version = System.getenv("TIMEMATES_SDK_VERSION")
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/GrpcTimeMatesRequestsEngine.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/GrpcTimeMatesRequestsEngine.kt
deleted file mode 100644
index ef9f211..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/GrpcTimeMatesRequestsEngine.kt
+++ /dev/null
@@ -1,429 +0,0 @@
-@file:Suppress("UNCHECKED_CAST")
-
-package io.timemates.api.grpc
-
-import com.google.protobuf.Empty
-import com.google.protobuf.kotlin.toByteString
-import io.grpc.Metadata
-import io.grpc.Status
-import io.grpc.StatusException
-import io.timemates.api.authorizations.AuthorizationServiceGrpcKt
-import io.timemates.api.files.FilesServiceGrpcKt
-import io.timemates.api.files.requests.UploadFileRequestKt.fileMetadata
-import io.timemates.api.grpc.factory.GrpcEngineBuilder
-import io.timemates.api.grpc.internal.mapException
-import io.timemates.api.grpc.mappers.AuthorizationsMapper
-import io.timemates.api.grpc.mappers.FilesMapper
-import io.timemates.api.grpc.mappers.TimersMapper
-import io.timemates.api.grpc.mappers.UsersMapper
-import io.timemates.api.timers.TimerSessionsServiceGrpcKt
-import io.timemates.api.timers.TimersServiceGrpcKt
-import io.timemates.api.timers.sessions.requests.getTimerStateRequest
-import io.timemates.api.users.UsersServiceGrpcKt
-import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest
-import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest
-import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest
-import io.timemates.sdk.authorization.email.types.value.VerificationHash
-import io.timemates.sdk.authorization.sessions.requests.GetAuthorizationSessionsRequest
-import io.timemates.sdk.authorization.sessions.requests.TerminateCurrentAuthorizationSessionRequest
-import io.timemates.sdk.authorization.types.value.AccessHash
-import io.timemates.sdk.common.constructor.createOrThrow
-import io.timemates.sdk.common.engine.TimeMatesRequestsEngine
-import io.timemates.sdk.common.exceptions.AlreadyExistsException
-import io.timemates.sdk.common.exceptions.InternalServerError
-import io.timemates.sdk.common.exceptions.InvalidArgumentException
-import io.timemates.sdk.common.exceptions.NotFoundException
-import io.timemates.sdk.common.exceptions.PermissionDeniedException
-import io.timemates.sdk.common.exceptions.TooManyRequestsException
-import io.timemates.sdk.common.exceptions.UnauthorizedException
-import io.timemates.sdk.common.exceptions.UnavailableException
-import io.timemates.sdk.common.exceptions.UnsupportedException
-import io.timemates.sdk.common.pagination.Page
-import io.timemates.sdk.common.pagination.PageToken
-import io.timemates.sdk.common.types.TimeMatesEntity
-import io.timemates.sdk.common.types.TimeMatesRequest
-import io.timemates.sdk.common.types.value.Count
-import io.timemates.sdk.files.requests.GetFileBytesRequest
-import io.timemates.sdk.files.requests.UploadFileRequest
-import io.timemates.sdk.files.types.value.FileId
-import io.timemates.sdk.timers.members.invites.requests.CreateInviteRequest
-import io.timemates.sdk.timers.members.invites.requests.GetInvitesRequest
-import io.timemates.sdk.timers.members.invites.requests.RemoveInviteRequest
-import io.timemates.sdk.timers.members.invites.types.value.InviteCode
-import io.timemates.sdk.timers.members.requests.GetMembersRequest
-import io.timemates.sdk.timers.members.requests.KickMemberRequest
-import io.timemates.sdk.timers.requests.*
-import io.timemates.sdk.timers.sessions.requests.ConfirmTimerRoundRequest
-import io.timemates.sdk.timers.sessions.requests.GetTimerStateRequest
-import io.timemates.sdk.timers.sessions.requests.GetUserCurrentSessionRequest
-import io.timemates.sdk.timers.sessions.requests.JoinTimerSessionRequest
-import io.timemates.sdk.timers.sessions.requests.LeaveTimerSessionRequest
-import io.timemates.sdk.timers.sessions.requests.PingSessionRequest
-import io.timemates.sdk.timers.sessions.requests.StartTimerRequest
-import io.timemates.sdk.timers.sessions.requests.StopTimerRequest
-import io.timemates.sdk.timers.types.value.TimerId
-import io.timemates.sdk.users.profile.requests.EditProfileRequest
-import io.timemates.sdk.users.profile.requests.GetUsersRequest
-import io.timemates.sdk.users.profile.types.Avatar
-import io.timemates.sdk.users.settings.requests.EditEmailRequest
-import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.map
-import kotlinx.datetime.Instant
-import kotlin.reflect.KClass
-import io.timemates.api.authorizations.requests.ConfirmAuthorizationRequestOuterClass.ConfirmAuthorizationRequest as GrpcConfirmAuthorizationRequest
-import io.timemates.api.authorizations.requests.GetAuthorizationsRequestOuterClass.GetAuthorizationsRequest as GrpcGetAuthorizationsRequest
-import io.timemates.api.authorizations.requests.StartAuthorizationRequestOuterClass.StartAuthorizationRequest as GrpcStartAuthorizationRequest
-import io.timemates.api.files.requests.GetFileBytesRequestOuterClass.GetFileBytesRequest as GrpcGetFileBytesRequest
-import io.timemates.api.files.requests.uploadFileRequest as buildUploadFileGrpcRequest
-import io.timemates.api.timers.members.invites.requests.getInvitesRequest as buildGetInvitesGrpcRequest
-import io.timemates.api.timers.members.invites.requests.inviteMemberRequest as buildCreateInviteGrpcRequest
-import io.timemates.api.timers.members.invites.requests.removeInviteRequest as buildRemoveInviteGrpcRequest
-import io.timemates.api.timers.members.requests.getMembersRequest as buildGetMembersGrpcRequest
-import io.timemates.api.timers.members.requests.kickMemberRequest as buildKickMemberGrpcRequest
-import io.timemates.api.timers.requests.CreateTimerRequestOuterClass.CreateTimerRequest as GrpcCreateTimerRequest
-import io.timemates.api.timers.requests.EditTimerInfoRequest.EditTimerRequest as GrpcEditTimerRequest
-import io.timemates.api.timers.requests.getTimerRequest as buildGetTimerGrpcRequest
-import io.timemates.api.timers.requests.getTimersRequest as buildGetTimersGrpcRequest
-import io.timemates.api.timers.requests.removeTimerRequest as buildRemoveTimerGrpcRequest
-import io.timemates.api.timers.sessions.requests.joinTimerSessionRequest as buildJoinTimerSessionGrpcRequest
-import io.timemates.api.timers.sessions.requests.startTimerRequest as buildStartTimerGrpcRequest
-import io.timemates.api.timers.sessions.requests.stopTimerRequest as buildStopTimerGrpcRequest
-import io.timemates.api.users.requests.CreateProfileRequestOuterClass.CreateProfileRequest as GrpcCreateProfileRequest
-import io.timemates.api.users.requests.EditUserRequestOuterClass.EditUserRequest as GrpcEditUserRequest
-import io.timemates.api.users.requests.GetUsersRequestOuterClass.GetUsersRequest as GrpcGetUsersRequest
-import io.timemates.sdk.common.types.Empty as SdkEmpty
-
-/**
- * gRPC-based implementation of the TimeMatesRequestsEngine interface.
- *
- * @param endpoint The endpoint URL for the gRPC API. Default value is "https://api.timemates.io".
- */
-public class GrpcTimeMatesRequestsEngine(
- endpoint: String = "api.timemates.io",
- grpcEngineBuilder: GrpcEngineBuilder,
-) : TimeMatesRequestsEngine {
- private companion object {
- val ACCESS_TOKEN: Metadata.Key = Metadata.Key.of("access-token", Metadata.ASCII_STRING_MARSHALLER)
- }
-
- private val channel = grpcEngineBuilder.createGrpcEngine(endpoint)
-
- private val authorizationService = AuthorizationServiceGrpcKt.AuthorizationServiceCoroutineStub(channel)
- private val authMapper = AuthorizationsMapper()
-
- private val filesService = FilesServiceGrpcKt.FilesServiceCoroutineStub(channel)
- private val filesMapper = FilesMapper()
-
- private val usersService = UsersServiceGrpcKt.UsersServiceCoroutineStub(channel)
- private val usersMapper = UsersMapper()
-
- private val timersService = TimersServiceGrpcKt.TimersServiceCoroutineStub(channel)
- private val timerSessionsService = TimerSessionsServiceGrpcKt.TimerSessionsServiceCoroutineStub(channel)
- private val timersMapper = TimersMapper()
-
- override suspend fun execute(request: TimeMatesRequest): Result = runCatching {
- when (request) {
- is StartAuthorizationRequest -> authorizationService.startAuthorization(
- GrpcStartAuthorizationRequest
- .newBuilder()
- .setEmailAddress(request.emailAddress.string)
- .build()
- ).let {
- StartAuthorizationRequest.Result(
- verificationHash = VerificationHash.createOrThrow(it.verificationHash),
- attempts = Count.createOrThrow(it.attempts),
- expiresAt = Instant.fromEpochMilliseconds(it.expiresAt),
- )
- }
-
- is ConfirmAuthorizationRequest -> authorizationService.confirmAuthorization(
- GrpcConfirmAuthorizationRequest
- .newBuilder()
- .setConfirmationCode(request.confirmationCode.string)
- .setVerificationHash(request.verificationHash.string)
- .build()
- ).let { response ->
- ConfirmAuthorizationRequest.Response(
- isNewAccount = response.isNewAccount,
- authorization = response.authorization.takeIf { !response.isNewAccount }
- ?.let(authMapper::grpcAuthorizationToSdkAuthorization),
- )
- }
-
- is ConfigureNewAccountRequest -> authorizationService.createProfile(
- GrpcCreateProfileRequest.newBuilder()
- .setName(request.name.string)
- .setDescription(request.description.string)
- .setVerificationHash(request.verificationHash.string)
- .build()
- ).let {
- ConfigureNewAccountRequest.Result(
- authMapper.grpcAuthorizationToSdkAuthorization(it.authorization)
- )
- }
-
- is GetAuthorizationSessionsRequest -> authorizationService.getAuthorizations(
- GrpcGetAuthorizationsRequest.newBuilder()
- .setPageToken(request.nextPageToken?.string)
- .build(),
- headers = authorizedMetadata(request.accessHash),
- ).let { response ->
- Page(
- response.authorizationsList.map(authMapper::grpcAuthorizationToSdkAuthorization),
- nextPageToken = response.nextPageToken.takeIf { it.isNotEmpty() }
- ?.let(PageToken::createOrThrow),
- )
- }
-
- is TerminateCurrentAuthorizationSessionRequest ->
- authorizationService.terminateAuthorization(Empty.getDefaultInstance())
- .let { SdkEmpty }
-
- is GetFileBytesRequest ->
- filesService.getFileBytes(
- GrpcGetFileBytesRequest
- .newBuilder()
- .setFileId(request.fileId.string)
- .build(),
- ).map { it.chunk.toByteArray() }.let { GetFileBytesRequest.Result(it) }
-
- is UploadFileRequest -> filesService.uploadFile(
- requests = flow {
- emit(buildUploadFileGrpcRequest {
- metadata = fileMetadata {
- fileName = request.fileName.string
- fileType = filesMapper.sdkFileTypeToGrpcFileType(request.fileType)
- }
- })
-
- request.bytes.collect {
- emit(buildUploadFileGrpcRequest {
- chunk = it.toByteString()
- })
- }
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { UploadFileRequest.Result(FileId.createOrThrow(it.fileId)) }
-
- is EditProfileRequest -> usersService.setUser(
- GrpcEditUserRequest.newBuilder()
- .apply {
- request.name?.let { name = it.string }
- request.description?.let { description = it.string }
- request.avatar?.let {
- avatarId = (it as? Avatar.FileId)?.string
- gravatarId = (it as? Avatar.GravatarId)?.string
- }
- }.build(),
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is GetUsersRequest -> usersService.getUsers(
- GrpcGetUsersRequest.newBuilder()
- .addAllUserId(request.users.map { it.long })
- .build(),
- ).let { GetUsersRequest.Result(it.usersList.map { usersMapper.grpcUserToSdkUser(it) }) }
-
- is EditEmailRequest -> unsupported()
-
- is CreateTimerRequest -> timersService.createTimer(
- GrpcCreateTimerRequest.newBuilder()
- .setName(request.name.string)
- .setDescription(request.description.string)
- .setSettings(timersMapper.sdkSettingsToGrpcSettings(request.settings))
- .build(),
- headers = authorizedMetadata(request.accessHash)
- ).let { CreateTimerRequest.Result(TimerId.createOrThrow(it.timerId)) }
-
- is EditTimerRequest -> timersService.editTimer(
- GrpcEditTimerRequest.newBuilder()
- .setTimerId(request.timerId.long)
- .apply {
- request.name?.let { name = it.string }
- request.description?.let { description = it.string }
- request.settings?.let {
- settings = timersMapper.sdkSettingsPatchToGrpcSettingsPatch(it)
- }
- }.build(),
- headers = authorizedMetadata(request.accessHash)
- ).let { SdkEmpty }
-
- is GetTimerRequest -> timersService.getTimer(
- buildGetTimerGrpcRequest {
- timerId = request.timerId.long
- },
- headers = authorizedMetadata(request.accessHash)
- ).let { timersMapper.grpcTimerToSdkTimer(it) }
-
- is GetUserTimersRequest -> timersService.getTimers(
- buildGetTimersGrpcRequest {
- request.pageToken?.let { nextPageToken = it.string }
- },
- headers = authorizedMetadata(request.accessHash)
- ).let { response ->
- Page(
- response.timersList.map { timersMapper.grpcTimerToSdkTimer(it) },
- nextPageToken = response.nextPageToken.takeIf {
- response.hasNextPageToken()
- }?.let {
- PageToken.createOrThrow(it)
- },
- )
- }
-
- is RemoveTimerRequest -> timersService.removeTimer(
- buildRemoveTimerGrpcRequest {
- timerId = request.timerId.long
- },
- headers = authorizedMetadata(request.accessHash)
- ).let { SdkEmpty }
-
- is GetMembersRequest -> timersService.getMembers(
- buildGetMembersGrpcRequest {
- timerId = request.timerId.long
- request.pageToken?.let { nextPageToken = it.string }
- },
- headers = authorizedMetadata(request.accessHash)
- ).let { response ->
- Page(
- response.usersList.map { usersMapper.grpcUserToSdkUser(it) },
- nextPageToken = response.nextPageToken?.takeIf { it.isNotEmpty() }
- ?.let { PageToken.createOrThrow(it) }
- )
- }
-
- is KickMemberRequest -> timersService.kickMember(
- buildKickMemberGrpcRequest {
- timerId = request.timerId.long
- userId = request.userId.long
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is CreateInviteRequest -> timersService.createInvite(
- buildCreateInviteGrpcRequest {
- timerId = request.timerId.long
- maxJoiners = request.maxJoinersCount.int
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { CreateInviteRequest.Result(InviteCode.createOrThrow(it.inviteCode)) }
-
- is GetInvitesRequest -> timersService.getInvites(
- buildGetInvitesGrpcRequest {
- timerId = request.timerId.long
- request.pageToken?.let { nextPageToken = it.string }
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { response ->
- Page(
- results = response.invitesList.map { timersMapper.grpcInviteToSdkInvite(it) },
- nextPageToken = response.nextPageToken.takeIf { it.isNotEmpty() }
- ?.let { PageToken.createOrThrow(it) }
- )
- }
-
- is RemoveInviteRequest -> timersService.removeInvite(
- buildRemoveInviteGrpcRequest {
- timerId = request.timerId.long
- inviteCode = request.inviteCode.string
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is StartTimerRequest -> timerSessionsService.startTimer(
- buildStartTimerGrpcRequest {
- timerId = request.timerId.long
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is StopTimerRequest -> timerSessionsService.stopTimer(
- buildStopTimerGrpcRequest {
- timerId = request.timerId.long
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is JoinTimerSessionRequest -> timerSessionsService.joinSession(
- buildJoinTimerSessionGrpcRequest {
- timerId = request.timerId.long
- },
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is LeaveTimerSessionRequest -> timerSessionsService.leaveSession(
- Empty.getDefaultInstance(),
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is ConfirmTimerRoundRequest -> timerSessionsService.pingSession(
- Empty.getDefaultInstance(),
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is PingSessionRequest -> timerSessionsService.pingSession(
- Empty.getDefaultInstance(),
- headers = authorizedMetadata(request.accessHash),
- ).let { SdkEmpty }
-
- is GetUserCurrentSessionRequest -> timerSessionsService.getUserCurrentSession(
- request = Empty.getDefaultInstance(),
- headers = authorizedMetadata(request.accessHash),
- ).let { timersMapper.grpcTimerToSdkTimer(it) }
-
- is GetTimerStateRequest -> timerSessionsService.getState(
- request = getTimerStateRequest {
-
- },
- headers = authorizedMetadata(request.accessHash)
- ).let { states ->
- GetTimerStateRequest.Result(
- states.map { state -> timersMapper.grpcStateToSdkState(state) }
- )
- }
-
- else -> unsupported(request::class)
- } as T
- }.mapException {
- val exception = (it as? StatusException) ?: return@mapException it
- val status = exception.status
-
- val message = exception.message ?: NO_MESSAGE
-
- when (status) {
- Status.RESOURCE_EXHAUSTED ->
- TooManyRequestsException("Too many requests.", exception)
-
- Status.INVALID_ARGUMENT, Status.FAILED_PRECONDITION ->
- InvalidArgumentException(message, exception)
-
- Status.UNAUTHENTICATED ->
- UnauthorizedException(message, exception)
-
- Status.INTERNAL ->
- InternalServerError(message, exception)
-
- Status.NOT_FOUND ->
- NotFoundException(message, exception)
-
- Status.ALREADY_EXISTS ->
- AlreadyExistsException(message, exception)
-
- Status.PERMISSION_DENIED -> PermissionDeniedException(message, exception)
- Status.UNAVAILABLE -> UnavailableException(message, exception)
-
- else -> InternalServerError(message, exception)
- }
- }
-
- private fun authorizedMetadata(accessHash: AccessHash) = Metadata().apply {
- put(ACCESS_TOKEN, accessHash.string)
- }
-
- private fun unsupported(kClass: KClass<*>): Nothing =
- throw UnsupportedException("Request of type ${kClass.simpleName} is not supported")
-
- private inline fun unsupported(): Nothing = unsupported(T::class)
-}
-
-private const val NO_MESSAGE = "No message is provided."
\ No newline at end of file
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/DefaultGrpcEngineBuilder.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/DefaultGrpcEngineBuilder.kt
deleted file mode 100644
index 5137877..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/DefaultGrpcEngineBuilder.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.timemates.api.grpc.factory
-
-import io.grpc.ManagedChannel
-import io.grpc.ManagedChannelBuilder
-
-public class DefaultGrpcEngineBuilder : GrpcEngineBuilder {
- override fun createGrpcEngine(endpoint: String): ManagedChannel {
- return ManagedChannelBuilder.forTarget(endpoint)
- .useTransportSecurity()
- .build()
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/GrpcEngineBuilder.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/GrpcEngineBuilder.kt
deleted file mode 100644
index c9318f8..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/factory/GrpcEngineBuilder.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package io.timemates.api.grpc.factory
-
-import io.grpc.ManagedChannel
-
-public interface GrpcEngineBuilder {
- public fun createGrpcEngine(endpoint: String): ManagedChannel
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/internal/ResultExt.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/internal/ResultExt.kt
deleted file mode 100644
index 4564846..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/internal/ResultExt.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.timemates.api.grpc.internal
-
-/**
- * Applies the given transformation function to the exception contained in the `Result` and returns a new `Result`
- * with the transformed exception. If the `Result` does not contain an exception,
- * it returns the original `Result` unchanged.
- *
- * @param transform The transformation function to apply to the exception.
- * @return A new `Result` with the transformed exception, or the original `Result` if no exception is present.
- */
-@JvmSynthetic
-internal inline fun Result.mapException(transform: (Throwable) -> Throwable): Result {
- val exception = exceptionOrNull() ?: return this
-
- return Result.failure(transform(exception))
-}
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/AuthorizationsMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/AuthorizationsMapper.kt
deleted file mode 100644
index 15fc28c..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/AuthorizationsMapper.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package io.timemates.api.grpc.mappers
-
-import io.timemates.api.authorizations.types.AuthorizationOuterClass.Authorization
-import io.timemates.sdk.authorization.sessions.types.value.ClientIpAddress
-import io.timemates.sdk.authorization.sessions.types.value.ClientName
-import io.timemates.sdk.authorization.sessions.types.value.ClientVersion
-import io.timemates.sdk.authorization.types.value.HashValue
-import io.timemates.sdk.common.constructor.createOrThrow
-import kotlinx.datetime.Instant
-import io.timemates.sdk.authorization.sessions.types.Authorization as SdkAuthorization
-
-internal class AuthorizationsMapper {
- fun grpcAuthorizationToSdkAuthorization(
- authorization: Authorization
- ): SdkAuthorization = with(authorization) {
- return@with SdkAuthorization(
- accessHash = SdkAuthorization.Hash(
- value = HashValue.createOrThrow(accessHash.value),
- expiresAt = Instant.fromEpochMilliseconds(accessHash.expiresAt),
- ),
- refreshHash = SdkAuthorization.Hash(
- value = HashValue.createOrThrow(refreshHash.value),
- expiresAt = Instant.fromEpochMilliseconds(refreshHash.expiresAt),
- ),
- generationTime = Instant.fromEpochMilliseconds(generationTime),
- metadata = grpcMetadataToSdkMetadata(metadata),
- )
- }
-
- private fun grpcMetadataToSdkMetadata(
- metadata: Authorization.Metadata,
- ): SdkAuthorization.Metadata = with(metadata) {
- return@with SdkAuthorization.Metadata(
- clientName = ClientName.createOrThrow(clientName),
- clientVersion = ClientVersion.createOrThrow(clientVersion),
- clientIpAddress = ClientIpAddress.createOrThrow(clientIpAddress),
- )
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/FilesMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/FilesMapper.kt
deleted file mode 100644
index e10877a..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/FilesMapper.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.timemates.api.grpc.mappers
-
-import io.timemates.api.files.requests.UploadFileRequestOuterClass
-import io.timemates.sdk.files.types.FileType
-import io.timemates.api.files.requests.UploadFileRequestOuterClass.UploadFileRequest.FileMetadata.FileType as GrpcFileType
-
-internal class FilesMapper {
- fun sdkFileTypeToGrpcFileType(fileType: FileType): GrpcFileType {
- return when (fileType) {
- FileType.IMAGE -> GrpcFileType.IMAGE
- }
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/TimersMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/TimersMapper.kt
deleted file mode 100644
index 37b5659..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/TimersMapper.kt
+++ /dev/null
@@ -1,116 +0,0 @@
-package io.timemates.api.grpc.mappers
-
-import io.timemates.api.timers.members.invites.types.InviteOuterClass.Invite
-import io.timemates.api.timers.sessions.types.TimerStateOuterClass.TimerState
-import io.timemates.api.timers.types.TimerKt
-import io.timemates.api.timers.types.TimerOuterClass.Timer
-import io.timemates.sdk.common.constructor.createOrThrow
-import io.timemates.sdk.common.exceptions.UnsupportedException
-import io.timemates.sdk.common.types.value.Count
-import io.timemates.sdk.timers.members.invites.types.value.InviteCode
-import io.timemates.sdk.timers.types.value.TimerDescription
-import io.timemates.sdk.timers.types.value.TimerId
-import io.timemates.sdk.timers.types.value.TimerName
-import io.timemates.sdk.users.profile.types.value.UserId
-import kotlinx.datetime.Instant
-import kotlin.time.Duration.Companion.seconds
-import kotlin.time.DurationUnit
-import io.timemates.sdk.timers.members.invites.types.Invite as SdkInvite
-import io.timemates.sdk.timers.types.Timer as SdkTimer
-import io.timemates.sdk.timers.types.TimerSettings as SdkTimerSettings
-
-internal class TimersMapper {
- fun grpcTimerToSdkTimer(timer: Timer): SdkTimer = with(timer) {
- return SdkTimer(
- timerId = TimerId.createOrThrow(id),
- name = TimerName.createOrThrow(name),
- description = TimerDescription.createOrThrow(description),
- ownerId = UserId.createOrThrow(ownerId),
- membersCount = Count.createOrThrow(membersCount),
- state = grpcStateToSdkState(currentState),
- settings = grpcSettingsToSdkSettings(settings),
- )
- }
-
- fun grpcStateToSdkState(timerState: TimerState): SdkTimer.State = with(timerState) {
- val publishTime = Instant.fromEpochMilliseconds(publishTime)
-
- return when {
- hasPaused() -> SdkTimer.State.Paused(publishTime)
- hasRunning() -> SdkTimer.State.Running(
- publishTime = publishTime,
- endsAt = Instant.fromEpochMilliseconds(running.endsAt),
- )
-
- hasConfirmationWaiting() -> SdkTimer.State.ConfirmationWaiting(
- publishTime = publishTime,
- endsAt = Instant.fromEpochMilliseconds(confirmationWaiting.endsAt),
- )
-
- hasRest() -> SdkTimer.State.Rest(
- publishTime = publishTime,
- endsAt = Instant.fromEpochMilliseconds(rest.endsAt),
- )
-
- hasInactive() -> SdkTimer.State.Inactive(
- publishTime = publishTime,
- )
-
- else -> throw UnsupportedException("Unsupported timer state.")
- }
- }
-
- fun grpcSettingsToSdkSettings(settings: Timer.Settings): SdkTimerSettings = with(settings) {
- return SdkTimerSettings(
- workTime = workTime.seconds,
- restTime = restTime.seconds,
- bigRestTime = bigRestTime.seconds,
- bigRestEnabled = bigRestEnabled,
- bigRestPer = Count.createOrThrow(bigRestPer),
- isEveryoneCanPause = isEveryoneCanPause,
- isConfirmationRequired = isConfirmationRequired,
- )
- }
- fun sdkTimerToGrpcTimer(sdkTimer: SdkTimer): Timer = with(sdkTimer) {
- return Timer.newBuilder()
- .setId(timerId.long)
- .setName(name.string)
- .setDescription(description.string)
- .setOwnerId(ownerId.long)
- .setMembersCount(membersCount.int)
- .setSettings(sdkSettingsToGrpcSettings(settings))
- .build()
- }
-
- fun sdkSettingsToGrpcSettings(sdkSettings: SdkTimerSettings): Timer.Settings = with(sdkSettings) {
- return Timer.Settings.newBuilder()
- .setWorkTime(workTime.toInt(DurationUnit.MINUTES))
- .setRestTime(restTime.toInt(DurationUnit.MINUTES))
- .setBigRestTime(bigRestTime.toInt(DurationUnit.MINUTES))
- .setBigRestEnabled(bigRestEnabled)
- .setBigRestPer(bigRestPer.int)
- .setIsEveryoneCanPause(isEveryoneCanPause)
- .setIsConfirmationRequired(isConfirmationRequired)
- .build()
- }
-
- fun sdkSettingsPatchToGrpcSettingsPatch(
- sdkSettings: SdkTimerSettings.Patch
- ): Timer.Settings.Patch = TimerKt.SettingsKt.patch {
- sdkSettings.workTime?.let { workTime = it.toInt(DurationUnit.MINUTES) }
- sdkSettings.restTime?.let { restTime = it.toInt(DurationUnit.MINUTES) }
- sdkSettings.bigRestTime?.let { bigRestTime = it.toInt(DurationUnit.MINUTES) }
- sdkSettings.bigRestPer?.let { bigRestPer = it.int }
- sdkSettings.bigRestEnabled?.let { bigRestEnabled = it }
- sdkSettings.isConfirmationRequired?.let { isConfirmationRequired = it }
- sdkSettings.isEveryoneCanPause?.let { isEveryoneCanPause = it }
- }
-
- fun grpcInviteToSdkInvite(invite: Invite): SdkInvite {
- return SdkInvite(
- inviteCode = InviteCode.createOrThrow(invite.code),
- creationTime = Instant.fromEpochMilliseconds(invite.creationTime),
- limit = Count.createOrThrow(invite.limit),
- )
- }
-}
diff --git a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/UsersMapper.kt b/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/UsersMapper.kt
deleted file mode 100644
index 4fc1a08..0000000
--- a/grpc-engine/src/main/kotlin/io/timemates/api/grpc/mappers/UsersMapper.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package io.timemates.api.grpc.mappers
-
-import io.timemates.api.users.types.UserOuterClass
-import io.timemates.sdk.common.constructor.createOrThrow
-import io.timemates.sdk.users.profile.types.Avatar
-import io.timemates.sdk.users.profile.types.value.EmailAddress
-import io.timemates.sdk.users.profile.types.value.UserDescription
-import io.timemates.sdk.users.profile.types.value.UserId
-import io.timemates.sdk.users.profile.types.value.UserName
-import io.timemates.sdk.users.profile.types.User as SdkUser
-
-internal class UsersMapper {
- fun grpcUserToSdkUser(user: UserOuterClass.User): SdkUser = with(user) {
- return SdkUser(
- id = UserId.createOrThrow(id),
- name = UserName.createOrThrow(name),
- description = UserDescription.createOrThrow(description),
- emailAddress = email?.takeIf { it.isNotEmpty() }?.let { EmailAddress.createOrThrow(it) },
- avatar = gravatarId?.let { Avatar.GravatarId.createOrThrow(it) } ?:
- avatarId?.let { Avatar.FileId.createOrThrow(it) }
- )
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/files/FilesService.proto b/grpc-engine/src/main/proto/io/timemates/api/files/FilesService.proto
deleted file mode 100644
index 00f5cad..0000000
--- a/grpc-engine/src/main/proto/io/timemates/api/files/FilesService.proto
+++ /dev/null
@@ -1,23 +0,0 @@
-syntax = "proto3";
-
-import "io/timemates/api/files/requests/GetFileBytesRequest.proto";
-import "io/timemates/api/files/requests/UploadFileRequest.proto";
-import "io/timemates/api/authorizations/options/OmitAuthorizationOption.proto";
-import "google/protobuf/empty.proto";
-
-option java_package = "io.timemates.api.files";
-
-service FilesService {
- /**
- * Returns a sequence of bytes of the file's content.
- */
- rpc getFileBytes(GetFileBytesRequest) returns (stream GetFileBytesRequest.Response) {
- option (omit_authorization) = true;
- }
-
- /*
- * Uploads file to server.
- * Returns status after upload file stream ends.
- */
- rpc uploadFile(stream UploadFileRequest) returns (UploadFileRequest.Response);
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/files/requests/GetFileBytesRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/files/requests/GetFileBytesRequest.proto
deleted file mode 100644
index 625ea0d..0000000
--- a/grpc-engine/src/main/proto/io/timemates/api/files/requests/GetFileBytesRequest.proto
+++ /dev/null
@@ -1,14 +0,0 @@
-syntax = "proto3";
-
-option java_package = "io.timemates.api.files.requests";
-
-message GetFileBytesRequest {
- string fileId = 1;
-
- message Response {
- /**
- * Chunked file content bytes.
- */
- bytes chunk = 1;
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/files/requests/UploadFileRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/files/requests/UploadFileRequest.proto
deleted file mode 100644
index f32c786..0000000
--- a/grpc-engine/src/main/proto/io/timemates/api/files/requests/UploadFileRequest.proto
+++ /dev/null
@@ -1,31 +0,0 @@
-syntax = "proto3";
-
-option java_package = "io.timemates.api.files.requests";
-
-message UploadFileRequest {
- oneof request {
- /**
- * Should always be sent as first request.
- * Should not be repeated.
- */
- FileMetadata metadata = 1;
- /**
- * Bytes of file included into given chunk.
- */
- bytes chunk = 2;
- }
-
- message Response {
- string fileId = 1;
- }
-
- message FileMetadata {
- FileType fileType = 1;
- string fileName = 2;
-
- enum FileType {
- BINARY = 0; // unsupported by default
- IMAGE = 1;
- }
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto
deleted file mode 100644
index c73a7eb..0000000
--- a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto
+++ /dev/null
@@ -1,11 +0,0 @@
-syntax = "proto3";
-
-import "io/timemates/api/timers/types/Timer.proto";
-
-option java_package = "io.timemates.api.timers.sessions.requests";
-
-message GetUserCurrentSessionRequest {
- message Response {
- optional Timer timer = 1;
- }
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/UsersService.proto b/grpc-engine/src/main/proto/io/timemates/api/users/UsersService.proto
deleted file mode 100644
index 4f7fc7d..0000000
--- a/grpc-engine/src/main/proto/io/timemates/api/users/UsersService.proto
+++ /dev/null
@@ -1,32 +0,0 @@
-syntax = "proto3";
-
-import "io/timemates/api/users/requests/GetUsersRequest.proto";
-import "io/timemates/api/users/requests/EditUserRequest.proto";
-import "io/timemates/api/users/requests/EditEmailRequest.proto";
-import "io/timemates/api/users/types/User.proto";
-import "google/protobuf/empty.proto";
-
-option java_package = "io.timemates.api.users";
-
-service UsersService {
- /**
- * Gets users by given identifiers.
- *
- * Returns [User] or null
- */
- rpc getUsers(GetUsersRequest) returns (Users);
-
- /**
- * Sets user information (name / description / avatar file id).
- *
- * Returns [Status]
- */
- rpc setUser(EditUserRequest) returns (google.protobuf.Empty);
-
- /**
- * Sets new email for current user.
- *
- * Returns [Status]
- */
- rpc setEmail(EditEmailRequest) returns (google.protobuf.Empty);
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto b/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto
deleted file mode 100644
index aa19215..0000000
--- a/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto
+++ /dev/null
@@ -1,22 +0,0 @@
-syntax = "proto3";
-
-option java_package = "io.timemates.api.users.requests";
-
-message EditUserRequest {
- /**
- * User's avatar id
- */
- oneof avatar {
- string avatarId = 1;
- string gravatarId = 2;
- }
- /**
- * User's name
- */
- optional string name = 3;
-
- /**
- * User's description.
- */
- optional string description = 4;
-}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/types/User.proto b/grpc-engine/src/main/proto/io/timemates/api/users/types/User.proto
deleted file mode 100644
index b5b69c0..0000000
--- a/grpc-engine/src/main/proto/io/timemates/api/users/types/User.proto
+++ /dev/null
@@ -1,39 +0,0 @@
-syntax = "proto3";
-
-option java_package = "io.timemates.api.users.types";
-
-message User {
- /**
- * User's identifier
- */
- int64 id = 1;
-
- /**
- * String identifier of 128 length. Can be null
- * if there is no avatar.
- */
- oneof avatar {
- string avatarId = 2;
- string gravatarId = 3;
- }
-
- /**
- * User's name
- */
- string name = 4;
-
- /**
- * User's description.
- */
- string description = 5;
-
- /**
- * User's email up to 200 symbols.
- * Can be null if there is no access.
- */
- optional string email = 6;
-}
-
-message Users {
- repeated User users = 1;
-}
\ No newline at end of file
diff --git a/rsocket-engine/build.gradle.kts b/rsocket-engine/build.gradle.kts
new file mode 100644
index 0000000..08c2ada
--- /dev/null
+++ b/rsocket-engine/build.gradle.kts
@@ -0,0 +1,60 @@
+plugins {
+ alias(libs.plugins.kotlin.multiplatform)
+ alias(libs.plugins.kotlinx.serialization)
+ alias(libs.plugins.library.publish)
+ alias(libs.plugins.timemates.rsproto)
+}
+
+kotlin {
+ jvm()
+ jvmToolchain(17)
+
+ sourceSets {
+ val commonMain by getting {
+ kotlin.srcDirs("src/main/kotlin", "build/generated/rsproto/kotlin")
+ }
+ }
+
+ explicitApi()
+}
+
+dependencies {
+ commonMainImplementation(projects.sdk)
+
+ commonMainImplementation(libs.timemates.rsproto.common)
+ commonMainImplementation(libs.timemates.rsproto.client)
+
+ commonMainImplementation(libs.kotlinx.serialization)
+ commonMainImplementation(libs.kotlinx.datetime)
+ commonMainImplementation(libs.rsocket.client)
+}
+
+deployLibrary {
+ ssh(tag = "rsocket-engine to maven.timemates.io") {
+ host = System.getenv("TIMEMATES_SSH_HOST")
+ user = System.getenv("TIMEMATES_SSH_USER")
+ password = System.getenv("TIMEMATES_SSH_PASSWORD")
+ deployPath = System.getenv("TIMEMATES_SSH_DEPLOY_PATH")
+
+ group = "io.timemates"
+ componentName = "kotlin"
+ artifactId = "rsocket-engine"
+ name = "rsocket-engine"
+
+ description = "TimeMates rsocket adapter for SDK"
+
+ version = System.getenv("TIMEMATES_SDK_VERSION")
+ }
+}
+
+rsproto {
+ protoSourcePath = "src/main/proto/"
+ generationOutputPath = "generated/rsproto/kotlin"
+
+ clientGeneration = true
+ serverGeneration = false
+}
+
+tasks.withType {
+ useJUnitPlatform()
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/ApiContainer.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/ApiContainer.kt
new file mode 100644
index 0000000..9dc9a29
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/ApiContainer.kt
@@ -0,0 +1,13 @@
+package io.timemates.api.rsocket
+
+import io.timemates.api.authorizations.AuthorizationServiceApi
+import io.timemates.api.timers.TimerSessionsServiceApi
+import io.timemates.api.timers.TimersServiceApi
+import io.timemates.api.users.UsersServiceApi
+
+internal class ApiContainer (
+ val auth: AuthorizationServiceApi,
+ val users: UsersServiceApi,
+ val timers: TimersServiceApi,
+ val timerSessions: TimerSessionsServiceApi,
+)
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/CommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/CommandsRegistry.kt
new file mode 100644
index 0000000..8f30c77
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/CommandsRegistry.kt
@@ -0,0 +1,18 @@
+package io.timemates.api.rsocket
+
+import io.timemates.api.rsocket.authorizations.commands.authorizations
+import io.timemates.api.rsocket.common.commands.rSocketCommands
+import io.timemates.api.rsocket.timers.commands.timers
+import io.timemates.api.rsocket.users.commands.users
+
+/**
+ * Registry for RSocket commands used in the TimeMates application.
+ *
+ * The [rSocketCommandsRegistry] is responsible for initializing and registering RSocket commands
+ * for specific TimeMates features or functionalities.
+ */
+internal val rSocketCommandsRegistry = rSocketCommands {
+ authorizations()
+ users()
+ timers()
+}
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/RSocketTimeMatesRequestsEngine.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/RSocketTimeMatesRequestsEngine.kt
new file mode 100644
index 0000000..42c577b
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/RSocketTimeMatesRequestsEngine.kt
@@ -0,0 +1,113 @@
+package io.timemates.api.rsocket
+
+import io.ktor.client.HttpClient
+import io.ktor.client.HttpClientConfig
+import io.ktor.client.plugins.websocket.WebSockets
+import io.rsocket.kotlin.core.WellKnownMimeType
+import io.rsocket.kotlin.keepalive.KeepAlive
+import io.rsocket.kotlin.ktor.client.RSocketSupport
+import io.rsocket.kotlin.ktor.client.rSocket
+import io.rsocket.kotlin.payload.PayloadMimeType
+import io.timemates.api.authorizations.AuthorizationServiceApi
+import io.timemates.api.timers.TimerSessionsServiceApi
+import io.timemates.api.timers.TimersServiceApi
+import io.timemates.api.users.UsersServiceApi
+import io.timemates.sdk.common.engine.TimeMatesRequestsEngine
+import io.timemates.sdk.common.exceptions.UnsupportedException
+import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.TimeMatesRequest
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.protobuf.ProtoBuf
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.Duration.Companion.seconds
+
+/**
+ * Creates an RSocket-based TimeMates request engine.
+ *
+ * This function configures and creates an RSocket-based TimeMates request engine
+ * that communicates with the TimeMates API over WebSockets. You can customize the
+ * WebSocket endpoint, coroutine scope, and HTTP client configuration using the
+ * provided parameters.
+ *
+ * **Note**: You should implement ktor client engine to use it.
+ *
+ * @param endpoint The WebSocket endpoint URL for the TimeMates API.
+ * @param coroutineScope The coroutine scope used for RSocket lifecycle.
+ * @param config Configuration lambda for customizing the underlying HTTP client.
+ * @return An instance of the RSocketTimeMatesRequestsEngine.
+ */
+public fun RSocketTimeMatesRequestsEngine(
+ endpoint: String = "wss://api.timemates.io/v0/rsocket",
+ coroutineScope: CoroutineScope,
+ config: HttpClientConfig<*>.() -> Unit = {},
+): RSocketTimeMatesRequestsEngine {
+ val client = HttpClient {
+ install(WebSockets)
+ install(RSocketSupport) {
+ connector {
+ maxFragmentSize = 1024
+
+ connectionConfig {
+ keepAlive = KeepAlive(
+ interval = 30.seconds,
+ maxLifetime = 2.minutes
+ )
+
+ payloadMimeType = PayloadMimeType(
+ data = WellKnownMimeType.ApplicationProtoBuf,
+ metadata = WellKnownMimeType.ApplicationProtoBuf,
+ )
+ }
+ }
+ }
+ config()
+ }
+
+ return RSocketTimeMatesRequestsEngine(
+ client, endpoint, coroutineScope,
+ )
+}
+
+/**
+ * Represents an engine for making requests using RSocket.
+ *
+ * @property client An instance of [HttpClient] for making HTTP requests.
+ * @param endpoint The RSocket endpoint URL. Defaults to "wss://api.timemates.io/v0/rsocket".
+ * @param coroutineScope A [CoroutineScope] tied to the RSocket lifecycle.
+ */
+public class RSocketTimeMatesRequestsEngine internal constructor(
+ private val client: HttpClient,
+ endpoint: String = "wss://api.timemates.io/rsocket",
+ coroutineScope: CoroutineScope,
+) : TimeMatesRequestsEngine {
+ public companion object {
+ public const val API_VERSION: Double = 1.0
+ }
+
+ private val rSocket = coroutineScope.async(start = CoroutineStart.LAZY) {
+ client.rSocket(endpoint)
+ }
+
+ @OptIn(ExperimentalSerializationApi::class)
+ private val container = coroutineScope.async(start = CoroutineStart.LAZY) {
+ val rSocket = rSocket.await()
+
+ ApiContainer(
+ auth = AuthorizationServiceApi(rSocket, ProtoBuf),
+ users = UsersServiceApi(rSocket, ProtoBuf),
+ timers = TimersServiceApi(rSocket, ProtoBuf),
+ timerSessions = TimerSessionsServiceApi(rSocket, ProtoBuf)
+ )
+ }
+
+ override suspend fun execute(
+ request: TimeMatesRequest,
+ ): Result = runCatching {
+ return@runCatching rSocketCommandsRegistry.execute(container.await(), request)
+ ?: throw UnsupportedException("This type of request is not supported in RSocket engine.")
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/AuthMappers.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/AuthMappers.kt
new file mode 100644
index 0000000..b6bf406
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/AuthMappers.kt
@@ -0,0 +1,42 @@
+package io.timemates.api.rsocket.authorizations
+
+import io.timemates.api.authorizations.types.Metadata
+import io.timemates.sdk.authorization.sessions.types.value.ApplicationName
+import io.timemates.sdk.authorization.sessions.types.value.ClientIpAddress
+import io.timemates.sdk.authorization.sessions.types.value.ClientVersion
+import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.authorization.types.value.HashValue
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.users.profile.types.value.UserId
+import kotlinx.datetime.Instant
+import io.timemates.api.authorizations.types.Authorization as RSAuthorization
+import io.timemates.sdk.authorization.sessions.types.Authorization as SdkAuth
+
+internal fun Metadata.sdk(): SdkAuth.Metadata {
+ return SdkAuth.Metadata(
+ applicationName = ApplicationName.createOrThrow(clientName),
+ clientVersion = ClientVersion.createOrThrow(clientVersion),
+ clientIpAddress = ClientIpAddress.createOrThrow("UNDEFINED")
+ )
+}
+
+internal fun SdkAuth.Metadata.rs(): Metadata {
+ return Metadata(
+ clientName = applicationName.string,
+ clientVersion = clientVersion.double,
+ )
+}
+
+internal fun RSAuthorization.sdk(): SdkAuth {
+ return SdkAuth(
+ accessHash = accessHash?.let { SdkAuth.Hash(HashValue.createOrThrow(it.value), Instant.fromEpochMilliseconds(it.expiresAt)) },
+ refreshHash = refreshHash?.let { SdkAuth.Hash(HashValue.createOrThrow(it.value), Instant.fromEpochMilliseconds(it.expiresAt)) },
+ generationTime = Instant.fromEpochMilliseconds(generationTime),
+ metadata = metadata?.sdk(),
+ userId = UserId.createOrThrow(userId),
+ )
+}
+
+internal fun AccessHash.toExtra(): Map {
+ return mapOf("access_hash" to string.toByteArray())
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/AuthorizationCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/AuthorizationCommandsRegistry.kt
new file mode 100644
index 0000000..c7820d2
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/AuthorizationCommandsRegistry.kt
@@ -0,0 +1,23 @@
+package io.timemates.api.rsocket.authorizations.commands
+
+import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope
+import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest
+import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest
+import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest
+import io.timemates.sdk.authorization.sessions.requests.GetAuthorizationSessionsRequest
+import io.timemates.sdk.authorization.sessions.requests.RenewAuthorizationRequest
+import io.timemates.sdk.authorization.sessions.requests.TerminateCurrentAuthorizationSessionRequest
+import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi
+
+/**
+ * The commands that is connected to the authorization feature.
+ */
+@OptIn(ExperimentalTimeMatesApi::class)
+internal fun RSocketCommandsBuilderScope.authorizations() {
+ StartAuthorizationCommand associatedWith StartAuthorizationRequest
+ ConfirmAuthorizationCommand associatedWith ConfirmAuthorizationRequest
+ ConfigureNewAccountCommand associatedWith ConfigureNewAccountRequest
+ GetAuthorizationSessionsCommand associatedWith GetAuthorizationSessionsRequest
+ TerminateCurrentAuthorizationCommand associatedWith TerminateCurrentAuthorizationSessionRequest
+ RenewAuthorizationCommand associatedWith RenewAuthorizationRequest
+}
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfigureNewAccountCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfigureNewAccountCommand.kt
new file mode 100644
index 0000000..ed7ee83
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfigureNewAccountCommand.kt
@@ -0,0 +1,23 @@
+package io.timemates.api.rsocket.authorizations.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.sdk
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest
+import io.timemates.api.users.requests.CreateProfileRequest as RSCreateProfileRequest
+
+internal object ConfigureNewAccountCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: ConfigureNewAccountRequest): ConfigureNewAccountRequest.Result {
+ return apis.auth.createProfile(
+ message = RSCreateProfileRequest(
+ verificationHash = input.verificationHash.string,
+ name = input.name.string,
+ description = input.description?.string.orEmpty(),
+ )
+ ).let { result ->
+ ConfigureNewAccountRequest.Result(
+ authorization = result.authorization!!.sdk()
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfirmAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfirmAuthorizationCommand.kt
new file mode 100644
index 0000000..2d19215
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/ConfirmAuthorizationCommand.kt
@@ -0,0 +1,22 @@
+package io.timemates.api.rsocket.authorizations.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.sdk
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest
+import io.timemates.api.authorizations.requests.ConfirmAuthorizationRequest as RSConfirmAuthorizationRequest
+
+internal object ConfirmAuthorizationCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: ConfirmAuthorizationRequest): ConfirmAuthorizationRequest.Result {
+ return apis.auth.confirmAuthorization(
+ message = RSConfirmAuthorizationRequest(
+ input.verificationHash.string, input.confirmationCode.string
+ )
+ ).let { result ->
+ ConfirmAuthorizationRequest.Result(
+ isNewAccount = result.isNewAccount,
+ authorization = result.authorization?.sdk(),
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/GetAuthorizationSessionsCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/GetAuthorizationSessionsCommand.kt
new file mode 100644
index 0000000..7e3dd5b
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/GetAuthorizationSessionsCommand.kt
@@ -0,0 +1,28 @@
+package io.timemates.api.rsocket.authorizations.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.sdk
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.authorization.sessions.requests.GetAuthorizationSessionsRequest
+import io.timemates.sdk.authorization.sessions.types.Authorization
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.common.pagination.Page
+import io.timemates.sdk.common.pagination.PageToken
+import io.timemates.api.authorizations.requests.GetAuthorizationsRequest as RSGetAuthorizationsRequest
+
+internal object GetAuthorizationSessionsCommand : RSocketCommand> {
+ override suspend fun execute(apis: ApiContainer, input: GetAuthorizationSessionsRequest): Page {
+ return apis.auth.getAuthorizations(
+ message = RSGetAuthorizationsRequest(input.nextPageToken?.string.orEmpty()),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ Page(
+ results = result.authorizations.map { it.sdk() },
+ nextPageToken = result.nextPageToken
+ .takeIf { it.isNotEmpty() }
+ ?.let { PageToken.createOrThrow(it) },
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/RenewAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/RenewAuthorizationCommand.kt
new file mode 100644
index 0000000..245143a
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/RenewAuthorizationCommand.kt
@@ -0,0 +1,21 @@
+package io.timemates.api.rsocket.authorizations.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.sdk
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.authorization.sessions.requests.RenewAuthorizationRequest
+import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi
+import io.timemates.api.authorizations.requests.RenewAuthorizationRequest as RSRenewAuthorizationRequest
+
+@OptIn(ExperimentalTimeMatesApi::class)
+internal object RenewAuthorizationCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: RenewAuthorizationRequest): RenewAuthorizationRequest.Result {
+ return apis.auth.renewAuthorization(
+ message = RSRenewAuthorizationRequest(input.refreshHash.string),
+ ).let { result ->
+ RenewAuthorizationRequest.Result(
+ authorization = result.authorization!!.sdk()
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/StartAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/StartAuthorizationCommand.kt
new file mode 100644
index 0000000..cc892ee
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/StartAuthorizationCommand.kt
@@ -0,0 +1,31 @@
+package io.timemates.api.rsocket.authorizations.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.rs
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest
+import io.timemates.sdk.authorization.email.types.value.VerificationHash
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.common.types.value.Count
+import kotlinx.datetime.Instant
+import io.timemates.api.authorizations.requests.StartAuthorizationRequest as RSStartAuthorizationRequest
+
+internal object StartAuthorizationCommand : RSocketCommand {
+ override suspend fun execute(
+ apis: ApiContainer,
+ input: StartAuthorizationRequest,
+ ): StartAuthorizationRequest.Result {
+ return apis.auth.startAuthorization(
+ message = RSStartAuthorizationRequest(
+ input.emailAddress.string,
+ input.metadata.rs(),
+ )
+ ).let { result ->
+ StartAuthorizationRequest.Result(
+ verificationHash = VerificationHash.createOrThrow(result.verificationHash),
+ attempts = Count.createOrThrow(result.attempts),
+ expiresAt = Instant.fromEpochMilliseconds(result.expiresAt),
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/TerminateCurrentAuthorizationCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/TerminateCurrentAuthorizationCommand.kt
new file mode 100644
index 0000000..7e12e41
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/authorizations/commands/TerminateCurrentAuthorizationCommand.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.authorizations.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.authorization.sessions.requests.TerminateCurrentAuthorizationSessionRequest
+import io.timemates.sdk.common.types.Empty
+import com.google.protobuf.Empty.Companion as RSEmpty
+
+internal object TerminateCurrentAuthorizationCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: TerminateCurrentAuthorizationSessionRequest): Empty {
+ return apis.auth.terminateAuthorization(
+ message = RSEmpty.Default,
+ input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommand.kt
new file mode 100644
index 0000000..6403b51
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommand.kt
@@ -0,0 +1,26 @@
+package io.timemates.api.rsocket.common.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.TimeMatesRequest
+
+/**
+ * An interface representing a command that can be executed via an RSocket connection.
+ *
+ * This interface is used to decouple logic by accepting an SDK entity of type [T]
+ * and converting it into the engine's entity type [R] within the implementation.
+ *
+ * @param T The type of the SDK entity that serves as the command's input.
+ * @param R The type of the engine's entity that represents the command's result.
+ */
+internal interface RSocketCommand, R : TimeMatesEntity> {
+ /**
+ * Executes the command using the provided RSocket connection and input of type [T].
+ *
+ * @param apis The RSocket connection over which the command will be executed.
+ * @param input The SDK entity representing the command's input.
+ * @return The engine's entity representing the result of executing the command.
+ * @throws RSocketException if there is an issue with the RSocket communication.
+ */
+ suspend fun execute(apis: ApiContainer, input: T): R
+}
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommands.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommands.kt
new file mode 100644
index 0000000..902aa47
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommands.kt
@@ -0,0 +1,39 @@
+package io.timemates.api.rsocket.common.commands
+
+import io.rsocket.kotlin.RSocket
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.TimeMatesRequest
+
+/**
+ * An inline class that encapsulates a set of RSocket commands for executing TimeMates requests.
+ *
+ * The [RSocketCommands] class allows you to execute TimeMates requests using the provided RSocket
+ * instance. It maintains a map of commands associated with request keys, which are used to look up
+ * the appropriate command for a given request.
+ *
+ * @param commands A map of request keys to RSocket command implementations.
+ */
+@JvmInline
+internal value class RSocketCommands(
+ private val commands: Map, RSocketCommand<*, *>>,
+) {
+ /**
+ * Executes a TimeMates request using the specified RSocket instance.
+ *
+ * This function looks up the appropriate RSocket command based on the request's [requestKey]
+ * and executes it with the provided RSocket and request object.
+ *
+ * @param T The specific type of the TimeMates request.
+ * @param R The type of the response expected from the request.
+ * @param rSocket The RSocket instance to use for executing the request.
+ * @param request The TimeMates request to execute.
+ */
+ suspend inline fun , R : TimeMatesEntity> execute(
+ rSocket: ApiContainer,
+ request: T,
+ ): R? {
+ @Suppress("UNCHECKED_CAST")
+ return (commands[request.requestKey] as? RSocketCommand)?.execute(rSocket, request)
+ }
+}
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommandsBuilderScope.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommandsBuilderScope.kt
new file mode 100644
index 0000000..2889876
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/common/commands/RSocketCommandsBuilderScope.kt
@@ -0,0 +1,37 @@
+package io.timemates.api.rsocket.common.commands
+
+import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.TimeMatesRequest
+
+@RSocketCommandsDsl
+@JvmInline
+internal value class RSocketCommandsBuilderScope(
+ private val commands: MutableMap, RSocketCommand<*, *>> =
+ mutableMapOf(),
+) {
+ fun , R : TimeMatesEntity> associate(
+ key: TimeMatesRequest.Key,
+ command: RSocketCommand,
+ ) {
+ commands += key to command
+ }
+
+
+ infix fun , R : TimeMatesEntity> RSocketCommand.associatedWith(
+ key: TimeMatesRequest.Key,
+ ) {
+ associate(key, this)
+ }
+
+ fun build(): RSocketCommands = RSocketCommands(commands)
+}
+
+@DslMarker
+internal annotation class RSocketCommandsDsl
+
+@RSocketCommandsDsl
+internal inline fun rSocketCommands(
+ block: RSocketCommandsBuilderScope.() -> Unit,
+): RSocketCommands {
+ return RSocketCommandsBuilderScope().apply(block).build()
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/TimerMappers.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/TimerMappers.kt
new file mode 100644
index 0000000..218b64a
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/TimerMappers.kt
@@ -0,0 +1,89 @@
+package io.timemates.api.rsocket.timers
+
+import io.timemates.api.timers.sessions.types.TimerState
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.common.types.value.Count
+import io.timemates.sdk.timers.members.invites.types.value.InviteCode
+import io.timemates.sdk.timers.types.Timer
+import io.timemates.sdk.timers.types.TimerSettings
+import io.timemates.sdk.timers.types.value.TimerDescription
+import io.timemates.sdk.timers.types.value.TimerId
+import io.timemates.sdk.timers.types.value.TimerName
+import io.timemates.sdk.users.profile.types.value.UserId
+import kotlinx.datetime.Instant
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.DurationUnit
+import io.timemates.api.timers.members.invites.types.Invite as RSInvite
+import io.timemates.api.timers.sessions.types.TimerState as RSTimerState
+import io.timemates.api.timers.types.Timer as RSTimer
+import io.timemates.sdk.timers.members.invites.types.Invite as SdkInvite
+import io.timemates.sdk.timers.types.Timer as SdkTimer
+import io.timemates.sdk.timers.types.Timer.State as SdkTimerState
+import io.timemates.sdk.timers.types.TimerSettings as SdkTimerSettings
+
+internal fun RSTimer.sdk(): SdkTimer {
+ return SdkTimer(
+ timerId = TimerId.createOrThrow(id),
+ name = TimerName.createOrThrow(name),
+ description = TimerDescription.createOrThrow(description),
+ ownerId = UserId.createOrThrow(ownerId),
+ membersCount = Count.createOrThrow(membersCount),
+ state = currentState?.sdk() ?: SdkTimerState.Inactive(Instant.DISTANT_PAST),
+ settings = settings?.sdk() ?: TimerSettings(),
+ )
+}
+
+internal fun RSTimerState.sdk(): SdkTimerState {
+ val publishTime = Instant.fromEpochMilliseconds(publishTime)
+ return when (phase) {
+ is TimerState.PhaseOneOf.ConfirmationWaiting -> SdkTimerState.ConfirmationWaiting(
+ endsAt = Instant.fromEpochMilliseconds(phase.value!!.endsAt),
+ publishTime = publishTime,
+ )
+ is TimerState.PhaseOneOf.Inactive -> SdkTimerState.Inactive(
+ publishTime = publishTime,
+ )
+ is TimerState.PhaseOneOf.Paused -> SdkTimerState.Paused(
+ publishTime = publishTime,
+ )
+ is TimerState.PhaseOneOf.Rest -> SdkTimerState.Rest(
+ endsAt = Instant.fromEpochMilliseconds(phase.value!!.endsAt),
+ publishTime = publishTime,
+ )
+ is TimerState.PhaseOneOf.Running -> SdkTimerState.Running(
+ endsAt = Instant.fromEpochMilliseconds(phase.value!!.endsAt),
+ publishTime = publishTime,
+ )
+ null -> SdkTimerState.Inactive(Instant.DISTANT_PAST)
+ }
+}
+
+internal fun RSTimer.Settings.sdk(): SdkTimerSettings {
+ return SdkTimerSettings(
+ workTime = workTime.minutes,
+ restTime = restTime.minutes,
+ bigRestTime = bigRestTime.minutes,
+ bigRestEnabled = bigRestEnabled,
+ bigRestPer = Count.createOrThrow(bigRestPer),
+ isEveryoneCanPause = isEveryoneCanPause,
+ isConfirmationRequired = isConfirmationRequired,
+ )
+}
+
+internal fun SdkTimerSettings.rs(): RSTimer.Settings {
+ return RSTimer.Settings(
+ workTime = workTime.toInt(DurationUnit.MINUTES),
+ restTime = restTime.toInt(DurationUnit.MINUTES),
+ bigRestEnabled = bigRestEnabled,
+ bigRestTime = bigRestTime.toInt(DurationUnit.MINUTES),
+ isConfirmationRequired = isConfirmationRequired,
+ )
+}
+
+internal fun RSInvite.sdk(): SdkInvite {
+ return SdkInvite(
+ inviteCode = InviteCode.createOrThrow(code),
+ creationTime = Instant.fromEpochMilliseconds(creationTime),
+ limit = Count.createOrThrow(limit),
+ )
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/CreateTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/CreateTimerCommand.kt
new file mode 100644
index 0000000..e3b0cea
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/CreateTimerCommand.kt
@@ -0,0 +1,25 @@
+package io.timemates.api.rsocket.timers.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.timers.rs
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.timers.requests.CreateTimerRequest
+import io.timemates.sdk.timers.types.value.TimerId
+import io.timemates.api.timers.requests.CreateTimerRequest as RSCreateTimerRequest
+
+internal object CreateTimerCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: CreateTimerRequest): CreateTimerRequest.Result {
+ return apis.timers.createTimer(
+ message = RSCreateTimerRequest(
+ name = input.name.string,
+ description = input.description.string,
+ settings = input.settings.rs(),
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ CreateTimerRequest.Result(TimerId.createOrThrow(result.timerId))
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/EditTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/EditTimerCommand.kt
new file mode 100644
index 0000000..6ccea2c
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/EditTimerCommand.kt
@@ -0,0 +1,20 @@
+package io.timemates.api.rsocket.timers.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.requests.EditTimerRequest
+import io.timemates.api.timers.requests.EditTimerRequest as RSEditTimerRequest
+
+internal object EditTimerCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: EditTimerRequest): Empty {
+ return apis.timers.editTimer(
+ message = RSEditTimerRequest(
+ timerId = input.timerId.long,
+ name = input.name?.string.orEmpty(),
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetTimerCommand.kt
new file mode 100644
index 0000000..4769722
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetTimerCommand.kt
@@ -0,0 +1,21 @@
+package io.timemates.api.rsocket.timers.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.timers.sdk
+import io.timemates.sdk.timers.requests.GetTimerRequest
+import io.timemates.api.timers.requests.GetTimerRequest as RSGetTimerRequest
+
+internal object GetTimerCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: GetTimerRequest): GetTimerRequest.Result {
+ return apis.timers.getTimer(
+ message = RSGetTimerRequest(
+ timerId = input.timerId.long,
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ GetTimerRequest.Result(result.sdk())
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetUserTimersCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetUserTimersCommand.kt
new file mode 100644
index 0000000..cbfb139
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/GetUserTimersCommand.kt
@@ -0,0 +1,30 @@
+package io.timemates.api.rsocket.timers.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.timers.sdk
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.common.pagination.Page
+import io.timemates.sdk.common.pagination.PageToken
+import io.timemates.sdk.timers.requests.GetUserTimersRequest
+import io.timemates.sdk.timers.types.Timer
+import io.timemates.api.timers.requests.GetTimersRequest as RSGetTimersRequest
+
+internal object GetUserTimersCommand : RSocketCommand> {
+ override suspend fun execute(apis: ApiContainer, input: GetUserTimersRequest): Page {
+ return apis.timers.getTimers(
+ message = RSGetTimersRequest(
+ nextPageToken = input.pageToken?.string.orEmpty(),
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ Page(
+ results = result.timers.map { it.sdk() },
+ nextPageToken = result.nextPageToken
+ .takeIf { it.isNotEmpty() }
+ ?.let { PageToken.createOrThrow(it) },
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/RemoveTimerCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/RemoveTimerCommand.kt
new file mode 100644
index 0000000..5abfeb5
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/RemoveTimerCommand.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.timers.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.requests.RemoveTimerRequest
+import io.timemates.api.timers.requests.RemoveTimerRequest as RSRemoveTimerRequest
+
+internal object RemoveTimerCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: RemoveTimerRequest): Empty {
+ return apis.timers.removeTimer(
+ message = RSRemoveTimerRequest(input.timerId.long),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/TimersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/TimersCommandsRegistry.kt
new file mode 100644
index 0000000..ad3f892
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/commands/TimersCommandsRegistry.kt
@@ -0,0 +1,24 @@
+package io.timemates.api.rsocket.timers.commands
+
+import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope
+import io.timemates.api.rsocket.timers.members.commands.timerMembers
+import io.timemates.api.rsocket.timers.sessions.commands.timerSessions
+import io.timemates.sdk.timers.requests.CreateTimerRequest
+import io.timemates.sdk.timers.requests.EditTimerRequest
+import io.timemates.sdk.timers.requests.GetTimerRequest
+import io.timemates.sdk.timers.requests.GetUserTimersRequest
+import io.timemates.sdk.timers.requests.RemoveTimerRequest
+
+/**
+ * RSocket commands related to timers.
+ */
+internal fun RSocketCommandsBuilderScope.timers() {
+ timerMembers()
+ timerSessions()
+
+ CreateTimerCommand associatedWith CreateTimerRequest
+ EditTimerCommand associatedWith EditTimerRequest
+ GetTimerCommand associatedWith GetTimerRequest
+ RemoveTimerCommand associatedWith RemoveTimerRequest
+ GetUserTimersCommand associatedWith GetUserTimersRequest
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/GetTimerMembersCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/GetTimerMembersCommand.kt
new file mode 100644
index 0000000..91fdbb2
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/GetTimerMembersCommand.kt
@@ -0,0 +1,31 @@
+package io.timemates.api.rsocket.timers.members.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.users.sdk
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.common.pagination.Page
+import io.timemates.sdk.common.pagination.PageToken
+import io.timemates.sdk.timers.members.requests.GetMembersRequest
+import io.timemates.sdk.users.profile.types.User
+import io.timemates.api.timers.members.requests.GetMembersRequest as RSGetMembersRequest
+
+internal object GetTimerMembersCommand : RSocketCommand> {
+ override suspend fun execute(apis: ApiContainer, input: GetMembersRequest): Page {
+ return apis.timers.getMembers(
+ message = RSGetMembersRequest(
+ timerId = input.timerId.long,
+ nextPageToken = input.pageToken?.string.orEmpty(),
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ Page(
+ results = result.users.map { it.sdk() },
+ nextPageToken = result.nextPageToken
+ .takeIf { it.isNotEmpty() }
+ ?.let { PageToken.createOrThrow(it) },
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/KickTimerMemberCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/KickTimerMemberCommand.kt
new file mode 100644
index 0000000..557c09b
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/KickTimerMemberCommand.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.timers.members.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.members.requests.KickMemberRequest
+import io.timemates.api.timers.members.requests.KickMemberRequest as RSKickMemberRequest
+
+internal object KickTimerMemberCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: KickMemberRequest): Empty {
+ return apis.timers.kickMember(
+ message = RSKickMemberRequest(timerId = input.timerId.long),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/TimerMembersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/TimerMembersCommandsRegistry.kt
new file mode 100644
index 0000000..e21024f
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/commands/TimerMembersCommandsRegistry.kt
@@ -0,0 +1,20 @@
+package io.timemates.api.rsocket.timers.members.commands
+
+import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope
+import io.timemates.api.rsocket.timers.members.invites.commands.timerMemberInvites
+import io.timemates.sdk.timers.members.requests.GetMembersRequest
+import io.timemates.sdk.timers.members.requests.KickMemberRequest
+import io.timemates.sdk.timers.requests.CreateTimerRequest
+import io.timemates.sdk.timers.requests.EditTimerRequest
+import io.timemates.sdk.timers.requests.GetTimerRequest
+import io.timemates.sdk.timers.requests.RemoveTimerRequest
+
+/**
+ * RSocket commands related to timer members.
+ */
+internal fun RSocketCommandsBuilderScope.timerMembers() {
+ timerMemberInvites()
+
+ GetTimerMembersCommand associatedWith GetMembersRequest
+ KickTimerMemberCommand associatedWith KickMemberRequest
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/CreateInviteCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/CreateInviteCommand.kt
new file mode 100644
index 0000000..801e38e
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/CreateInviteCommand.kt
@@ -0,0 +1,23 @@
+package io.timemates.api.rsocket.timers.members.invites.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.timers.members.invites.requests.InviteMemberRequest
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.timers.members.invites.requests.CreateInviteRequest
+import io.timemates.sdk.timers.members.invites.types.value.InviteCode
+
+internal object CreateInviteCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: CreateInviteRequest): CreateInviteRequest.Result {
+ return apis.timers.createInvite(
+ message = InviteMemberRequest(
+ timerId = input.timerId.long,
+ maxJoiners = input.maxJoinersCount.int,
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ CreateInviteRequest.Result(InviteCode.createOrThrow(result.inviteCode))
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/GetInvitesCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/GetInvitesCommand.kt
new file mode 100644
index 0000000..08c4f18
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/GetInvitesCommand.kt
@@ -0,0 +1,31 @@
+package io.timemates.api.rsocket.timers.members.invites.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.timers.sdk
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.common.pagination.Page
+import io.timemates.sdk.common.pagination.PageToken
+import io.timemates.sdk.timers.members.invites.requests.GetInvitesRequest
+import io.timemates.sdk.timers.members.invites.types.Invite
+import io.timemates.api.timers.members.invites.requests.GetInvitesRequest as RSGetInvitesRequest
+
+internal object GetInvitesCommand : RSocketCommand> {
+ override suspend fun execute(apis: ApiContainer, input: GetInvitesRequest): Page {
+ return apis.timers.getInvites(
+ message = RSGetInvitesRequest(
+ timerId = input.timerId.long,
+ nextPageToken = input.pageToken?.string.orEmpty(),
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ Page(
+ results = result.invites.map { it.sdk() },
+ nextPageToken = result.nextPageToken
+ .takeIf { it.isNotEmpty() }
+ ?.let { PageToken.createOrThrow(it) },
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/JoinTimerByCodeCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/JoinTimerByCodeCommand.kt
new file mode 100644
index 0000000..11b1c67
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/JoinTimerByCodeCommand.kt
@@ -0,0 +1,23 @@
+package io.timemates.api.rsocket.timers.members.invites.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.timers.sdk
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.timers.members.invites.requests.JoinTimerByCodeRequest
+import io.timemates.sdk.timers.types.value.TimerId
+import io.timemates.api.timers.requests.JoinTimerByInviteCodeRequest as RSJoinTimerByInviteCodeRequest
+
+internal object JoinTimerByCodeCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: JoinTimerByCodeRequest): JoinTimerByCodeRequest.Result {
+ return apis.timers.joinByInvite(
+ message = RSJoinTimerByInviteCodeRequest(
+ inviteCode = input.code.string,
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ JoinTimerByCodeRequest.Result(result.timer!!.sdk())
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/RemoveInviteCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/RemoveInviteCommand.kt
new file mode 100644
index 0000000..65821c9
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/RemoveInviteCommand.kt
@@ -0,0 +1,20 @@
+package io.timemates.api.rsocket.timers.members.invites.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.members.invites.requests.RemoveInviteRequest
+import io.timemates.api.timers.members.invites.requests.RemoveInviteRequest as RSRemoveInviteRequest
+
+internal object RemoveInviteCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: RemoveInviteRequest): Empty {
+ return apis.timers.removeInvite(
+ message = RSRemoveInviteRequest(
+ timerId = input.timerId.long,
+ inviteCode = input.inviteCode.string,
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/TimerMembersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/TimerMembersCommandsRegistry.kt
new file mode 100644
index 0000000..ad64e2a
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/members/invites/commands/TimerMembersCommandsRegistry.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.timers.members.invites.commands
+
+import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope
+import io.timemates.sdk.timers.members.invites.requests.CreateInviteRequest
+import io.timemates.sdk.timers.members.invites.requests.GetInvitesRequest
+import io.timemates.sdk.timers.members.invites.requests.JoinTimerByCodeRequest
+import io.timemates.sdk.timers.members.invites.requests.RemoveInviteRequest
+
+/**
+ * RSocket commands related to timer members.
+ */
+internal fun RSocketCommandsBuilderScope.timerMemberInvites() {
+ CreateInviteCommand associatedWith CreateInviteRequest
+ GetInvitesCommand associatedWith GetInvitesRequest
+ JoinTimerByCodeCommand associatedWith JoinTimerByCodeRequest
+ RemoveInviteCommand associatedWith RemoveInviteRequest
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/ConfirmSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/ConfirmSessionCommand.kt
new file mode 100644
index 0000000..ccc2dc5
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/ConfirmSessionCommand.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.sessions.requests.ConfirmTimerRoundRequest
+import com.google.protobuf.Empty.Companion as RSEmpty
+
+internal object ConfirmSessionCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: ConfirmTimerRoundRequest): Empty {
+ return apis.timerSessions.confirmRound(
+ message = RSEmpty.Default,
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetCurrentSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetCurrentSessionCommand.kt
new file mode 100644
index 0000000..0172b9f
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetCurrentSessionCommand.kt
@@ -0,0 +1,18 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import com.google.protobuf.Empty
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.timers.sdk
+import io.timemates.sdk.timers.sessions.requests.GetUserCurrentSessionRequest
+import io.timemates.sdk.timers.types.Timer
+
+internal object GetCurrentSessionCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: GetUserCurrentSessionRequest): Timer {
+ return apis.timerSessions.getCurrentTimerSession(
+ message = Empty.Default,
+ extra = input.accessHash.toExtra(),
+ ).sdk()
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetTimerStateCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetTimerStateCommand.kt
new file mode 100644
index 0000000..8828690
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/GetTimerStateCommand.kt
@@ -0,0 +1,20 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.timers.sdk
+import io.timemates.sdk.timers.sessions.requests.GetTimerStateRequest
+import kotlinx.coroutines.flow.map
+import io.timemates.api.timers.sessions.requests.GetTimerStateRequest as RSGetTimerStateRequest
+
+internal object GetTimerStateCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: GetTimerStateRequest): GetTimerStateRequest.Result {
+ return apis.timerSessions.getState(
+ message = RSGetTimerStateRequest(timerId = input.timerId.long),
+ extra = input.accessHash.toExtra(),
+ ).let { result ->
+ GetTimerStateRequest.Result(result.map { it.sdk() })
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/JoinSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/JoinSessionCommand.kt
new file mode 100644
index 0000000..114f20f
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/JoinSessionCommand.kt
@@ -0,0 +1,19 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.sessions.requests.JoinTimerSessionRequest
+import io.timemates.api.timers.sessions.requests.JoinTimerSessionRequest as RSJoinTimerSessionRequest
+
+internal object JoinSessionCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: JoinTimerSessionRequest): Empty {
+ return apis.timerSessions.joinSession(
+ message = RSJoinTimerSessionRequest(
+ timerId = input.timerId.long,
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/LeaveSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/LeaveSessionCommand.kt
new file mode 100644
index 0000000..9753d39
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/LeaveSessionCommand.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.sessions.requests.LeaveTimerSessionRequest
+import com.google.protobuf.Empty.Companion as RSEmpty
+
+internal object LeaveSessionCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: LeaveTimerSessionRequest): Empty {
+ return apis.timerSessions.leaveSession(
+ message = RSEmpty.Default,
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/PingSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/PingSessionCommand.kt
new file mode 100644
index 0000000..3c63c6e
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/PingSessionCommand.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.sessions.requests.PingSessionRequest
+import com.google.protobuf.Empty.Companion as RSEmpty
+
+internal object PingSessionCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: PingSessionRequest): Empty {
+ return apis.timerSessions.pingSession(
+ message = RSEmpty.Default,
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StartSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StartSessionCommand.kt
new file mode 100644
index 0000000..c782ab8
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StartSessionCommand.kt
@@ -0,0 +1,19 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.sessions.requests.StartTimerRequest
+import io.timemates.api.timers.sessions.requests.StartTimerRequest as RSStartTimerRequest
+
+internal object StartSessionCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: StartTimerRequest): Empty {
+ return apis.timerSessions.startTimer(
+ message = RSStartTimerRequest(
+ timerId = input.timerId.long,
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StopSessionCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StopSessionCommand.kt
new file mode 100644
index 0000000..e497cbf
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/StopSessionCommand.kt
@@ -0,0 +1,19 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.timers.sessions.requests.StopTimerRequest
+import io.timemates.api.timers.sessions.requests.StopTimerRequest as RSStopTimerRequest
+
+internal object StopSessionCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: StopTimerRequest): Empty {
+ return apis.timerSessions.stopTimer(
+ message = RSStopTimerRequest(
+ timerId = input.timerId.long,
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/TimerSessionsCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/TimerSessionsCommandsRegistry.kt
new file mode 100644
index 0000000..bd38fb0
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/timers/sessions/commands/TimerSessionsCommandsRegistry.kt
@@ -0,0 +1,25 @@
+package io.timemates.api.rsocket.timers.sessions.commands
+
+import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope
+import io.timemates.sdk.timers.sessions.requests.ConfirmTimerRoundRequest
+import io.timemates.sdk.timers.sessions.requests.GetTimerStateRequest
+import io.timemates.sdk.timers.sessions.requests.GetUserCurrentSessionRequest
+import io.timemates.sdk.timers.sessions.requests.JoinTimerSessionRequest
+import io.timemates.sdk.timers.sessions.requests.LeaveTimerSessionRequest
+import io.timemates.sdk.timers.sessions.requests.PingSessionRequest
+import io.timemates.sdk.timers.sessions.requests.StartTimerRequest
+import io.timemates.sdk.timers.sessions.requests.StopTimerRequest
+
+/**
+ * RSocket commands related to timer members.
+ */
+internal fun RSocketCommandsBuilderScope.timerSessions() {
+ ConfirmSessionCommand associatedWith ConfirmTimerRoundRequest
+ LeaveSessionCommand associatedWith LeaveTimerSessionRequest
+ PingSessionCommand associatedWith PingSessionRequest
+ GetCurrentSessionCommand associatedWith GetUserCurrentSessionRequest
+ StartSessionCommand associatedWith StartTimerRequest
+ StopSessionCommand associatedWith StopTimerRequest
+ JoinSessionCommand associatedWith JoinTimerSessionRequest
+ GetTimerStateCommand associatedWith GetTimerStateRequest
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/UsersMapper.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/UsersMapper.kt
new file mode 100644
index 0000000..84d7da2
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/UsersMapper.kt
@@ -0,0 +1,20 @@
+package io.timemates.api.rsocket.users
+
+import io.timemates.sdk.common.constructor.createOrThrow
+import io.timemates.sdk.users.profile.types.Avatar
+import io.timemates.sdk.users.profile.types.value.EmailAddress
+import io.timemates.sdk.users.profile.types.value.UserDescription
+import io.timemates.sdk.users.profile.types.value.UserId
+import io.timemates.sdk.users.profile.types.value.UserName
+import io.timemates.api.users.types.User as RSUser
+import io.timemates.sdk.users.profile.types.User as SdkUser
+
+internal fun RSUser.sdk(): SdkUser {
+ return SdkUser(
+ id = UserId.createOrThrow(id),
+ name = UserName.createOrThrow(name),
+ description = description.takeIf { it.isNotEmpty() }?.let { UserDescription.createOrThrow(it) },
+ emailAddress = email.takeIf { it.isNotEmpty() }?.let { EmailAddress.createOrThrow(it) },
+ avatar = gravatarId.takeIf { it.isNotBlank() }?.let { Avatar.GravatarId.createOrThrow(it) },
+ )
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditEmailCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditEmailCommand.kt
new file mode 100644
index 0000000..b0bb573
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditEmailCommand.kt
@@ -0,0 +1,19 @@
+package io.timemates.api.rsocket.users.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.users.settings.requests.EditEmailRequest
+import io.timemates.api.users.requests.EditEmailRequest as RSEditEmailRequest
+
+@OptIn(ExperimentalTimeMatesApi::class)
+internal object EditEmailCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: EditEmailRequest): Empty {
+ return apis.users.setEmail(
+ message = RSEditEmailRequest(email = input.newEmail.string),
+ extra = input.accessHash.toExtra()
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditProfileCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditProfileCommand.kt
new file mode 100644
index 0000000..0b6ec97
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/EditProfileCommand.kt
@@ -0,0 +1,22 @@
+package io.timemates.api.rsocket.users.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.authorizations.toExtra
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.users.profile.requests.EditProfileRequest
+import io.timemates.sdk.users.profile.types.Avatar
+import io.timemates.api.users.requests.EditUserRequest as RSEditUserRequest
+
+internal object EditProfileCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: EditProfileRequest): Empty {
+ return apis.users.setUser(
+ message = RSEditUserRequest(
+ gravatarId = (input.avatar as? Avatar.GravatarId)?.string.orEmpty(),
+ name = input.name?.string.orEmpty(),
+ description = input.description?.string.orEmpty(),
+ ),
+ extra = input.accessHash.toExtra(),
+ ).let { _ -> Empty }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/GetUsersCommand.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/GetUsersCommand.kt
new file mode 100644
index 0000000..85e7a5b
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/GetUsersCommand.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.users.commands
+
+import io.timemates.api.rsocket.ApiContainer
+import io.timemates.api.rsocket.common.commands.RSocketCommand
+import io.timemates.api.rsocket.users.sdk
+import io.timemates.sdk.users.profile.requests.GetUsersRequest
+import io.timemates.api.users.requests.GetUsersRequest as RSGetUsersRequest
+
+internal object GetUsersCommand : RSocketCommand {
+ override suspend fun execute(apis: ApiContainer, input: GetUsersRequest): GetUsersRequest.Result {
+ return apis.users.getUsers(
+ message = RSGetUsersRequest(userId = input.users.map { it.long }),
+ ).let { result ->
+ GetUsersRequest.Result(result.users.map { it.sdk() })
+ }
+ }
+}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/UsersCommandsRegistry.kt b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/UsersCommandsRegistry.kt
new file mode 100644
index 0000000..89ee76c
--- /dev/null
+++ b/rsocket-engine/src/main/kotlin/io/timemates/api/rsocket/users/commands/UsersCommandsRegistry.kt
@@ -0,0 +1,17 @@
+package io.timemates.api.rsocket.users.commands
+
+import io.timemates.api.rsocket.common.commands.RSocketCommandsBuilderScope
+import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi
+import io.timemates.sdk.users.profile.requests.EditProfileRequest
+import io.timemates.sdk.users.profile.requests.GetUsersRequest
+import io.timemates.sdk.users.settings.requests.EditEmailRequest
+
+/**
+ * RSocket commands related to user operations.
+ */
+@OptIn(ExperimentalTimeMatesApi::class)
+internal fun RSocketCommandsBuilderScope.users() {
+ EditProfileCommand associatedWith EditProfileRequest
+ GetUsersCommand associatedWith GetUsersRequest
+ EditEmailCommand associatedWith EditEmailRequest
+}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto
similarity index 81%
rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto
index 059cfea..c27c867 100644
--- a/grpc-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto
+++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/AuthorizationService.proto
@@ -5,6 +5,7 @@ import "io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.pro
import "io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto";
import "io/timemates/api/authorizations/options/OmitAuthorizationOption.proto";
import "io/timemates/api/authorizations/requests/CreateProfileRequest.proto";
+import "io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto";
import "io/timemates/api/authorizations/types/Authorization.proto";
import "google/protobuf/empty.proto";
@@ -31,6 +32,18 @@ service AuthorizationService {
option (omit_authorization) = true;
}
+ /**
+ * Renews authorization using refresh token.
+ *
+ * Returns: new [Authorization].
+ */
+ rpc renewAuthorization(RenewAuthorizationRequest) returns (RenewAuthorizationRequest.Response) {
+ option (omit_authorization) = true;
+ }
+
+ /**
+ * Creates a user's profile if it's a new account.
+ */
rpc createProfile(CreateProfileRequest) returns (CreateProfileRequest.Response) {
option (omit_authorization) = true;
}
diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/options/OmitAuthorizationOption.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/ConfirmAuthorizationRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/CreateProfileRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/GetAuthorizationsRequest.proto
diff --git a/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto
new file mode 100644
index 0000000..f5ad398
--- /dev/null
+++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/RenewAuthorizationRequest.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+import "io/timemates/api/authorizations/types/Authorization.proto";
+
+option java_package = "io.timemates.api.authorizations.requests";
+
+message RenewAuthorizationRequest {
+ string refreshHash = 1;
+
+ message Response {
+ Authorization authorization = 1;
+ }
+}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto
similarity index 60%
rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto
index 605b36e..1992b67 100644
--- a/grpc-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto
+++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/requests/StartAuthorizationRequest.proto
@@ -1,10 +1,15 @@
syntax = "proto3";
+import "io/timemates/api/authorizations/types/Authorization.proto";
+import "io/timemates/api/authorizations/types/Metadata.proto";
+
option java_package = "io.timemates.api.authorizations.requests";
message StartAuthorizationRequest {
string emailAddress = 1;
+ optional Metadata metadata = 2;
+
message Result {
string verificationHash = 1;
int64 expiresAt = 2;
diff --git a/grpc-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto
similarity index 84%
rename from grpc-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto
index db61522..a7908e3 100644
--- a/grpc-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto
+++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Authorization.proto
@@ -1,5 +1,7 @@
syntax = "proto3";
+import "io/timemates/api/authorizations/types/Metadata.proto";
+
option java_package = "io.timemates.api.authorizations.types";
message Authorization {
@@ -27,14 +29,13 @@ message Authorization {
*/
optional Metadata metadata = 5;
+ /**
+ * Owner's id.
+ */
+ int64 userId = 6;
+
message Hash {
string value = 1;
int64 expiresAt = 2;
}
-
- message Metadata {
- string clientName = 1;
- string clientVersion = 2;
- string clientIpAddress = 3;
- }
}
\ No newline at end of file
diff --git a/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Metadata.proto b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Metadata.proto
new file mode 100644
index 0000000..75d00a1
--- /dev/null
+++ b/rsocket-engine/src/main/proto/io/timemates/api/authorizations/types/Metadata.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+
+option java_package = "io.timemates.api.authorizations.types";
+
+message Metadata {
+ string clientName = 1;
+ double clientVersion = 2;
+}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/TimersService.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/TimersService.proto
similarity index 89%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/TimersService.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/TimersService.proto
index ff8cfc5..3300089 100644
--- a/grpc-engine/src/main/proto/io/timemates/api/timers/TimersService.proto
+++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/TimersService.proto
@@ -10,6 +10,7 @@ import "io/timemates/api/timers/members/requests/GetMembersRequest.proto";
import "io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto";
import "io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto";
import "io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto";
+import "io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto";
import "io/timemates/api/timers/types/Timer.proto";
import "google/protobuf/empty.proto";
@@ -61,6 +62,11 @@ service TimersService {
*/
rpc removeInvite(RemoveInviteRequest) returns (google.protobuf.Empty);
+ /**
+ * Joins timer by invite code.
+ */
+ rpc joinByInvite(JoinTimerByInviteCodeRequest) returns (JoinTimerByInviteCodeRequest.Response);
+
/**
* Removes timer.
*/
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/CreateInviteRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/GetInvitesRequest.proto
diff --git a/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto
new file mode 100644
index 0000000..448bb0e
--- /dev/null
+++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/JoinTimerByInviteCodeRequest.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+import "io/timemates/api/timers/types/Timer.proto";
+
+option java_package = "io.timemates.api.timers.requests";
+
+message JoinTimerByInviteCodeRequest {
+ string inviteCode = 1;
+
+ message Response {
+ Timer timer = 1;
+ }
+}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/requests/RemoveInviteRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/invites/types/Invite.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/GetMembersRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/members/requests/KickMemberRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto
similarity index 73%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto
index 945ec05..144ff68 100644
--- a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto
+++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/CreateTimerRequest.proto
@@ -5,18 +5,17 @@ import "io/timemates/api/timers/types/Timer.proto";
option java_package = "io.timemates.api.timers.requests";
message CreateTimerRequest {
- int64 timerId = 1;
/**
* Timer's name. Up to 50 symbols.
*/
- string name = 2;
+ string name = 1;
/**
* Timer's name. Up to 500 symbols.
*/
- optional string description = 3;
+ optional string description = 2;
- optional Timer.Settings settings = 4;
+ optional Timer.Settings settings = 3;
message Response {
int64 timerId = 1;
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/EditTimerInfoRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimerRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/GetTimersRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/requests/RemoveTimerRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto
similarity index 93%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto
index fcfe1ce..d34518d 100644
--- a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto
+++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/TimerSessionsService.proto
@@ -5,10 +5,10 @@ import "io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto"
import "io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto";
import "io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto";
import "io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto";
-import "io/timemates/api/timers/sessions/requests/GetUserCurrentSessionRequest.proto";
import "io/timemates/api/timers/sessions/types/TimerState.proto";
-import "io/timemates/api/timers/types/Timer.proto";
import "google/protobuf/empty.proto";
+import "io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto";
+import "io/timemates/api/timers/types/Timer.proto";
option java_package = "io.timemates.api.timers";
@@ -67,5 +67,5 @@ service TimerSessionsService {
/**
* Gets current timer session
*/
- rpc getUserCurrentSession(google.protobuf.Empty) returns (Timer);
+ rpc getCurrentTimerSession(google.protobuf.Empty) returns (Timer);
}
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/ConfirmTimerSessionRequest.proto
diff --git a/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto
new file mode 100644
index 0000000..150599d
--- /dev/null
+++ b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetCurrentTimerSessionRequest.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+
+import "io/timemates/api/timers/types/Timer.proto";
+
+option java_package = "io.timemates.api.timers.requests";
+
+message GetCurrentTimerSessionRequest {
+ message Response {
+ Timer timer = 1;
+ }
+}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/GetTimerStateRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/JoinTimerSessionRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StartTimerSessionRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/requests/StopTimerSessionRequest.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/sessions/types/TimerState.proto
diff --git a/grpc-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto b/rsocket-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/timers/types/Timer.proto
diff --git a/rsocket-engine/src/main/proto/io/timemates/api/users/UsersService.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/UsersService.proto
new file mode 100644
index 0000000..f9e6524
--- /dev/null
+++ b/rsocket-engine/src/main/proto/io/timemates/api/users/UsersService.proto
@@ -0,0 +1,32 @@
+syntax = "proto3";
+
+import "io/timemates/api/users/requests/GetUsersRequest.proto";
+import "io/timemates/api/users/requests/EditUserRequest.proto";
+import "io/timemates/api/users/requests/EditEmailRequest.proto";
+import "io/timemates/api/users/types/User.proto";
+import "google/protobuf/empty.proto";
+
+option java_package = "io.timemates.api.users";
+
+service UsersService {
+ /**
+ * Gets users by given identifiers.
+ *
+ * Returns [User] or null.
+ */
+ rpc getUsers(GetUsersRequest) returns (Users);
+
+ /**
+ * Sets user information (name / description / avatar file id).
+ *
+ * Returns [Status]
+ */
+ rpc setUser(EditUserRequest) returns (google.protobuf.Empty);
+
+ /**
+ * Sets new email for current user.
+ *
+ * Returns [Status]
+ */
+ rpc setEmail(EditEmailRequest) returns (google.protobuf.Empty);
+}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditEmailRequest.proto
diff --git a/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto
new file mode 100644
index 0000000..53b072c
--- /dev/null
+++ b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/EditUserRequest.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+option java_package = "io.timemates.api.users.requests";
+
+message EditUserRequest {
+ /**
+ * User's avatar id
+ */
+ string gravatarId = 1;
+ /**
+ * User's name
+ */
+ optional string name = 2;
+
+ /**
+ * User's description.
+ */
+ optional string description = 3;
+}
\ No newline at end of file
diff --git a/grpc-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto
similarity index 100%
rename from grpc-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto
rename to rsocket-engine/src/main/proto/io/timemates/api/users/requests/GetUsersRequest.proto
diff --git a/rsocket-engine/src/main/proto/io/timemates/api/users/types/User.proto b/rsocket-engine/src/main/proto/io/timemates/api/users/types/User.proto
new file mode 100644
index 0000000..62e9437
--- /dev/null
+++ b/rsocket-engine/src/main/proto/io/timemates/api/users/types/User.proto
@@ -0,0 +1,32 @@
+syntax = "proto3";
+
+option java_package = "io.timemates.api.users.types";
+
+message User {
+ /**
+ * User's identifier
+ */
+ int64 id = 1;
+
+ string gravatarId = 3;
+
+ /**
+ * User's name
+ */
+ string name = 4;
+
+ /**
+ * User's description.
+ */
+ string description = 5;
+
+ /**
+ * User's email up to 200 symbols.
+ * Can be null if there is no access.
+ */
+ optional string email = 6;
+}
+
+message Users {
+ repeated User users = 1;
+}
\ No newline at end of file
diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts
index bdad811..8c72269 100644
--- a/sdk/build.gradle.kts
+++ b/sdk/build.gradle.kts
@@ -33,4 +33,8 @@ deployLibrary {
version = System.getenv("TIMEMATES_SDK_VERSION")
}
+}
+
+tasks.withType {
+ useJUnitPlatform()
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt
index 011a199..3a85a35 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/EmailAuthorizationApi.kt
@@ -4,6 +4,7 @@ import io.timemates.sdk.authorization.email.requests.ConfigureNewAccountRequest
import io.timemates.sdk.authorization.email.requests.ConfirmAuthorizationRequest
import io.timemates.sdk.authorization.email.requests.StartAuthorizationRequest
import io.timemates.sdk.authorization.email.types.value.VerificationHash
+import io.timemates.sdk.authorization.sessions.types.Authorization
import io.timemates.sdk.authorization.sessions.types.value.ConfirmationCode
import io.timemates.sdk.common.engine.TimeMatesRequestsEngine
import io.timemates.sdk.users.profile.types.value.EmailAddress
@@ -21,8 +22,12 @@ public class EmailAuthorizationApi(private val engine: TimeMatesRequestsEngine)
*
* @see confirm
*/
- public suspend fun authorize(emailAddress: EmailAddress): Result {
- return engine.execute(StartAuthorizationRequest(emailAddress)).map { it.verificationHash }
+ public suspend fun authorize(
+ emailAddress: EmailAddress,
+ metadata: Authorization.Metadata,
+ ): Result {
+ return engine.execute(StartAuthorizationRequest(emailAddress, metadata))
+ .map { it.verificationHash }
}
/**
@@ -36,7 +41,7 @@ public class EmailAuthorizationApi(private val engine: TimeMatesRequestsEngine)
public suspend fun confirm(
verificationHash: VerificationHash,
confirmationCode: ConfirmationCode,
- ): Result {
+ ): Result {
return engine.execute(ConfirmAuthorizationRequest(verificationHash, confirmationCode))
}
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt
index 8a11ec5..cb4f74c 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfigureNewAccountRequest.kt
@@ -10,7 +10,12 @@ import io.timemates.sdk.users.profile.types.value.UserName
public data class ConfigureNewAccountRequest(
val verificationHash: VerificationHash,
val name: UserName,
- val description: UserDescription,
+ val description: UserDescription?,
) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
public data class Result(val authorization: Authorization) : TimeMatesEntity()
+
+ override val requestKey: Key
+ get() = Key
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt
index 6e9d3a4..3296000 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/ConfirmAuthorizationRequest.kt
@@ -1,17 +1,22 @@
package io.timemates.sdk.authorization.email.requests
+import io.timemates.sdk.authorization.email.types.value.VerificationHash
import io.timemates.sdk.authorization.sessions.types.Authorization
import io.timemates.sdk.authorization.sessions.types.value.ConfirmationCode
-import io.timemates.sdk.authorization.email.types.value.VerificationHash
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
public data class ConfirmAuthorizationRequest(
val verificationHash: VerificationHash,
val confirmationCode: ConfirmationCode,
-) : TimeMatesRequest() {
- public data class Response(
+) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ public data class Result(
val isNewAccount: Boolean,
val authorization: Authorization?,
) : TimeMatesEntity()
+
+ override val requestKey: Key
+ get() = Key
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt
index 7c103d4..cf1411b 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/email/requests/StartAuthorizationRequest.kt
@@ -1,18 +1,24 @@
package io.timemates.sdk.authorization.email.requests
-import io.timemates.sdk.users.profile.types.value.EmailAddress
import io.timemates.sdk.authorization.email.types.value.VerificationHash
+import io.timemates.sdk.authorization.sessions.types.Authorization
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.common.types.value.Count
+import io.timemates.sdk.users.profile.types.value.EmailAddress
import kotlinx.datetime.Instant
public data class StartAuthorizationRequest(
- val emailAddress: EmailAddress
+ val emailAddress: EmailAddress,
+ val metadata: Authorization.Metadata,
) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
public data class Result(
val verificationHash: VerificationHash,
val attempts: Count,
val expiresAt: Instant,
) : TimeMatesEntity()
+
+ override val requestKey: Key get() = Key
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt
index 6150783..5510830 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/AuthorizedSessionsApi.kt
@@ -16,9 +16,6 @@ import io.timemates.sdk.common.providers.AccessHashProvider
import io.timemates.sdk.common.providers.getAsResult
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.value.Count
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flow
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
@@ -55,6 +52,7 @@ public class AuthorizedSessionsApi(
}
}
+@Suppress("NAME_SHADOWING")
public fun AuthorizedSessionsApi.getSessionsPages(
pageToken: PageToken?,
maxRetries: Count = Count.createOrThrow(5),
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt
index d727df4..96d605b 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/GetAuthorizationSessionsRequest.kt
@@ -4,10 +4,15 @@ import io.timemates.sdk.authorization.sessions.types.Authorization
import io.timemates.sdk.authorization.types.value.AccessHash
import io.timemates.sdk.common.pagination.Page
import io.timemates.sdk.common.pagination.PageToken
-import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesRequest
public data class GetAuthorizationSessionsRequest(
val nextPageToken: PageToken?,
- val accessHash: AccessHash,
-) : TimeMatesRequest>()
\ No newline at end of file
+ override val accessHash: AccessHash,
+) : AuthorizedTimeMatesRequest>() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key
+ get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/RenewAuthorizationRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/RenewAuthorizationRequest.kt
new file mode 100644
index 0000000..6b9adb2
--- /dev/null
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/RenewAuthorizationRequest.kt
@@ -0,0 +1,23 @@
+package io.timemates.sdk.authorization.sessions.requests
+
+import io.timemates.sdk.authorization.sessions.types.Authorization
+import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.authorization.types.value.HashValue
+import io.timemates.sdk.common.annotations.ApiStatus
+import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi
+import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.TimeMatesRequest
+
+@ExperimentalTimeMatesApi(status = ApiStatus.IN_PROGRESS)
+public data class RenewAuthorizationRequest(
+ val refreshHash: HashValue,
+) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ @ExperimentalTimeMatesApi(status = ApiStatus.NEEDS_REVISION)
+ public data class Result(
+ val authorization: Authorization,
+ ) : TimeMatesEntity()
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt
index 2406b88..5eee55f 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/requests/TerminateCurrentAuthorizationSessionRequest.kt
@@ -1,9 +1,14 @@
package io.timemates.sdk.authorization.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
public data class TerminateCurrentAuthorizationSessionRequest(
- val accessHash: AccessHash
-) : TimeMatesRequest()
\ No newline at end of file
+ override val accessHash: AccessHash,
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt
index 57260ac..f956ac5 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/Authorization.kt
@@ -1,17 +1,19 @@
package io.timemates.sdk.authorization.sessions.types
+import io.timemates.sdk.authorization.sessions.types.value.ApplicationName
import io.timemates.sdk.authorization.sessions.types.value.ClientIpAddress
-import io.timemates.sdk.authorization.sessions.types.value.ClientName
import io.timemates.sdk.authorization.sessions.types.value.ClientVersion
import io.timemates.sdk.authorization.types.value.HashValue
import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.users.profile.types.value.UserId
import kotlinx.datetime.Instant
public data class Authorization(
val accessHash: Hash?,
val refreshHash: Hash?,
val generationTime: Instant,
- val metadata: Metadata?
+ val metadata: Metadata?,
+ val userId: UserId,
) : TimeMatesEntity() {
public data class Hash(
val value: HashValue,
@@ -19,7 +21,7 @@ public data class Authorization(
) : TimeMatesEntity()
public data class Metadata(
- val clientName: ClientName,
+ val applicationName: ApplicationName,
val clientVersion: ClientVersion,
val clientIpAddress: ClientIpAddress,
) : TimeMatesEntity()
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt
new file mode 100644
index 0000000..aad89c8
--- /dev/null
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ApplicationName.kt
@@ -0,0 +1,12 @@
+package io.timemates.sdk.authorization.sessions.types.value
+
+import io.timemates.sdk.common.constructor.Factory
+
+@JvmInline
+public value class ApplicationName private constructor(public val string: String) {
+ public companion object : Factory() {
+ override fun create(input: String): Result {
+ return Result.success(ApplicationName(input))
+ }
+ }
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientName.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientName.kt
deleted file mode 100644
index f2eb3ca..0000000
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientName.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.timemates.sdk.authorization.sessions.types.value
-
-import io.timemates.sdk.common.constructor.Factory
-
-@JvmInline
-public value class ClientName private constructor(public val string: String) {
- public companion object : Factory() {
- override fun create(input: String): Result {
- return Result.success(ClientName(input))
- }
- }
-}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt
index d5f2767..c43e388 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/authorization/sessions/types/value/ClientVersion.kt
@@ -3,9 +3,9 @@ package io.timemates.sdk.authorization.sessions.types.value
import io.timemates.sdk.common.constructor.Factory
@JvmInline
-public value class ClientVersion private constructor(public val string: String) {
- public companion object : Factory() {
- override fun create(input: String): Result {
+public value class ClientVersion private constructor(public val double: Double) {
+ public companion object : Factory() {
+ override fun create(input: Double): Result {
return Result.success(ClientVersion(input))
}
}
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalTimeMatesApi.kt
similarity index 81%
rename from sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalApi.kt
rename to sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalTimeMatesApi.kt
index a920340..a45ed91 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalApi.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/annotations/ExperimentalTimeMatesApi.kt
@@ -4,7 +4,7 @@ package io.timemates.sdk.common.annotations
* Annotation used to indicate that a given SDK API is experimental.
*/
@RequiresOptIn(message = "Given SDK API is experimental", level = RequiresOptIn.Level.ERROR)
-public annotation class ExperimentalApi(val status: ApiStatus)
+public annotation class ExperimentalTimeMatesApi(val status: ApiStatus)
public enum class ApiStatus {
PROTOTYPE,
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/exceptions/handler/SafeExceptionResult.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/exceptions/handler/SafeExceptionResult.kt
deleted file mode 100644
index 352fdc8..0000000
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/exceptions/handler/SafeExceptionResult.kt
+++ /dev/null
@@ -1,221 +0,0 @@
-@file:OptIn(InternalApi::class, ExperimentalApi::class)
-
-package io.timemates.sdk.common.exceptions.handler
-
-import io.timemates.sdk.common.annotations.ApiStatus
-import io.timemates.sdk.common.annotations.ExperimentalApi
-import io.timemates.sdk.common.annotations.InternalApi
-import io.timemates.sdk.common.types.TimeMatesEntity
-import io.timemates.sdk.common.exceptions.*
-
-/**
- * Represents a type-safe wrapper class for handling exceptions in the context of an operation's result.
- *
- * The [SafeExceptionResult] class provides a convenient way to handle exceptions and control the flow of execution based on the encountered exception types.
- * It is designed to ensure type safety by using the generic type parameters [T] for the result value and [E] for the exception type.
- *
- * @param T The type of the result value.
- * @param E The type of the exception.
- * @property result The original result of the operation.
- */
-@ExperimentalApi(status = ApiStatus.NEEDS_REVISION)
-@JvmInline
-public value class SafeExceptionResult @InternalApi constructor(
- @property:InternalApi public val result: Result
-)
-
-/**
- * Converts a [Result] into a [SafeExceptionResult] for safe exception handling.
- *
- * The [safeResult] function is used to wrap the original [Result] in a [SafeExceptionResult],
- * which allows for more controlled handling of exceptions within the operation's result.
- *
- * @receiver The original result of the operation.
- * @return The [SafeExceptionResult] containing the original result.
- */
-@ExperimentalApi(status = ApiStatus.NEEDS_REVISION)
-public fun Result.safeResult(): SafeExceptionResult {
- return SafeExceptionResult(this)
-}
-
-/**
- * Executes a specified block if the encountered exception is of type [UnauthorizedException].
- *
- * The [whenUnauthorized] function enables controlled handling of the [UnauthorizedException] by executing the provided block
- * if the encountered exception matches the type [UnauthorizedException].
- *
- * @param block The block of code to be executed if the encountered exception is [UnauthorizedException].
- * @return The [SafeExceptionResult] after executing the block.
- */
-public inline fun SafeExceptionResult.whenUnauthorized(
- block: (UnauthorizedException) -> Unit
-): SafeExceptionResult {
- val exception = result.exceptionOrNull()
- if (exception is UnauthorizedException)
- block(exception)
-
- return SafeExceptionResult(result)
-}
-
-/**
- * Executes a specified block if the encountered exception is of type [UnavailableException].
- *
- * The [whenUnavailable] function allows for controlled handling of the [UnavailableException] by executing the provided block
- * if the encountered exception matches the type [UnavailableException].
- *
- * @param block The block of code to be executed if the encountered exception is [UnavailableException].
- * @return The [SafeExceptionResult] after executing the block.
- */
-public inline fun SafeExceptionResult.whenUnavailable(
- block: (UnavailableException) -> Unit
-): SafeExceptionResult {
- val exception = result.exceptionOrNull()
- if (exception is UnavailableException)
- block(exception)
-
- return SafeExceptionResult(result)
-}
-
-/**
- * Executes a specified block if the encountered exception is of type [TooManyRequestsException].
- *
- * The [whenTooManyRequests] function allows for controlled handling of the [TooManyRequestsException] by executing the provided block
- * if the encountered exception matches the type [TooManyRequestsException].
- *
- * @param block The block of code to be executed if the encountered exception is [TooManyRequestsException].
- * @return The [SafeExceptionResult] after executing the block.
- */
-public inline fun SafeExceptionResult.whenTooManyRequests(
- block: (TooManyRequestsException) -> Unit
-): SafeExceptionResult {
- val exception = result.exceptionOrNull()
- if (exception is TooManyRequestsException)
- block(exception)
-
- return SafeExceptionResult(result)
-}
-
-/**
- * Executes a specified block if the encountered exception is of type [NotFoundException].
- *
- * The [whenNotFound] function allows for controlled handling of the [NotFoundException] by executing the provided block
- * if the encountered exception matches the type [NotFoundException].
- *
- * @param block The block of code to be executed if the encountered exception is [NotFoundException].
- * @return The [SafeExceptionResult] after executing the block.
- */
-public inline fun SafeExceptionResult.whenNotFound(
- block: (NotFoundException) -> Unit
-): SafeExceptionResult {
- val exception = result.exceptionOrNull()
- if (exception is NotFoundException)
- block(exception)
-
- return SafeExceptionResult(result)
-}
-
-/**
- * Ignores the [NotFoundException] exception and continues execution.
- *
- * The [ignoreNotFound] function allows for ignoring the [NotFoundException] exception
- * and continuing the flow of execution without interruption.
- *
- * @receiver The [SafeExceptionResult].
- * @return The [SafeExceptionResult] after ignoring the [NotFoundException].
- */
-public fun SafeExceptionResult.ignoreNotFound(): SafeExceptionResult {
- return SafeExceptionResult(result)
-}
-
-/**
- * Executes a specified block if any exception is encountered.
- *
- * **Any inheritor of [TimeMatesException] are ignored here.**
- *
- * The [whenOtherError] function allows for handling any encountered exception by executing the provided block.
- * It is useful for executing common error-handling code regardless of the specific exception type.
- *
- * @param block The block of code to be executed if any exception is encountered.
- * @return The [SafeExceptionResult] after executing the block.
- */
-@ExperimentalApi(status = ApiStatus.NEEDS_REVISION)
-public inline fun SafeExceptionResult.whenOtherError(
- block: (E) -> Unit
-): SafeExceptionResult {
- result.exceptionOrNull()?.takeIf { it !is TimeMatesException }?.let {
- @Suppress("UNCHECKED_CAST")
- block(it as E)
- }
-
- return SafeExceptionResult(result)
-}
-
-/**
- * Handles **ANY** throwable, even inheritors of [TimeMatesException]. You should use it if
- * you want to handle some failure logic more than one time or when you want to ignore type-safe
- * way of handling failures with [whenUnauthorized], [whenUnavailable], etc.
- *
- * But, if it's possible, it's better to use just [Result] API instead of [SafeExceptionResult].
- */
-@ExperimentalApi(status = ApiStatus.NEEDS_REVISION)
-public inline fun SafeExceptionResult.whenAnyError(
- block: (Throwable) -> Unit
-): SafeExceptionResult {
- result.exceptionOrNull()?.let(block)
-
- return SafeExceptionResult(result)
-}
-
-/**
- * Executes a specified block if the operation is successful.
- *
- * The [whenSuccess] function allows for executing a block of code if the operation is successful,
- * providing access to the result value for further processing.
- *
- * @param block The block of code to be executed if the operation is successful.
- */
-public inline fun SafeExceptionResult.whenSuccess(
- block: (T) -> Unit
-) {
- if(result.isSuccess)
- block(result.getOrThrow())
-}
-
-/**
- * Ignores the [UnauthorizedException] exception and continues execution.
- *
- * The [ignoreUnauthorized] function allows for ignoring the [UnauthorizedException] exception
- * and continuing the flow of execution without interruption.
- *
- * @receiver The [SafeExceptionResult].
- * @return The [SafeExceptionResult] after ignoring the [UnauthorizedException].
- */
-public fun SafeExceptionResult.ignoreUnauthorized(): SafeExceptionResult {
- return SafeExceptionResult(result)
-}
-
-/**
- * Ignores the [TooManyRequestsException] exception and continues execution.
- *
- * The [ignoreTooManyRequests] function allows for ignoring the [TooManyRequestsException] exception
- * and continuing the flow of execution without interruption.
- *
- * @receiver The [SafeExceptionResult].
- * @return The [SafeExceptionResult] after ignoring the [TooManyRequestsException].
- */
-public fun SafeExceptionResult.ignoreTooManyRequests(): SafeExceptionResult {
- return SafeExceptionResult(result)
-}
-
-/**
- * Ignores the [UnavailableException] exception and continues execution.
- *
- * The [ignoreUnavailable] function allows for ignoring the [UnavailableException] exception
- * and continuing the flow of execution without interruption.
- *
- * @receiver The [SafeExceptionResult].
- * @return The [SafeExceptionResult] after ignoring the [UnavailableException].
- */
-public fun SafeExceptionResult.ignoreUnavailable(): SafeExceptionResult {
- return SafeExceptionResult(result)
-}
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt
index fddd1d7..647c137 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/pagination/PagesIterator.kt
@@ -1,7 +1,7 @@
package io.timemates.sdk.common.pagination
import io.timemates.sdk.common.annotations.ApiStatus
-import io.timemates.sdk.common.annotations.ExperimentalApi
+import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi
import io.timemates.sdk.common.constructor.createOrThrow
import io.timemates.sdk.common.exceptions.TimeMatesException
import io.timemates.sdk.common.pagination.PagesIteratorImpl.State
@@ -60,7 +60,7 @@ public fun PagesIterator.asFlow(): Flow>> = flow {
*
* @return A [List] containing all elements from the page iterator.
*/
-@ExperimentalApi(status = ApiStatus.NEEDS_REVISION)
+@ExperimentalTimeMatesApi(status = ApiStatus.NEEDS_REVISION)
public suspend fun PagesIterator.toList(): List> {
return buildList {
for (result in this@toList) {
@@ -78,7 +78,7 @@ public suspend fun PagesIterator.toList(): List> {
*
* @return A [Sequence] containing all elements from the page iterator.
*/
-@ExperimentalApi(status = ApiStatus.NEEDS_REVISION)
+@ExperimentalTimeMatesApi(status = ApiStatus.NEEDS_REVISION)
public suspend fun PagesIterator.asSequence(): Sequence> {
return toList().asSequence()
}
@@ -99,7 +99,7 @@ public suspend inline fun PagesIterator.forEachPage(block: (Result PagesIterator.forEach(block: (Result) -> Unit) {
forEachPage { page ->
if (page.isSuccess) {
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt
index 83b8b23..ae80877 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/providers/AccessHashProvider.kt
@@ -6,7 +6,7 @@ import io.timemates.sdk.common.exceptions.UnauthorizedException
/**
* Interface for providing access token hashes.
*/
-public interface AccessHashProvider {
+public fun interface AccessHashProvider {
/**
* Retrieves the access hash or null if not available.
* @return The [AccessHash] or null.
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/AuthorizedTimeMatesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/AuthorizedTimeMatesRequest.kt
new file mode 100644
index 0000000..36bffc7
--- /dev/null
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/AuthorizedTimeMatesRequest.kt
@@ -0,0 +1,18 @@
+package io.timemates.sdk.common.types
+
+import io.timemates.sdk.authorization.types.value.AccessHash
+
+/**
+ * An abstract class representing an authorized request within the TimeMates system.
+ * Subclasses of this class are used to perform operations that require valid
+ * authorization via an access hash.
+ *
+ * @param R The response type expected from the request.
+ */
+public abstract class AuthorizedTimeMatesRequest : TimeMatesRequest() {
+ /**
+ * The access hash associated with this authorized request.
+ * It is used for authentication and authorization purposes.
+ */
+ public abstract val accessHash: AccessHash
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt
index b74177f..531a182 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/common/types/TimeMatesRequest.kt
@@ -8,4 +8,15 @@ package io.timemates.sdk.common.types
*
* @param R The type of the response expected from the request.
*/
-public abstract class TimeMatesRequest internal constructor() : TimeMatesEntity()
\ No newline at end of file
+public abstract class TimeMatesRequest internal constructor() : TimeMatesEntity() {
+ /**
+ * A unique key that identifies this request type.
+ */
+ public abstract val requestKey: Key<*>
+
+ /**
+ * An interface representing the key associated with a [TimeMatesRequest].
+ * @param T The specific type of the [TimeMatesRequest].
+ */
+ public interface Key>
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt
index 8aa4b3e..e95b864 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/GetFileBytesRequest.kt
@@ -2,13 +2,19 @@ package io.timemates.sdk.files.requests
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
+import io.timemates.sdk.files.types.FileType
import io.timemates.sdk.files.types.value.FileId
import kotlinx.coroutines.flow.Flow
public data class GetFileBytesRequest(
val fileId: FileId,
) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
public data class Result(
+ val fileType: FileType,
val bytes: Flow
) : TimeMatesEntity()
+
+ override val requestKey: Key = Key
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt
index 00e1c44..36c13a7 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/requests/UploadFileRequest.kt
@@ -1,6 +1,7 @@
package io.timemates.sdk.files.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.files.types.FileType
@@ -9,10 +10,14 @@ import io.timemates.sdk.files.types.value.FileName
import kotlinx.coroutines.flow.Flow
public data class UploadFileRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val bytes: Flow,
val fileName: FileName,
val fileType: FileType,
-) : TimeMatesRequest() {
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
public data class Result(val fileId: FileId) : TimeMatesEntity()
+
+ override val requestKey: Key get() = Key
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt
index 986a99d..8cd32c8 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/files/types/FileType.kt
@@ -1,7 +1,5 @@
package io.timemates.sdk.files.types
-import io.timemates.sdk.common.types.TimeMatesEntity
-
public enum class FileType {
IMAGE,
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt
index fbe8f2b..c4279f6 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/CreateInviteRequest.kt
@@ -1,17 +1,21 @@
package io.timemates.sdk.timers.members.invites.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.common.types.value.Count
import io.timemates.sdk.timers.members.invites.types.value.InviteCode
-import io.timemates.sdk.timers.members.invites.types.value.InviteName
import io.timemates.sdk.timers.types.value.TimerId
public data class CreateInviteRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
val maxJoinersCount: Count,
-) : TimeMatesRequest() {
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+
public data class Result(public val inviteCode: InviteCode) : TimeMatesEntity()
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt
index 3a22851..bdef1d1 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/GetInvitesRequest.kt
@@ -3,13 +3,17 @@ package io.timemates.sdk.timers.members.invites.requests
import io.timemates.sdk.authorization.types.value.AccessHash
import io.timemates.sdk.common.pagination.Page
import io.timemates.sdk.common.pagination.PageToken
-import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.members.invites.types.Invite
import io.timemates.sdk.timers.types.value.TimerId
public data class GetInvitesRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
val pageToken: PageToken?,
-) : TimeMatesRequest>()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest>() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/JoinTimerByCodeRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/JoinTimerByCodeRequest.kt
new file mode 100644
index 0000000..ace017c
--- /dev/null
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/JoinTimerByCodeRequest.kt
@@ -0,0 +1,19 @@
+package io.timemates.sdk.timers.members.invites.requests
+
+import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.TimeMatesRequest
+import io.timemates.sdk.timers.members.invites.types.value.InviteCode
+import io.timemates.sdk.timers.types.Timer
+import io.timemates.sdk.timers.types.value.TimerId
+
+public data class JoinTimerByCodeRequest(
+ public val code: InviteCode,
+ public val accessHash: AccessHash,
+) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+
+ public data class Result(val timer: Timer) : TimeMatesEntity()
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt
index f26c260..df6152a 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/invites/requests/RemoveInviteRequest.kt
@@ -1,13 +1,18 @@
package io.timemates.sdk.timers.members.invites.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.members.invites.types.value.InviteCode
import io.timemates.sdk.timers.types.value.TimerId
public data class RemoveInviteRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
val inviteCode: InviteCode,
-) : TimeMatesRequest()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt
index c8e4d1b..bdaac90 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/GetMembersRequest.kt
@@ -3,13 +3,17 @@ package io.timemates.sdk.timers.members.requests
import io.timemates.sdk.authorization.types.value.AccessHash
import io.timemates.sdk.common.pagination.Page
import io.timemates.sdk.common.pagination.PageToken
-import io.timemates.sdk.common.types.TimeMatesEntity
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.value.TimerId
import io.timemates.sdk.users.profile.types.User
public data class GetMembersRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
val pageToken: PageToken?,
-) : TimeMatesRequest>()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest>() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt
index 8b8909a..a3005f8 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/members/requests/KickMemberRequest.kt
@@ -10,4 +10,8 @@ public data class KickMemberRequest(
val accessHash: AccessHash,
val timerId: TimerId,
val userId: UserId,
-) : TimeMatesRequest()
\ No newline at end of file
+) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt
index 759de46..be3e950 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/CreateTimerRequest.kt
@@ -1,6 +1,7 @@
package io.timemates.sdk.timers.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.TimerSettings
@@ -9,10 +10,14 @@ import io.timemates.sdk.timers.types.value.TimerId
import io.timemates.sdk.timers.types.value.TimerName
public data class CreateTimerRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val name: TimerName,
val description: TimerDescription,
val settings: TimerSettings,
-) : TimeMatesRequest() {
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+
public data class Result(val timerId: TimerId) : TimeMatesEntity()
}
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt
index b194b7b..4a72708 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/EditTimerRequest.kt
@@ -1,6 +1,7 @@
package io.timemates.sdk.timers.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.TimerSettings
@@ -9,9 +10,13 @@ import io.timemates.sdk.timers.types.value.TimerId
import io.timemates.sdk.timers.types.value.TimerName
public data class EditTimerRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
val name: TimerName? = null,
val description: TimerDescription? = null,
val settings: TimerSettings.Patch? = null,
-) : TimeMatesRequest()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt
index 2b6f6b8..d84b5c3 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetTimerRequest.kt
@@ -1,15 +1,20 @@
package io.timemates.sdk.timers.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.Timer
import io.timemates.sdk.timers.types.value.TimerId
public data class GetTimerRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
-) : TimeMatesRequest() {
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+
public data class Result(
val timer: Timer,
) : TimeMatesEntity()
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt
index f5f86e2..68a9f61 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/GetUserTimersRequest.kt
@@ -3,10 +3,15 @@ package io.timemates.sdk.timers.requests
import io.timemates.sdk.authorization.types.value.AccessHash
import io.timemates.sdk.common.pagination.Page
import io.timemates.sdk.common.pagination.PageToken
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.Timer
public data class GetUserTimersRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val pageToken: PageToken?,
-) : TimeMatesRequest>()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest>() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt
index 262a9e6..60f4b72 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/requests/RemoveTimerRequest.kt
@@ -8,4 +8,8 @@ import io.timemates.sdk.timers.types.value.TimerId
public data class RemoveTimerRequest(
val accessHash: AccessHash,
val timerId: TimerId,
-) : TimeMatesRequest()
\ No newline at end of file
+) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt
index 07e7533..07d97ad 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/ConfirmTimerRoundRequest.kt
@@ -1,10 +1,14 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
-import io.timemates.sdk.timers.types.value.TimerId
public data class ConfirmTimerRoundRequest(
- val accessHash: AccessHash,
-) : TimeMatesRequest()
\ No newline at end of file
+ override val accessHash: AccessHash,
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt
index 8f5fc45..096e887 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetTimerStateRequest.kt
@@ -1,7 +1,7 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
-import io.timemates.sdk.common.types.Empty
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesEntity
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.Timer
@@ -12,8 +12,12 @@ import kotlinx.coroutines.flow.Flow
* Gets timer session state.
*/
public data class GetTimerStateRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
-) : TimeMatesRequest() {
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+
public data class Result(val flow: Flow) : TimeMatesEntity()
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt
index b87f957..bbab4bf 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/GetUserCurrentSessionRequest.kt
@@ -1,6 +1,7 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.Timer
@@ -8,5 +9,10 @@ import io.timemates.sdk.timers.types.Timer
* Gets current timer session.
*/
public data class GetUserCurrentSessionRequest(
- val accessHash: AccessHash,
-) : TimeMatesRequest()
\ No newline at end of file
+ override val accessHash: AccessHash,
+) : AuthorizedTimeMatesRequest() {
+
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt
index 0727f89..c60c0de 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/JoinTimerSessionRequest.kt
@@ -1,11 +1,16 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.value.TimerId
public data class JoinTimerSessionRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
-) : TimeMatesRequest()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt
index b93e0cb..ff23c1b 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/LeaveTimerSessionRequest.kt
@@ -1,10 +1,14 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
-import io.timemates.sdk.timers.types.value.TimerId
public data class LeaveTimerSessionRequest(
- val accessHash: AccessHash,
-) : TimeMatesRequest()
\ No newline at end of file
+ override val accessHash: AccessHash,
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt
index bbb741b..8c48343 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/PingSessionRequest.kt
@@ -1,10 +1,14 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
-import io.timemates.sdk.timers.types.value.TimerId
public data class PingSessionRequest(
- val accessHash: AccessHash,
-) : TimeMatesRequest()
\ No newline at end of file
+ override val accessHash: AccessHash,
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt
index 3591187..d79d4f5 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StartTimerRequest.kt
@@ -1,6 +1,7 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.value.TimerId
@@ -9,6 +10,10 @@ import io.timemates.sdk.timers.types.value.TimerId
* Starts timer session if user didn't joined any yet.
*/
public data class StartTimerRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
-) : TimeMatesRequest()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt
index d8849d0..77af17c 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/timers/sessions/requests/StopTimerRequest.kt
@@ -1,6 +1,7 @@
package io.timemates.sdk.timers.sessions.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.timers.types.value.TimerId
@@ -9,6 +10,10 @@ import io.timemates.sdk.timers.types.value.TimerId
* Stops timer session.
*/
public data class StopTimerRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val timerId: TimerId,
-) : TimeMatesRequest()
\ No newline at end of file
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt
index 50e6cf5..3ed3b49 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/UserApi.kt
@@ -1,6 +1,5 @@
package io.timemates.sdk.users
-import io.timemates.sdk.authorization.types.value.AccessHash
import io.timemates.sdk.common.engine.TimeMatesRequestsEngine
import io.timemates.sdk.common.providers.AccessHashProvider
import io.timemates.sdk.users.profile.ProfileApi
@@ -10,7 +9,7 @@ import io.timemates.sdk.users.settings.UserSettingsApi
* Provides access to user-related functionality through the API.
*
* @param engine The TimeMatesRequestsEngine instance used for making API requests.
- * @param accessHash The access hash for authentication purposes.
+ * @param tokenProvider The provider of access hash for authentication purposes.
*/
public class UserApi(engine: TimeMatesRequestsEngine, tokenProvider: AccessHashProvider) {
/**
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt
index eda56f8..769edf7 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/ProfileApi.kt
@@ -9,7 +9,6 @@ import io.timemates.sdk.users.profile.requests.EditProfileRequest
import io.timemates.sdk.users.profile.requests.GetUsersRequest
import io.timemates.sdk.users.profile.types.Avatar
import io.timemates.sdk.users.profile.types.User
-import io.timemates.sdk.users.profile.types.value.EmailAddress
import io.timemates.sdk.users.profile.types.value.UserDescription
import io.timemates.sdk.users.profile.types.value.UserId
import io.timemates.sdk.users.profile.types.value.UserName
@@ -18,7 +17,7 @@ import io.timemates.sdk.users.profile.types.value.UserName
* Provides functionality for accessing and modifying user profiles through the API.
*
* @property engine The TimeMatesRequestsEngine instance used for making API requests.
- * @property accessHash The access hash for authentication purposes.
+ * @property tokenProvider The provider of access hash for authentication purposes.
*/
public class ProfileApi(
private val engine: TimeMatesRequestsEngine,
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt
index cbe97af..3bfe96b 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/EditProfileRequest.kt
@@ -1,16 +1,20 @@
package io.timemates.sdk.users.profile.requests
import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
-import io.timemates.sdk.files.types.value.FileId
import io.timemates.sdk.users.profile.types.Avatar
import io.timemates.sdk.users.profile.types.value.UserDescription
import io.timemates.sdk.users.profile.types.value.UserName
public data class EditProfileRequest(
- val accessHash: AccessHash,
+ override val accessHash: AccessHash,
val name: UserName?,
val description: UserDescription?,
- val avatar: Avatar?
-) : TimeMatesRequest()
\ No newline at end of file
+ val avatar: Avatar?,
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt
index 353e241..9c8af86 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/requests/GetUsersRequest.kt
@@ -8,5 +8,9 @@ import io.timemates.sdk.users.profile.types.value.UserId
public data class GetUsersRequest(
val users: List,
) : TimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
public data class Result(val users: List) : TimeMatesEntity()
+
+ override val requestKey: Key get() = Key
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt
index 671d622..1394f4f 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/Avatar.kt
@@ -15,16 +15,4 @@ public sealed interface Avatar {
}
}
}
-
- @JvmInline
- public value class FileId private constructor(public val string: String) : Avatar {
- public companion object : Factory() {
- override fun create(input: String): Result {
- return when {
- input.isBlank() -> Result.failure(CreationFailure.ofBlank())
- else -> Result.success(FileId(input))
- }
- }
- }
- }
}
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt
index 9f4b62f..70bbc93 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/profile/types/User.kt
@@ -12,13 +12,13 @@ import io.timemates.sdk.users.profile.types.value.UserName
* @property id The unique identifier of the user.
* @property name The name of the user.
* @property description The description of the user.
- * @property avatarFileId The unique identifier of the user's avatar file.
+ * @property avatar The user's avatar file.
* @property emailAddress The email address associated with the user (null if not available).
*/
public data class User(
val id: UserId,
val name: UserName,
- val description: UserDescription,
+ val description: UserDescription?,
val emailAddress: EmailAddress?,
val avatar: Avatar?,
) : TimeMatesEntity()
\ No newline at end of file
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt
index bb09758..5833f98 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/UserSettingsApi.kt
@@ -1,6 +1,5 @@
package io.timemates.sdk.users.settings
-import io.timemates.sdk.authorization.types.value.AccessHash
import io.timemates.sdk.common.annotations.UnimplementedApi
import io.timemates.sdk.common.engine.TimeMatesRequestsEngine
import io.timemates.sdk.common.providers.AccessHashProvider
diff --git a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt
index b697a52..c487b9b 100644
--- a/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt
+++ b/sdk/src/commonMain/kotlin/io/timemates/sdk/users/settings/requests/EditEmailRequest.kt
@@ -1,9 +1,25 @@
package io.timemates.sdk.users.settings.requests
+import io.timemates.sdk.authorization.types.value.AccessHash
+import io.timemates.sdk.common.annotations.ApiStatus
+import io.timemates.sdk.common.annotations.ExperimentalTimeMatesApi
+import io.timemates.sdk.common.types.AuthorizedTimeMatesRequest
import io.timemates.sdk.common.types.Empty
import io.timemates.sdk.common.types.TimeMatesRequest
import io.timemates.sdk.users.profile.types.value.EmailAddress
+/**
+ * This request is not implemented on server yet. Always throws
+ * [io.timemates.sdk.common.exceptions.UnsupportedException].
+ *
+ * TODO: remove notice once implemented
+ */
+@ExperimentalTimeMatesApi(status = ApiStatus.IN_PROGRESS)
public data class EditEmailRequest(
val newEmail: EmailAddress,
-) : TimeMatesRequest()
\ No newline at end of file
+ override val accessHash: AccessHash,
+) : AuthorizedTimeMatesRequest() {
+ public companion object Key : TimeMatesRequest.Key
+
+ override val requestKey: Key get() = Key
+}
\ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index bd3faff..57a9b30 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -3,6 +3,7 @@ enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
pluginManagement {
repositories {
gradlePluginPortal()
+ maven("https://maven.timemates.io")
mavenCentral()
google()
}
@@ -15,6 +16,7 @@ dependencyResolutionManagement {
mavenCentral()
maven("https://jitpack.io")
maven("https://maven.y9vad9.com")
+ maven("https://maven.timemates.io")
}
}
@@ -23,5 +25,4 @@ rootProject.name = "timemates-sdk"
includeBuild("build-logic/publish-library-plugin")
include(":sdk")
-include(":grpc-engine")
-include(":grpc-engine:android")
+include(":rsocket-engine")