From dc35941daf6ca50c0b465560a9f109d4c3e8783c Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 12:37:41 -0500 Subject: [PATCH 01/56] Kotlin: Upgrade Gradle --- kotlin/deploy.gradle | 2 -- kotlin/gradle/wrapper/gradle-wrapper.jar | Bin 59536 -> 59821 bytes .../gradle/wrapper/gradle-wrapper.properties | 4 ++-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/kotlin/deploy.gradle b/kotlin/deploy.gradle index 8a0d1a277..0744a0695 100644 --- a/kotlin/deploy.gradle +++ b/kotlin/deploy.gradle @@ -48,12 +48,10 @@ nexusPublishing { } task sourcesJar(type: Jar) { - classifier = "sources" from sourceSets.main.allSource } task javadocJar(type: Jar, dependsOn: javadoc) { - classifier = "javadoc" from javadoc.destinationDir } diff --git a/kotlin/gradle/wrapper/gradle-wrapper.jar b/kotlin/gradle/wrapper/gradle-wrapper.jar index 7454180f2ae8848c63b8b4dea2cb829da983f2fa..41d9927a4d4fb3f96a785543079b8df6723c946b 100644 GIT binary patch delta 8958 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 diff --git a/kotlin/gradle/wrapper/gradle-wrapper.properties b/kotlin/gradle/wrapper/gradle-wrapper.properties index 856da69bc..d951fac2b 100644 --- a/kotlin/gradle/wrapper/gradle-wrapper.properties +++ b/kotlin/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists \ No newline at end of file +zipStorePath=wrapper/dists From f3fedcbc4ed05154644e065a45efb2d614789300 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 12:59:56 -0500 Subject: [PATCH 02/56] kotlin: Add kotlinx and add dependency on kotlin.jvm 2.1.0 --- kotlin/build.gradle | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/kotlin/build.gradle b/kotlin/build.gradle index 9ae49c112..351fb7123 100644 --- a/kotlin/build.gradle +++ b/kotlin/build.gradle @@ -1,13 +1,5 @@ -group GROUP -version VERSION_NAME - -wrapper { - gradleVersion = '8.7' - distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" -} - buildscript { - ext.kotlin_version = '1.9.23' + ext.kotlin_version = '2.1.0' ext.spotless_version = "6.25.0" repositories { @@ -21,6 +13,21 @@ buildscript { } } +plugins { + id 'org.jetbrains.kotlin.jvm' version '2.1.0' + id 'org.jetbrains.kotlin.plugin.serialization' version '2.1.10' +} + +group GROUP +version VERSION_NAME + + +wrapper { + gradleVersion = '8.7' + distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" +} + + apply plugin: 'kotlin' apply plugin: 'com.diffplug.spotless' @@ -40,6 +47,8 @@ test { } dependencies { + implementation 'org.jetbrains.kotlinx:kotlinx-datetime:0.6.2' + implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2" From c4c4dd5db98667fa9022213574937c46b83baf05 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 13:00:15 -0500 Subject: [PATCH 03/56] kotlin: Add `MaybeUnset` and `SvixHttpClient` classes --- kotlin/lib/src/main/kotlin/MaybeUnset.kt | 44 ++++++++++ kotlin/lib/src/main/kotlin/SvixHttpClient.kt | 89 ++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 kotlin/lib/src/main/kotlin/MaybeUnset.kt create mode 100644 kotlin/lib/src/main/kotlin/SvixHttpClient.kt diff --git a/kotlin/lib/src/main/kotlin/MaybeUnset.kt b/kotlin/lib/src/main/kotlin/MaybeUnset.kt new file mode 100644 index 000000000..7876f36b1 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/MaybeUnset.kt @@ -0,0 +1,44 @@ +package com.svix.kotlin + +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +@Serializable(with = MaybeUnsetSerializer::class) +sealed class MaybeUnset { + data object Null : MaybeUnset() + + data object Undefined : MaybeUnset() + + data class Present(val value: T) : MaybeUnset() +} + +class MaybeUnsetSerializer(private val dataSerializer: KSerializer) : + KSerializer> { + override val descriptor: SerialDescriptor = + SerialDescriptor("com.svix.kotlin.MaybeUnsetSerializer", dataSerializer.descriptor) + + @OptIn(ExperimentalSerializationApi::class) + override fun serialize(encoder: Encoder, value: MaybeUnset) { + when (value) { + is MaybeUnset.Undefined -> + throw SerializationException("MaybeUnset.Undefined should not be serialized") + is MaybeUnset.Null -> encoder.encodeNull() + is MaybeUnset.Present -> encoder.encodeSerializableValue(dataSerializer, value.value) + else -> throw SerializationException("Unreachable") + } + } + + override fun deserialize(decoder: Decoder): MaybeUnset { + try { + val value = decoder.decodeSerializableValue(dataSerializer) + return MaybeUnset.Present(value) + } catch (e: SerializationException) { + return MaybeUnset.Null + } + } +} diff --git a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt new file mode 100644 index 000000000..afaec692a --- /dev/null +++ b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt @@ -0,0 +1,89 @@ +package com.svix.kotlin + +import com.svix.kotlin.exceptions.ApiException +import kotlinx.serialization.json.Json +import okhttp3.* +import okhttp3.RequestBody.Companion.toRequestBody + +open class SvixHttpClient +constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map) { + val client: OkHttpClient = OkHttpClient() + + fun newUrlBuilder(): HttpUrl.Builder { + return HttpUrl.Builder().scheme(baseUrl.scheme).host(baseUrl.host).port(baseUrl.port) + } + + internal inline fun executeRequest( + method: String, + url: HttpUrl, + headers: Headers? = null, + reqBody: Req? = null, + ): Res { + var reqBuilder = Request.Builder().url(url) + + if (reqBody != null) { + val jsonBody = Json.encodeToString(reqBody) + reqBuilder = reqBuilder.method(method, jsonBody.toRequestBody()) + } + + for ((k, v) in defaultHeaders) { + reqBuilder = reqBuilder.addHeader(k, v) + } + if (headers != null) { + for ((k, v) in headers) { + reqBuilder = reqBuilder.addHeader(k, v) + } + } + + val request = reqBuilder.build() + val debug: String = System.getenv("DEBUG") ?: "no" + if (debug == "yes") { + dbgRequest(request) + } + val res = client.newCall(request).execute() + + // if body is null panic + if (res.body == null) { + throw ApiException("Body is null", res.code) + } + val bodyString = res.body!!.string() + if (debug == "yes") { + dbgResponse(res, bodyString) + } + if (res.code == 204) { + return Json.decodeFromString("true") + } + if (res.code in 200..299) { + return Json.decodeFromString(bodyString) + } + throw ApiException("None 200 status code", res.code, bodyString) + } +} + +fun dbgRequest(request: Request) { + println("____ start req ____") + println("Url: ${request.url}") + println("Method ${request.method} path: ${request.url.encodedPath}") + for ((k, v) in request.headers) { + println("$k: $v}") + } + println() + if (request.body != null) { + println(request.body.toString()) + } + println("_____ end req _____") +} + +fun dbgResponse(response: Response, bodyString: String?) { + println("____ start res ____") + println("Status: ${response.code}") + for ((k, v) in response.headers) { + println("$k: $v") + } + println() + + if (response.body != null) { + println(bodyString) + } + println("_____ end res _____") +} From 240d77128903cfaf8266ce400697d015db9c8727 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 13:54:10 -0500 Subject: [PATCH 04/56] kotlin: Fix SvixHttpClient --- kotlin/lib/src/main/kotlin/SvixHttpClient.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt index afaec692a..0f372cf6e 100644 --- a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt +++ b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt @@ -24,6 +24,8 @@ constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map Date: Tue, 11 Feb 2025 13:54:36 -0500 Subject: [PATCH 05/56] kotlin: Refactor ApiException --- .../main/kotlin/exceptions/ApiException.kt | 39 +------------------ 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/exceptions/ApiException.kt b/kotlin/lib/src/main/kotlin/exceptions/ApiException.kt index f196badde..3908ad3f2 100644 --- a/kotlin/lib/src/main/kotlin/exceptions/ApiException.kt +++ b/kotlin/lib/src/main/kotlin/exceptions/ApiException.kt @@ -1,39 +1,4 @@ package com.svix.kotlin.exceptions -import com.svix.kotlin.internal.infrastructure.ClientError -import com.svix.kotlin.internal.infrastructure.ClientException -import com.svix.kotlin.internal.infrastructure.Response -import com.svix.kotlin.internal.infrastructure.ServerError -import com.svix.kotlin.internal.infrastructure.ServerException - -class ApiException -internal constructor(message: String? = null, val statusCode: Int = -1, val body: String? = null) : - RuntimeException(message) { - companion object { - private fun extractBody(response: Response?): String? { - return when (response) { - is ClientError<*> -> { - val body = response.body - return if (body is String) body else null - } - is ServerError<*> -> { - val body = response.body - return if (body is String) body else null - } - else -> null - } - } - - internal fun wrap(e: Exception): Exception { - return when (e) { - is ServerException -> { - ApiException(e.message, e.statusCode, extractBody(e.response)) - } - is ClientException -> { - ApiException(e.message, e.statusCode, extractBody(e.response)) - } - else -> e - } - } - } -} +class ApiException(message: String? = null, val statusCode: Int = -1, val body: String? = null) : + RuntimeException(message) {} From 439dbe281f7d6d0df8e771e1d5317e7b5a0bb9b4 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 15:56:58 -0500 Subject: [PATCH 06/56] kotlin: Refactor high-level client with newly generated code --- kotlin/lib/src/main/kotlin/Application.kt | 122 +++-- kotlin/lib/src/main/kotlin/Authentication.kt | 87 ++-- kotlin/lib/src/main/kotlin/BackgroundTask.kt | 68 +-- kotlin/lib/src/main/kotlin/Endpoint.kt | 271 +++++------ kotlin/lib/src/main/kotlin/EventType.kt | 150 +++--- kotlin/lib/src/main/kotlin/Integration.kt | 112 ++--- kotlin/lib/src/main/kotlin/Message.kt | 187 +++----- kotlin/lib/src/main/kotlin/MessageAttempt.kt | 435 +++++------------- .../main/kotlin/OperationalWebhookEndpoint.kt | 162 +++---- kotlin/lib/src/main/kotlin/Statistics.kt | 39 +- 10 files changed, 644 insertions(+), 989 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Application.kt b/kotlin/lib/src/main/kotlin/Application.kt index 2d938a198..50e724a0e 100644 --- a/kotlin/lib/src/main/kotlin/Application.kt +++ b/kotlin/lib/src/main/kotlin/Application.kt @@ -1,106 +1,104 @@ -// this file is @generated (with minor manual changes) +// this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.ApplicationApi import com.svix.kotlin.models.ApplicationIn import com.svix.kotlin.models.ApplicationOut import com.svix.kotlin.models.ApplicationPatch import com.svix.kotlin.models.ListResponseApplicationOut import com.svix.kotlin.models.Ordering +import okhttp3.Headers +import okhttp3.HttpUrl -class ApplicationListOptions { - var limit: Int? = null - var iterator: String? = null - var order: Ordering? = null +data class ApplicationListOptions( + val limit: ULong? = null, + val iterator: String? = null, + val order: Ordering? = null, +) - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } +data class ApplicationCreateOptions(val idempotencyKey: String? = null) - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } - - /** The sorting order of the returned items */ - fun order(order: Ordering) = apply { this.order = order } -} - -class Application internal constructor(token: String, options: SvixOptions) { - private val api = ApplicationApi(options.serverUrl) - - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +class Application(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** List of all the organization's applications. */ suspend fun list( options: ApplicationListOptions = ApplicationListOptions() ): ListResponseApplicationOut { - try { - return api.v1ApplicationList(options.limit, options.iterator, options.order) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/app") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.order?.let { url = url.addQueryParameter("order", it.toString()) } + return this.executeRequest("GET", url.build()) } /** Create a new application. */ suspend fun create( applicationIn: ApplicationIn, - options: PostOptions = PostOptions(), + options: ApplicationCreateOptions = ApplicationCreateOptions(), ): ApplicationOut { - try { - return api.v1ApplicationCreate(applicationIn, null, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = applicationIn, + ) } + /** Get or create an application. */ suspend fun getOrCreate( applicationIn: ApplicationIn, - options: PostOptions = PostOptions(), + options: ApplicationCreateOptions = ApplicationCreateOptions(), ): ApplicationOut { - try { - return api.v1ApplicationCreate(applicationIn, true, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/app") + .addQueryParameter("get_if_exists", "true") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = applicationIn, + ) } /** Get an application. */ suspend fun get(appId: String): ApplicationOut { - try { - return api.v1ApplicationGet(appId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") + return this.executeRequest("GET", url.build()) } /** Update an application. */ suspend fun update(appId: String, applicationIn: ApplicationIn): ApplicationOut { - try { - return api.v1ApplicationUpdate(appId, applicationIn) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") + + return this.executeRequest( + "PUT", + url.build(), + reqBody = applicationIn, + ) } /** Delete an application. */ suspend fun delete(appId: String) { - try { - api.v1ApplicationDelete(appId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") + this.executeRequest("DELETE", url.build()) } /** Partially update an application. */ suspend fun patch(appId: String, applicationPatch: ApplicationPatch): ApplicationOut { - try { - return api.v1ApplicationPatch(appId, applicationPatch) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") + + return this.executeRequest( + "PATCH", + url.build(), + reqBody = applicationPatch, + ) } } diff --git a/kotlin/lib/src/main/kotlin/Authentication.kt b/kotlin/lib/src/main/kotlin/Authentication.kt index 714a418a5..816fad9ea 100644 --- a/kotlin/lib/src/main/kotlin/Authentication.kt +++ b/kotlin/lib/src/main/kotlin/Authentication.kt @@ -1,22 +1,23 @@ // this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.AuthenticationApi import com.svix.kotlin.models.AppPortalAccessIn import com.svix.kotlin.models.AppPortalAccessOut import com.svix.kotlin.models.ApplicationTokenExpireIn import com.svix.kotlin.models.DashboardAccessOut +import okhttp3.Headers +import okhttp3.HttpUrl -class Authentication internal constructor(token: String, options: SvixOptions) { - private val api = AuthenticationApi(options.serverUrl) +data class AuthenticationAppPortalAccessOptions(val idempotencyKey: String? = null) - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +data class AuthenticationExpireAllOptions(val idempotencyKey: String? = null) + +data class AuthenticationDashboardAccessOptions(val idempotencyKey: String? = null) + +data class AuthenticationLogoutOptions(val idempotencyKey: String? = null) + +class Authentication(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** * Use this function to get magic links (and authentication codes) for connecting your users to @@ -25,30 +26,36 @@ class Authentication internal constructor(token: String, options: SvixOptions) { suspend fun appPortalAccess( appId: String, appPortalAccessIn: AppPortalAccessIn, - options: PostOptions = PostOptions(), + options: AuthenticationAppPortalAccessOptions = AuthenticationAppPortalAccessOptions(), ): AppPortalAccessOut { - try { - return api.v1AuthenticationAppPortalAccess( - appId, - appPortalAccessIn, - options.idempotencyKey, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/auth/app-portal-access/$appId") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = appPortalAccessIn, + ) } /** Expire all of the tokens associated with a specific application. */ suspend fun expireAll( appId: String, applicationTokenExpireIn: ApplicationTokenExpireIn, - options: PostOptions = PostOptions(), + options: AuthenticationExpireAllOptions = AuthenticationExpireAllOptions(), ) { - try { - api.v1AuthenticationExpireAll(appId, applicationTokenExpireIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/auth/app/$appId/expire-all") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = applicationTokenExpireIn, + ) } /** @@ -59,16 +66,19 @@ class Authentication internal constructor(token: String, options: SvixOptions) { * * @deprecated */ - @Deprecated(message = "Use appPortalAccess instead.") + @Deprecated("") suspend fun dashboardAccess( appId: String, - options: PostOptions = PostOptions(), + options: AuthenticationDashboardAccessOptions = AuthenticationDashboardAccessOptions(), ): DashboardAccessOut { - try { - return api.v1AuthenticationDashboardAccess(appId, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/auth/dashboard-access/$appId") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + ) } /** @@ -76,11 +86,10 @@ class Authentication internal constructor(token: String, options: SvixOptions) { * * Trying to log out other tokens will fail. */ - suspend fun logout(options: PostOptions = PostOptions()) { - try { - api.v1AuthenticationLogout(options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + suspend fun logout(options: AuthenticationLogoutOptions = AuthenticationLogoutOptions()) { + val url = this.newUrlBuilder().encodedPath("/api/v1/auth/logout") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + this.executeRequest("POST", url.build(), headers = headers.build()) } } diff --git a/kotlin/lib/src/main/kotlin/BackgroundTask.kt b/kotlin/lib/src/main/kotlin/BackgroundTask.kt index f6e37180e..63fe44e47 100644 --- a/kotlin/lib/src/main/kotlin/BackgroundTask.kt +++ b/kotlin/lib/src/main/kotlin/BackgroundTask.kt @@ -1,70 +1,40 @@ // this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.BackgroundTasksApi import com.svix.kotlin.models.BackgroundTaskOut import com.svix.kotlin.models.BackgroundTaskStatus import com.svix.kotlin.models.BackgroundTaskType import com.svix.kotlin.models.ListResponseBackgroundTaskOut import com.svix.kotlin.models.Ordering +import okhttp3.HttpUrl -class BackgroundTaskListOptions { - var status: BackgroundTaskStatus? = null - var task: BackgroundTaskType? = null - var limit: Int? = null - var iterator: String? = null - var order: Ordering? = null +data class BackgroundTaskListOptions( + val status: BackgroundTaskStatus? = null, + val task: BackgroundTaskType? = null, + val limit: ULong? = null, + val iterator: String? = null, + val order: Ordering? = null, +) - /** Filter the response based on the status. */ - fun status(status: BackgroundTaskStatus) = apply { this.status = status } - - /** Filter the response based on the type. */ - fun task(task: BackgroundTaskType) = apply { this.task = task } - - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } - - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } - - /** The sorting order of the returned items */ - fun order(order: Ordering) = apply { this.order = order } -} - -class BackgroundTask internal constructor(token: String, options: SvixOptions) { - private val api = BackgroundTasksApi(options.serverUrl) - - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +class BackgroundTask(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** List background tasks executed in the past 90 days. */ suspend fun list( options: BackgroundTaskListOptions = BackgroundTaskListOptions() ): ListResponseBackgroundTaskOut { - try { - return api.v1BackgroundTaskList( - options.status, - options.task, - options.limit, - options.iterator, - options.order, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/background-task") + options.status?.let { url = url.addQueryParameter("status", it.toString()) } + options.task?.let { url = url.addQueryParameter("task", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.order?.let { url = url.addQueryParameter("order", it.toString()) } + return this.executeRequest("GET", url.build()) } /** Get a background task by ID. */ suspend fun get(taskId: String): BackgroundTaskOut { - try { - return api.v1BackgroundTaskGet(taskId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/background-task/$taskId") + return this.executeRequest("GET", url.build()) } } diff --git a/kotlin/lib/src/main/kotlin/Endpoint.kt b/kotlin/lib/src/main/kotlin/Endpoint.kt index 39bca9c36..dbab1a844 100644 --- a/kotlin/lib/src/main/kotlin/Endpoint.kt +++ b/kotlin/lib/src/main/kotlin/Endpoint.kt @@ -1,8 +1,6 @@ // this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.EndpointApi import com.svix.kotlin.models.EndpointHeadersIn import com.svix.kotlin.models.EndpointHeadersOut import com.svix.kotlin.models.EndpointHeadersPatchIn @@ -23,54 +21,41 @@ import com.svix.kotlin.models.RecoverIn import com.svix.kotlin.models.RecoverOut import com.svix.kotlin.models.ReplayIn import com.svix.kotlin.models.ReplayOut -import java.time.OffsetDateTime +import kotlinx.datetime.Instant +import okhttp3.Headers +import okhttp3.HttpUrl -class EndpointListOptions { - var limit: Int? = null - var iterator: String? = null - var order: Ordering? = null +data class EndpointListOptions( + val limit: ULong? = null, + val iterator: String? = null, + val order: Ordering? = null, +) - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } +data class EndpointCreateOptions(val idempotencyKey: String? = null) - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } +data class EndpointRecoverOptions(val idempotencyKey: String? = null) - /** The sorting order of the returned items */ - fun order(order: Ordering) = apply { this.order = order } -} - -class EndpointGetStatsOptions { - var since: OffsetDateTime? = null - var until: OffsetDateTime? = null +data class EndpointReplayMissingOptions(val idempotencyKey: String? = null) - /** Filter the range to data starting from this date. */ - fun since(since: OffsetDateTime) = apply { this.since = since } +data class EndpointRotateSecretOptions(val idempotencyKey: String? = null) - /** Filter the range to data ending by this date. */ - fun until(until: OffsetDateTime) = apply { this.until = until } -} +data class EndpointSendExampleOptions(val idempotencyKey: String? = null) -class Endpoint internal constructor(token: String, options: SvixOptions) { - private val api = EndpointApi(options.serverUrl) +data class EndpointGetStatsOptions(val since: Instant? = null, val until: Instant? = null) - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** List the application's endpoints. */ suspend fun list( appId: String, options: EndpointListOptions = EndpointListOptions(), ): ListResponseEndpointOut { - try { - return api.v1EndpointList(appId, options.limit, options.iterator, options.order) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.order?.let { url = url.addQueryParameter("order", it.toString()) } + return this.executeRequest("GET", url.build()) } /** @@ -81,22 +66,24 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { suspend fun create( appId: String, endpointIn: EndpointIn, - options: PostOptions = PostOptions(), + options: EndpointCreateOptions = EndpointCreateOptions(), ): EndpointOut { - try { - return api.v1EndpointCreate(appId, endpointIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = endpointIn, + ) } /** Get an endpoint. */ - suspend fun get(endpointId: String, appId: String): EndpointOut { - try { - return api.v1EndpointGet(appId, endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + suspend fun get(appId: String, endpointId: String): EndpointOut { + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + return this.executeRequest("GET", url.build()) } /** Update an endpoint. */ @@ -105,20 +92,19 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { endpointId: String, endpointUpdate: EndpointUpdate, ): EndpointOut { - try { - return api.v1EndpointUpdate(appId, endpointId, endpointUpdate) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + + return this.executeRequest( + "PUT", + url.build(), + reqBody = endpointUpdate, + ) } /** Delete an endpoint. */ suspend fun delete(appId: String, endpointId: String) { - try { - api.v1EndpointDelete(appId, endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + this.executeRequest("DELETE", url.build()) } /** Partially update an endpoint. */ @@ -127,20 +113,20 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { endpointId: String, endpointPatch: EndpointPatch, ): EndpointOut { - try { - return api.v1EndpointPatch(appId, endpointId, endpointPatch) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + + return this.executeRequest( + "PATCH", + url.build(), + reqBody = endpointPatch, + ) } /** Get the additional headers to be sent with the webhook. */ suspend fun getHeaders(appId: String, endpointId: String): EndpointHeadersOut { - try { - return api.v1EndpointGetHeaders(appId, endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") + return this.executeRequest("GET", url.build()) } /** Set the additional headers to be sent with the webhook. */ @@ -149,11 +135,14 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { endpointId: String, endpointHeadersIn: EndpointHeadersIn, ) { - try { - api.v1EndpointUpdateHeaders(appId, endpointId, endpointHeadersIn) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") + + this.executeRequest( + "PUT", + url.build(), + reqBody = endpointHeadersIn, + ) } /** Partially set the additional headers to be sent with the webhook. */ @@ -162,11 +151,14 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { endpointId: String, endpointHeadersPatchIn: EndpointHeadersPatchIn, ) { - try { - api.v1EndpointPatchHeaders(appId, endpointId, endpointHeadersPatchIn) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") + + this.executeRequest( + "PATCH", + url.build(), + reqBody = endpointHeadersPatchIn, + ) } /** @@ -178,13 +170,19 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { appId: String, endpointId: String, recoverIn: RecoverIn, - options: PostOptions = PostOptions(), + options: EndpointRecoverOptions = EndpointRecoverOptions(), ): RecoverOut { - try { - return api.v1EndpointRecover(appId, endpointId, recoverIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/recover") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = recoverIn, + ) } /** @@ -197,13 +195,20 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { appId: String, endpointId: String, replayIn: ReplayIn, - options: PostOptions = PostOptions(), + options: EndpointReplayMissingOptions = EndpointReplayMissingOptions(), ): ReplayOut { - try { - return api.v1EndpointReplayMissing(appId, endpointId, replayIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/replay-missing") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = replayIn, + ) } /** @@ -213,11 +218,8 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { * [the consuming webhooks docs](https://docs.svix.com/consuming-webhooks/). */ suspend fun getSecret(appId: String, endpointId: String): EndpointSecretOut { - try { - return api.v1EndpointGetSecret(appId, endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/secret") + return this.executeRequest("GET", url.build()) } /** @@ -229,18 +231,20 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { appId: String, endpointId: String, endpointSecretRotateIn: EndpointSecretRotateIn, - options: PostOptions = PostOptions(), + options: EndpointRotateSecretOptions = EndpointRotateSecretOptions(), ) { - try { - api.v1EndpointRotateSecret( - appId, - endpointId, - endpointSecretRotateIn, - options.idempotencyKey, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/secret/rotate") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = endpointSecretRotateIn, + ) } /** Send an example message for an event. */ @@ -248,18 +252,19 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { appId: String, endpointId: String, eventExampleIn: EventExampleIn, - options: PostOptions = PostOptions(), + options: EndpointSendExampleOptions = EndpointSendExampleOptions(), ): MessageOut { - try { - return api.v1EndpointSendExample( - appId, - endpointId, - eventExampleIn, - options.idempotencyKey, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/send-example") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = eventExampleIn, + ) } /** Get basic statistics for the endpoint. */ @@ -268,20 +273,18 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { endpointId: String, options: EndpointGetStatsOptions = EndpointGetStatsOptions(), ): EndpointStats { - try { - return api.v1EndpointGetStats(appId, endpointId, options.since, options.until) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/stats") + options.since?.let { url = url.addQueryParameter("since", it.toString()) } + options.until?.let { url = url.addQueryParameter("until", it.toString()) } + return this.executeRequest("GET", url.build()) } /** Get the transformation code associated with this endpoint. */ suspend fun transformationGet(appId: String, endpointId: String): EndpointTransformationOut { - try { - return api.v1EndpointTransformationGet(appId, endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/transformation") + return this.executeRequest("GET", url.build()) } /** Set or unset the transformation code associated with this endpoint. */ @@ -290,10 +293,14 @@ class Endpoint internal constructor(token: String, options: SvixOptions) { endpointId: String, endpointTransformationIn: EndpointTransformationIn, ) { - try { - api.v1EndpointTransformationPartialUpdate(appId, endpointId, endpointTransformationIn) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/transformation") + + this.executeRequest( + "PATCH", + url.build(), + reqBody = endpointTransformationIn, + ) } } diff --git a/kotlin/lib/src/main/kotlin/EventType.kt b/kotlin/lib/src/main/kotlin/EventType.kt index 9ca3e764a..c8d275d7e 100644 --- a/kotlin/lib/src/main/kotlin/EventType.kt +++ b/kotlin/lib/src/main/kotlin/EventType.kt @@ -1,8 +1,6 @@ -// this file is @generated (with minor manual changes) +// this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.EventTypeApi import com.svix.kotlin.models.EventTypeImportOpenApiIn import com.svix.kotlin.models.EventTypeImportOpenApiOut import com.svix.kotlin.models.EventTypeIn @@ -11,68 +9,39 @@ import com.svix.kotlin.models.EventTypePatch import com.svix.kotlin.models.EventTypeUpdate import com.svix.kotlin.models.ListResponseEventTypeOut import com.svix.kotlin.models.Ordering +import okhttp3.Headers +import okhttp3.HttpUrl -class EventTypeListOptions { - var limit: Int? = null - var iterator: String? = null - var order: Ordering? = null - var includeArchived: Boolean? = null - var withContent: Boolean? = null +data class EventTypeListOptions( + val limit: ULong? = null, + val iterator: String? = null, + val order: Ordering? = null, + val includeArchived: Boolean? = null, + val withContent: Boolean? = null, +) - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } +data class EventTypeCreateOptions(val idempotencyKey: String? = null) - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } +data class EventTypeImportOpenapiOptions(val idempotencyKey: String? = null) - /** The sorting order of the returned items */ - fun order(order: Ordering) = apply { this.order = order } +data class EventTypeDeleteOptions(val expunge: Boolean? = null) - /** When `true` archived (deleted but not expunged) items are included in the response. */ - fun includeArchived(includeArchived: Boolean) = apply { this.includeArchived = includeArchived } - - @Deprecated("Use the new includeArchived() method") - fun includeAchived(includeArchived: Boolean) = apply { this.includeArchived = includeArchived } - - /** When `true` the full item (including the schema) is included in the response. */ - fun withContent(withContent: Boolean) = apply { this.withContent = withContent } -} - -class EventTypeDeleteOptions { - var expunge: Boolean? = null - - /** - * By default event types are archived when "deleted". Passing this to `true` deletes them - * entirely. - */ - fun expunge(expunge: Boolean) = apply { this.expunge = expunge } -} - -class EventType internal constructor(token: String, options: SvixOptions) { - private val api = EventTypeApi(options.serverUrl) - - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** Return the list of event types. */ suspend fun list( options: EventTypeListOptions = EventTypeListOptions() ): ListResponseEventTypeOut { - try { - return api.v1EventTypeList( - options.limit, - options.iterator, - options.order, - options.includeArchived, - options.withContent, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) + var url = this.newUrlBuilder().encodedPath("/api/v1/event-type") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.order?.let { url = url.addQueryParameter("order", it.toString()) } + options.includeArchived?.let { + url = url.addQueryParameter("include_archived", it.toString()) } + options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + return this.executeRequest("GET", url.build()) } /** @@ -84,13 +53,18 @@ class EventType internal constructor(token: String, options: SvixOptions) { */ suspend fun create( eventTypeIn: EventTypeIn, - options: PostOptions = PostOptions(), + options: EventTypeCreateOptions = EventTypeCreateOptions(), ): EventTypeOut { - try { - return api.v1EventTypeCreate(eventTypeIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/event-type") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = eventTypeIn, + ) } /** @@ -102,31 +76,35 @@ class EventType internal constructor(token: String, options: SvixOptions) { */ suspend fun importOpenapi( eventTypeImportOpenApiIn: EventTypeImportOpenApiIn, - options: PostOptions = PostOptions(), + options: EventTypeImportOpenapiOptions = EventTypeImportOpenapiOptions(), ): EventTypeImportOpenApiOut { - try { - return api.v1EventTypeImportOpenapi(eventTypeImportOpenApiIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/import/openapi") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = eventTypeImportOpenApiIn, + ) } /** Get an event type. */ suspend fun get(eventTypeName: String): EventTypeOut { - try { - return api.v1EventTypeGet(eventTypeName) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + return this.executeRequest("GET", url.build()) } /** Update an event type. */ suspend fun update(eventTypeName: String, eventTypeUpdate: EventTypeUpdate): EventTypeOut { - try { - return api.v1EventTypeUpdate(eventTypeName, eventTypeUpdate) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + + return this.executeRequest( + "PUT", + url.build(), + reqBody = eventTypeUpdate, + ) } /** @@ -141,19 +119,19 @@ class EventType internal constructor(token: String, options: SvixOptions) { eventTypeName: String, options: EventTypeDeleteOptions = EventTypeDeleteOptions(), ) { - try { - api.v1EventTypeDelete(eventTypeName, options.expunge) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + options.expunge?.let { url = url.addQueryParameter("expunge", it.toString()) } + this.executeRequest("DELETE", url.build()) } /** Partially update an event type. */ suspend fun patch(eventTypeName: String, eventTypePatch: EventTypePatch): EventTypeOut { - try { - return api.v1EventTypePatch(eventTypeName, eventTypePatch) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + + return this.executeRequest( + "PATCH", + url.build(), + reqBody = eventTypePatch, + ) } } diff --git a/kotlin/lib/src/main/kotlin/Integration.kt b/kotlin/lib/src/main/kotlin/Integration.kt index f0e8cf0c5..503930c37 100644 --- a/kotlin/lib/src/main/kotlin/Integration.kt +++ b/kotlin/lib/src/main/kotlin/Integration.kt @@ -1,72 +1,62 @@ // this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.IntegrationApi import com.svix.kotlin.models.IntegrationIn import com.svix.kotlin.models.IntegrationKeyOut import com.svix.kotlin.models.IntegrationOut import com.svix.kotlin.models.IntegrationUpdate import com.svix.kotlin.models.ListResponseIntegrationOut import com.svix.kotlin.models.Ordering +import okhttp3.Headers +import okhttp3.HttpUrl -class IntegrationListOptions { - var limit: Int? = null - var iterator: String? = null - var order: Ordering? = null +data class IntegrationListOptions( + val limit: ULong? = null, + val iterator: String? = null, + val order: Ordering? = null, +) - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } +data class IntegrationCreateOptions(val idempotencyKey: String? = null) - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } +data class IntegrationRotateKeyOptions(val idempotencyKey: String? = null) - /** The sorting order of the returned items */ - fun order(order: Ordering) = apply { this.order = order } -} - -class Integration internal constructor(token: String, options: SvixOptions) { - private val api = IntegrationApi(options.serverUrl) - - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** List the application's integrations. */ suspend fun list( appId: String, options: IntegrationListOptions = IntegrationListOptions(), ): ListResponseIntegrationOut { - try { - return api.v1IntegrationList(appId, options.limit, options.iterator, options.order) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.order?.let { url = url.addQueryParameter("order", it.toString()) } + return this.executeRequest("GET", url.build()) } /** Create an integration. */ suspend fun create( appId: String, integrationIn: IntegrationIn, - options: PostOptions = PostOptions(), + options: IntegrationCreateOptions = IntegrationCreateOptions(), ): IntegrationOut { - try { - return api.v1IntegrationCreate(appId, integrationIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = integrationIn, + ) } /** Get an integration. */ suspend fun get(appId: String, integId: String): IntegrationOut { - try { - return api.v1IntegrationGet(appId, integId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") + return this.executeRequest("GET", url.build()) } /** Update an integration. */ @@ -75,20 +65,19 @@ class Integration internal constructor(token: String, options: SvixOptions) { integId: String, integrationUpdate: IntegrationUpdate, ): IntegrationOut { - try { - return api.v1IntegrationUpdate(appId, integId, integrationUpdate) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") + + return this.executeRequest( + "PUT", + url.build(), + reqBody = integrationUpdate, + ) } /** Delete an integration. */ suspend fun delete(appId: String, integId: String) { - try { - api.v1IntegrationDelete(appId, integId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") + this.executeRequest("DELETE", url.build()) } /** @@ -96,25 +85,26 @@ class Integration internal constructor(token: String, options: SvixOptions) { * * @deprecated */ - @Deprecated(message = "This endpoint is deprecated.") + @Deprecated("") suspend fun getKey(appId: String, integId: String): IntegrationKeyOut { - try { - return api.v1IntegrationGetKey(appId, integId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId/key") + return this.executeRequest("GET", url.build()) } /** Rotate the integration's key. The previous key will be immediately revoked. */ suspend fun rotateKey( appId: String, integId: String, - options: PostOptions = PostOptions(), + options: IntegrationRotateKeyOptions = IntegrationRotateKeyOptions(), ): IntegrationKeyOut { - try { - return api.v1IntegrationRotateKey(appId, integId, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId/key/rotate") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + ) } } diff --git a/kotlin/lib/src/main/kotlin/Message.kt b/kotlin/lib/src/main/kotlin/Message.kt index 0cc0c0df4..87d5c2f8c 100644 --- a/kotlin/lib/src/main/kotlin/Message.kt +++ b/kotlin/lib/src/main/kotlin/Message.kt @@ -1,58 +1,33 @@ -// this file is @generated (with manual changes) +// this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.MessageApi -import com.svix.kotlin.models.ApplicationIn import com.svix.kotlin.models.ListResponseMessageOut import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.MessageOut -import java.time.OffsetDateTime - -class MessageListOptions { - var limit: Int? = null - var iterator: String? = null - var channel: String? = null - var before: OffsetDateTime? = null - var after: OffsetDateTime? = null - var withContent: Boolean? = null - var tag: String? = null - var eventTypes: List? = null - - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } - - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } - - /** Filter response based on the channel. */ - fun channel(channel: String) = apply { this.channel = channel } - - /** Only include items created before a certain date. */ - fun before(before: OffsetDateTime) = apply { this.before = before } - - /** Only include items created after a certain date. */ - fun after(after: OffsetDateTime) = apply { this.after = after } - - /** When `true` message payloads are included in the response. */ - fun withContent(withContent: Boolean) = apply { this.withContent = withContent } - - /** Filter messages matching the provided tag. */ - fun tag(tag: String) = apply { this.tag = tag } - - /** Filter response based on the event type */ - fun eventTypes(eventTypes: List) = apply { this.eventTypes = eventTypes } -} - -class Message internal constructor(token: String, options: SvixOptions) { - private val api = MessageApi(options.serverUrl) - - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +import kotlinx.datetime.Instant +import okhttp3.Headers +import okhttp3.HttpUrl + +data class MessageListOptions( + val limit: ULong? = null, + val iterator: String? = null, + val channel: String? = null, + val before: Instant? = null, + val after: Instant? = null, + val withContent: Boolean? = null, + val tag: String? = null, + val eventTypes: Set? = null, +) + +data class MessageCreateOptions( + val withContent: Boolean? = null, + val idempotencyKey: String? = null, +) + +data class MessageGetOptions(val withContent: Boolean? = null) + +class Message(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** * List all of the application's messages. @@ -70,21 +45,16 @@ class Message internal constructor(token: String, options: SvixOptions) { appId: String, options: MessageListOptions = MessageListOptions(), ): ListResponseMessageOut { - try { - return api.v1MessageList( - appId, - options.limit, - options.iterator, - options.channel, - options.before, - options.after, - options.withContent, - options.tag, - HashSet(options.eventTypes), - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.channel?.let { url = url.addQueryParameter("channel", it) } + options.before?.let { url = url.addQueryParameter("before", it.toString()) } + options.after?.let { url = url.addQueryParameter("after", it.toString()) } + options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + options.tag?.let { url = url.addQueryParameter("tag", it) } + options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + return this.executeRequest("GET", url.build()) } /** @@ -107,22 +77,30 @@ class Message internal constructor(token: String, options: SvixOptions) { suspend fun create( appId: String, messageIn: MessageIn, - options: PostOptions = PostOptions(), + options: MessageCreateOptions = MessageCreateOptions(), ): MessageOut { - try { - return api.v1MessageCreate(appId, messageIn, null, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") + options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = messageIn, + ) } /** Get a message by its ID or eventID. */ - suspend fun get(msgId: String, appId: String): MessageOut { - try { - return api.v1MessageGet(appId, msgId, null) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + suspend fun get( + appId: String, + msgId: String, + options: MessageGetOptions = MessageGetOptions(), + ): MessageOut { + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId") + options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + return this.executeRequest("GET", url.build()) } /** @@ -131,57 +109,8 @@ class Message internal constructor(token: String, options: SvixOptions) { * Useful in cases when a message was accidentally sent with sensitive content. The message * can't be replayed or resent once its payload has been deleted or expired. */ - suspend fun expungeContent(msgId: String, appId: String) { - try { - api.v1MessageExpungeContent(appId, msgId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + suspend fun expungeContent(appId: String, msgId: String) { + val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/content") + this.executeRequest("DELETE", url.build()) } } - -/** - * Creates a [MessageIn] with a pre-serialized payload. - * - * The payload is not normalized on the server. Normally, payloads are required to be JSON, and Svix - * will minify the payload before sending the webhooks (for example, by removing extraneous - * whitespace or unnecessarily escaped characters in strings). With this function, the payload will - * be sent "as is", without any minification or other processing. - * - * @param payload Serialized message payload - * @param contentType The value to use for the Content-Type header of the webhook sent by Svix, - * overwriting the default of `application/json` if specified - * - * See the class documentation for details about the other parameters. - */ -fun messageInRaw( - eventType: String, - payload: String, - contentType: String? = null, - application: ApplicationIn? = null, - channels: Set? = null, - eventId: String? = null, - payloadRetentionHours: Long? = null, - payloadRetentionPeriod: Long? = 90L, - tags: Set? = null, - transformationsParams: Map = mapOf(), -): MessageIn { - val transformationsParams = transformationsParams.toMutableMap() - transformationsParams.put("rawPayload", payload) - if (contentType != null) { - val headers = mapOf("content-type" to contentType) - transformationsParams.put("headers", headers) - } - - return MessageIn( - eventType = eventType, - payload = mapOf(), - application = application, - channels = channels, - eventId = eventId, - payloadRetentionHours = payloadRetentionHours, - payloadRetentionPeriod = payloadRetentionPeriod, - tags = tags, - transformationsParams = transformationsParams, - ) -} diff --git a/kotlin/lib/src/main/kotlin/MessageAttempt.kt b/kotlin/lib/src/main/kotlin/MessageAttempt.kt index 7e9f283fb..ee2b3a2fd 100644 --- a/kotlin/lib/src/main/kotlin/MessageAttempt.kt +++ b/kotlin/lib/src/main/kotlin/MessageAttempt.kt @@ -1,234 +1,65 @@ -// this file is @generated (with manual changes) +// this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.MessageAttemptApi import com.svix.kotlin.models.ListResponseEndpointMessageOut -import com.svix.kotlin.models.ListResponseMessageAttemptEndpointOut import com.svix.kotlin.models.ListResponseMessageAttemptOut import com.svix.kotlin.models.ListResponseMessageEndpointOut import com.svix.kotlin.models.MessageAttemptOut import com.svix.kotlin.models.MessageStatus import com.svix.kotlin.models.StatusCodeClass -import java.time.OffsetDateTime - -class MessageAttemptListByEndpointOptions { - var limit: Int? = null - var iterator: String? = null - var status: MessageStatus? = null - var statusCodeClass: StatusCodeClass? = null - var channel: String? = null - var tag: String? = null - var before: OffsetDateTime? = null - var after: OffsetDateTime? = null - var withContent: Boolean? = null - var withMsg: Boolean? = null - var eventTypes: List? = null - - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } - - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } - - /** - * Filter response based on the status of the attempt: Success (0), Pending (1), Failed (2), or - * Sending (3) - */ - fun status(status: MessageStatus) = apply { this.status = status } - - /** Filter response based on the HTTP status code */ - fun statusCodeClass(statusCodeClass: StatusCodeClass) = apply { - this.statusCodeClass = statusCodeClass - } - - /** Filter response based on the channel */ - fun channel(channel: String) = apply { this.channel = channel } - - /** Filter response based on the tag */ - fun tag(tag: String) = apply { this.tag = tag } - - /** Only include items created before a certain date */ - fun before(before: OffsetDateTime) = apply { this.before = before } - - /** Only include items created after a certain date */ - fun after(after: OffsetDateTime) = apply { this.after = after } - - /** When `true` attempt content is included in the response */ - fun withContent(withContent: Boolean) = apply { this.withContent = withContent } - - /** When `true`, the message information is included in the response */ - fun withMsg(withMsg: Boolean) = apply { this.withMsg = withMsg } - - /** Filter response based on the event type */ - fun eventTypes(eventTypes: List) = apply { this.eventTypes = eventTypes } -} - -class MessageAttemptListByMsgOptions { - var limit: Int? = null - var iterator: String? = null - var status: MessageStatus? = null - var statusCodeClass: StatusCodeClass? = null - var channel: String? = null - var tag: String? = null - var endpointId: String? = null - var before: OffsetDateTime? = null - var after: OffsetDateTime? = null - var withContent: Boolean? = null - var eventTypes: List? = null - - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } - - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } - - /** - * Filter response based on the status of the attempt: Success (0), Pending (1), Failed (2), or - * Sending (3) - */ - fun status(status: MessageStatus) = apply { this.status = status } - - /** Filter response based on the HTTP status code */ - fun statusCodeClass(statusCodeClass: StatusCodeClass) = apply { - this.statusCodeClass = statusCodeClass - } - - /** Filter response based on the channel */ - fun channel(channel: String) = apply { this.channel = channel } - - /** Filter response based on the tag */ - fun tag(tag: String) = apply { this.tag = tag } - - /** Filter the attempts based on the attempted endpoint */ - fun endpointId(endpointId: String) = apply { this.endpointId = endpointId } - - /** Only include items created before a certain date */ - fun before(before: OffsetDateTime) = apply { this.before = before } - - /** Only include items created after a certain date */ - fun after(after: OffsetDateTime) = apply { this.after = after } - - /** When `true` attempt content is included in the response */ - fun withContent(withContent: Boolean) = apply { this.withContent = withContent } - - /** Filter response based on the event type */ - fun eventTypes(eventTypes: List) = apply { this.eventTypes = eventTypes } -} - -class MessageAttemptListAttemptedMessagesOptions { - var limit: Int? = null - var iterator: String? = null - var channel: String? = null - var tag: String? = null - var status: MessageStatus? = null - var before: OffsetDateTime? = null - var after: OffsetDateTime? = null - var withContent: Boolean? = null - var eventTypes: List? = null - - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } - - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } - - /** Filter response based on the channel */ - fun channel(channel: String) = apply { this.channel = channel } - - /** Filter response based on the message tags */ - fun tag(tag: String) = apply { this.tag = tag } - - /** - * Filter response based on the status of the attempt: Success (0), Pending (1), Failed (2), or - * Sending (3) - */ - fun status(status: MessageStatus) = apply { this.status = status } - - /** Only include items created before a certain date */ - fun before(before: OffsetDateTime) = apply { this.before = before } - - /** Only include items created after a certain date */ - fun after(after: OffsetDateTime) = apply { this.after = after } - - /** When `true` message payloads are included in the response */ - fun withContent(withContent: Boolean) = apply { this.withContent = withContent } - - /** Filter response based on the event type */ - fun eventTypes(eventTypes: List) = apply { this.eventTypes = eventTypes } -} - -class MessageAttemptListAttemptedDestinationsOptions { - var limit: Int? = null - var iterator: String? = null - - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } - - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } -} - -class MessageAttemptListOptions( - var iterator: String? = null, - var limit: Int? = null, - var messageStatus: MessageStatus? = null, - var before: OffsetDateTime? = null, - var after: OffsetDateTime? = null, - var eventTypes: List? = null, - var statusCodeClass: StatusCodeClass? = null, - var channel: String? = null, - var tag: String? = null, - var endpointId: String? = null, - var withContent: Boolean? = null, - var withMsg: Boolean? = null, -) { - fun messageStatus(messageStatus: MessageStatus) = apply { this.messageStatus = messageStatus } - - fun before(before: OffsetDateTime) = apply { this.before = before } - - fun after(after: OffsetDateTime) = apply { this.after = after } - - fun statusCodeClass(statusCodeClass: StatusCodeClass) = apply { - this.statusCodeClass = statusCodeClass - } - - fun eventTypes(eventTypes: List) = apply { this.eventTypes = eventTypes } - - fun channel(channel: String) = apply { this.channel = channel } - - fun iterator(iterator: String) = apply { this.iterator = iterator } - - fun limit(limit: Int) = apply { this.limit = limit } - - fun endpointId(endpointId: String) = apply { this.endpointId = endpointId } - - fun withContent(withContent: Boolean) = apply { this.withContent = withContent } - - fun withMsg(withMsg: Boolean) = apply { this.withMsg = withMsg } - - fun tag(tag: String) = apply { this.tag = tag } -} - -class MessageAttempt internal constructor(token: String, options: SvixOptions) { - private val api = MessageAttemptApi(options.serverUrl) - - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } - - /** @deprecated use listByMsg instead. */ - @Deprecated(message = "use listByMsg instead.") - suspend fun list( - appId: String, - msgId: String, - options: MessageAttemptListByMsgOptions = MessageAttemptListByMsgOptions(), - ): ListResponseMessageAttemptOut { - return this.listByMsg(appId, msgId, options) - } +import kotlinx.datetime.Instant +import okhttp3.Headers +import okhttp3.HttpUrl + +data class MessageAttemptListByEndpointOptions( + val limit: ULong? = null, + val iterator: String? = null, + val status: MessageStatus? = null, + val statusCodeClass: StatusCodeClass? = null, + val channel: String? = null, + val tag: String? = null, + val before: Instant? = null, + val after: Instant? = null, + val withContent: Boolean? = null, + val withMsg: Boolean? = null, + val eventTypes: Set? = null, +) + +data class MessageAttemptListByMsgOptions( + val limit: ULong? = null, + val iterator: String? = null, + val status: MessageStatus? = null, + val statusCodeClass: StatusCodeClass? = null, + val channel: String? = null, + val tag: String? = null, + val endpointId: String? = null, + val before: Instant? = null, + val after: Instant? = null, + val withContent: Boolean? = null, + val eventTypes: Set? = null, +) + +data class MessageAttemptListAttemptedMessagesOptions( + val limit: ULong? = null, + val iterator: String? = null, + val channel: String? = null, + val tag: String? = null, + val status: MessageStatus? = null, + val before: Instant? = null, + val after: Instant? = null, + val withContent: Boolean? = null, + val eventTypes: Set? = null, +) + +data class MessageAttemptListAttemptedDestinationsOptions( + val limit: ULong? = null, + val iterator: String? = null, +) + +data class MessageAttemptResendOptions(val idempotencyKey: String? = null) + +class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** * List attempts by endpoint id @@ -243,25 +74,22 @@ class MessageAttempt internal constructor(token: String, options: SvixOptions) { endpointId: String, options: MessageAttemptListByEndpointOptions = MessageAttemptListByEndpointOptions(), ): ListResponseMessageAttemptOut { - try { - return api.v1MessageAttemptListByEndpoint( - appId, - endpointId, - options.limit, - options.iterator, - options.status, - options.statusCodeClass, - options.channel, - options.tag, - options.before, - options.after, - options.withContent, - options.withMsg, - HashSet(options.eventTypes), - ) - } catch (e: Exception) { - throw ApiException.wrap(e) + var url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/endpoint/$endpointId") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.status?.let { url = url.addQueryParameter("status", it.toString()) } + options.statusCodeClass?.let { + url = url.addQueryParameter("status_code_class", it.toString()) } + options.channel?.let { url = url.addQueryParameter("channel", it) } + options.tag?.let { url = url.addQueryParameter("tag", it) } + options.before?.let { url = url.addQueryParameter("before", it.toString()) } + options.after?.let { url = url.addQueryParameter("after", it.toString()) } + options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + options.withMsg?.let { url = url.addQueryParameter("with_msg", it.toString()) } + options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + return this.executeRequest("GET", url.build()) } /** @@ -277,25 +105,21 @@ class MessageAttempt internal constructor(token: String, options: SvixOptions) { msgId: String, options: MessageAttemptListByMsgOptions = MessageAttemptListByMsgOptions(), ): ListResponseMessageAttemptOut { - try { - return api.v1MessageAttemptListByMsg( - appId, - msgId, - options.limit, - options.iterator, - options.status, - options.statusCodeClass, - options.channel, - options.tag, - options.endpointId, - options.before, - options.after, - options.withContent, - HashSet(options.eventTypes), - ) - } catch (e: Exception) { - throw ApiException.wrap(e) + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/msg/$msgId") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.status?.let { url = url.addQueryParameter("status", it.toString()) } + options.statusCodeClass?.let { + url = url.addQueryParameter("status_code_class", it.toString()) } + options.channel?.let { url = url.addQueryParameter("channel", it) } + options.tag?.let { url = url.addQueryParameter("tag", it) } + options.endpointId?.let { url = url.addQueryParameter("endpoint_id", it) } + options.before?.let { url = url.addQueryParameter("before", it.toString()) } + options.after?.let { url = url.addQueryParameter("after", it.toString()) } + options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + return this.executeRequest("GET", url.build()) } /** @@ -316,32 +140,24 @@ class MessageAttempt internal constructor(token: String, options: SvixOptions) { options: MessageAttemptListAttemptedMessagesOptions = MessageAttemptListAttemptedMessagesOptions(), ): ListResponseEndpointMessageOut { - try { - return api.v1MessageAttemptListAttemptedMessages( - appId, - endpointId, - options.limit, - options.iterator, - options.channel, - options.tag, - options.status, - options.before, - options.after, - options.withContent, - HashSet(options.eventTypes), - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/msg") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.channel?.let { url = url.addQueryParameter("channel", it) } + options.tag?.let { url = url.addQueryParameter("tag", it) } + options.status?.let { url = url.addQueryParameter("status", it.toString()) } + options.before?.let { url = url.addQueryParameter("before", it.toString()) } + options.after?.let { url = url.addQueryParameter("after", it.toString()) } + options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + return this.executeRequest("GET", url.build()) } /** `msg_id`: Use a message id or a message `eventId` */ suspend fun get(appId: String, msgId: String, attemptId: String): MessageAttemptOut { - try { - return api.v1MessageAttemptGet(appId, msgId, attemptId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/attempt/$attemptId") + return this.executeRequest("GET", url.build()) } /** @@ -351,11 +167,10 @@ class MessageAttempt internal constructor(token: String, options: SvixOptions) { * replayed or resent once its payload has been deleted or expired. */ suspend fun expungeContent(appId: String, msgId: String, attemptId: String) { - try { - api.v1MessageAttemptExpungeContent(appId, msgId, attemptId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/app/$appId/msg/$msgId/attempt/$attemptId/content") + this.executeRequest("DELETE", url.build()) } /** @@ -370,37 +185,10 @@ class MessageAttempt internal constructor(token: String, options: SvixOptions) { options: MessageAttemptListAttemptedDestinationsOptions = MessageAttemptListAttemptedDestinationsOptions(), ): ListResponseMessageEndpointOut { - try { - return api.v1MessageAttemptListAttemptedDestinations( - appId, - msgId, - options.limit, - options.iterator, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } - } - - @Deprecated(message = "use listByMsg instead, passing the endpoint ID through options.") - suspend fun listAttemptsForEndpoint( - appId: String, - endpointId: String, - msgId: String, - options: MessageAttemptListOptions = MessageAttemptListOptions(), - ): ListResponseMessageAttemptOut { - val listByMsgOptions = MessageAttemptListByMsgOptions() - listByMsgOptions.limit = options.limit - listByMsgOptions.iterator = options.iterator - listByMsgOptions.channel = options.channel - listByMsgOptions.tag = options.tag - listByMsgOptions.status = options.messageStatus - listByMsgOptions.before = options.before - listByMsgOptions.after = options.after - listByMsgOptions.eventTypes = options.eventTypes - listByMsgOptions.endpointId = endpointId - - return listByMsg(appId, msgId, listByMsgOptions) + var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/endpoint") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + return this.executeRequest("GET", url.build()) } /** Resend a message to the specified endpoint. */ @@ -408,12 +196,13 @@ class MessageAttempt internal constructor(token: String, options: SvixOptions) { appId: String, msgId: String, endpointId: String, - options: PostOptions = PostOptions(), + options: MessageAttemptResendOptions = MessageAttemptResendOptions(), ) { - try { - api.v1MessageAttemptResend(appId, msgId, endpointId, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/app/$appId/msg/$msgId/endpoint/$endpointId/resend") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + this.executeRequest("POST", url.build(), headers = headers.build()) } } diff --git a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt index 8234b3d1c..67820e71d 100644 --- a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt +++ b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt @@ -1,8 +1,6 @@ // this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.WebhookEndpointApi as OperationalWebhookEndpointApi import com.svix.kotlin.models.ListResponseOperationalWebhookEndpointOut import com.svix.kotlin.models.OperationalWebhookEndpointHeadersIn import com.svix.kotlin.models.OperationalWebhookEndpointHeadersOut @@ -12,69 +10,58 @@ import com.svix.kotlin.models.OperationalWebhookEndpointSecretIn import com.svix.kotlin.models.OperationalWebhookEndpointSecretOut import com.svix.kotlin.models.OperationalWebhookEndpointUpdate import com.svix.kotlin.models.Ordering +import okhttp3.Headers +import okhttp3.HttpUrl -class OperationalWebhookEndpointListOptions { - var limit: Int? = null - var iterator: String? = null - var order: Ordering? = null +data class OperationalWebhookEndpointListOptions( + val limit: ULong? = null, + val iterator: String? = null, + val order: Ordering? = null, +) - /** Limit the number of returned items */ - fun limit(limit: Int) = apply { this.limit = limit } +data class OperationalWebhookEndpointCreateOptions(val idempotencyKey: String? = null) - /** The iterator returned from a prior invocation */ - fun iterator(iterator: String) = apply { this.iterator = iterator } +data class OperationalWebhookEndpointRotateSecretOptions(val idempotencyKey: String? = null) - /** The sorting order of the returned items */ - fun order(order: Ordering) = apply { this.order = order } -} - -class OperationalWebhookEndpoint internal constructor(token: String, options: SvixOptions) { - private val api = OperationalWebhookEndpointApi(options.serverUrl) - - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** List operational webhook endpoints. */ suspend fun list( options: OperationalWebhookEndpointListOptions = OperationalWebhookEndpointListOptions() ): ListResponseOperationalWebhookEndpointOut { - try { - return api.v1OperationalWebhookEndpointList( - options.limit, - options.iterator, - options.order, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + var url = this.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint") + options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.iterator?.let { url = url.addQueryParameter("iterator", it) } + options.order?.let { url = url.addQueryParameter("order", it.toString()) } + return this.executeRequest( + "GET", + url.build(), + ) } /** Create an operational webhook endpoint. */ suspend fun create( operationalWebhookEndpointIn: OperationalWebhookEndpointIn, - options: PostOptions = PostOptions(), + options: OperationalWebhookEndpointCreateOptions = OperationalWebhookEndpointCreateOptions(), ): OperationalWebhookEndpointOut { - try { - return api.v1OperationalWebhookEndpointCreate( - operationalWebhookEndpointIn, - options.idempotencyKey, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = operationalWebhookEndpointIn, + ) } /** Get an operational webhook endpoint. */ suspend fun get(endpointId: String): OperationalWebhookEndpointOut { - try { - return api.v1OperationalWebhookEndpointGet(endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint/$endpointId") + return this.executeRequest("GET", url.build()) } /** Update an operational webhook endpoint. */ @@ -82,32 +69,29 @@ class OperationalWebhookEndpoint internal constructor(token: String, options: Sv endpointId: String, operationalWebhookEndpointUpdate: OperationalWebhookEndpointUpdate, ): OperationalWebhookEndpointOut { - try { - return api.v1OperationalWebhookEndpointUpdate( - endpointId, - operationalWebhookEndpointUpdate, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint/$endpointId") + + return this.executeRequest( + "PUT", + url.build(), + reqBody = operationalWebhookEndpointUpdate, + ) } /** Delete an operational webhook endpoint. */ suspend fun delete(endpointId: String) { - try { - api.v1OperationalWebhookEndpointDelete(endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint/$endpointId") + this.executeRequest("DELETE", url.build()) } /** Get the additional headers to be sent with the operational webhook. */ suspend fun getHeaders(endpointId: String): OperationalWebhookEndpointHeadersOut { - try { - return api.v1OperationalWebhookEndpointGetHeaders(endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/operational-webhook/endpoint/$endpointId/headers") + return this.executeRequest("GET", url.build()) } /** Set the additional headers to be sent with the operational webhook. */ @@ -115,14 +99,15 @@ class OperationalWebhookEndpoint internal constructor(token: String, options: Sv endpointId: String, operationalWebhookEndpointHeadersIn: OperationalWebhookEndpointHeadersIn, ) { - try { - api.v1OperationalWebhookEndpointUpdateHeaders( - endpointId, - operationalWebhookEndpointHeadersIn, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/operational-webhook/endpoint/$endpointId/headers") + + this.executeRequest( + "PUT", + url.build(), + reqBody = operationalWebhookEndpointHeadersIn, + ) } /** @@ -132,11 +117,10 @@ class OperationalWebhookEndpoint internal constructor(token: String, options: Sv * [the consuming webhooks docs](https://docs.svix.com/consuming-webhooks/). */ suspend fun getSecret(endpointId: String): OperationalWebhookEndpointSecretOut { - try { - return api.v1OperationalWebhookEndpointGetSecret(endpointId) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/operational-webhook/endpoint/$endpointId/secret") + return this.executeRequest("GET", url.build()) } /** @@ -147,16 +131,20 @@ class OperationalWebhookEndpoint internal constructor(token: String, options: Sv suspend fun rotateSecret( endpointId: String, operationalWebhookEndpointSecretIn: OperationalWebhookEndpointSecretIn, - options: PostOptions = PostOptions(), + options: OperationalWebhookEndpointRotateSecretOptions = + OperationalWebhookEndpointRotateSecretOptions(), ) { - try { - api.v1OperationalWebhookEndpointRotateSecret( - endpointId, - operationalWebhookEndpointSecretIn, - options.idempotencyKey, - ) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = + this.newUrlBuilder() + .encodedPath("/api/v1/operational-webhook/endpoint/$endpointId/secret/rotate") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = operationalWebhookEndpointSecretIn, + ) } } diff --git a/kotlin/lib/src/main/kotlin/Statistics.kt b/kotlin/lib/src/main/kotlin/Statistics.kt index 79ca3e2a6..a0f415f68 100644 --- a/kotlin/lib/src/main/kotlin/Statistics.kt +++ b/kotlin/lib/src/main/kotlin/Statistics.kt @@ -1,21 +1,16 @@ // this file is @generated package com.svix.kotlin -import com.svix.kotlin.exceptions.ApiException -import com.svix.kotlin.internal.apis.StatisticsApi import com.svix.kotlin.models.AggregateEventTypesOut import com.svix.kotlin.models.AppUsageStatsIn import com.svix.kotlin.models.AppUsageStatsOut +import okhttp3.Headers +import okhttp3.HttpUrl -class Statistics internal constructor(token: String, options: SvixOptions) { - private val api = StatisticsApi(options.serverUrl) +data class StatisticsAggregateAppStatsOptions(val idempotencyKey: String? = null) - init { - api.accessToken = token - api.userAgent = options.getUA() - options.initialRetryDelayMillis?.let { api.initialRetryDelayMillis = it } - options.numRetries?.let { api.numRetries = it } - } +class Statistics(baseUrl: HttpUrl, defaultHeaders: Map) : + SvixHttpClient(baseUrl, defaultHeaders) { /** * Creates a background task to calculate the message destinations for all applications in the @@ -26,13 +21,18 @@ class Statistics internal constructor(token: String, options: SvixOptions) { */ suspend fun aggregateAppStats( appUsageStatsIn: AppUsageStatsIn, - options: PostOptions = PostOptions(), + options: StatisticsAggregateAppStatsOptions = StatisticsAggregateAppStatsOptions(), ): AppUsageStatsOut { - try { - return api.v1StatisticsAggregateAppStats(appUsageStatsIn, options.idempotencyKey) - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/stats/usage/app") + var headers = Headers.Builder() + options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + + return this.executeRequest( + "POST", + url.build(), + headers = headers.build(), + reqBody = appUsageStatsIn, + ) } /** @@ -43,10 +43,7 @@ class Statistics internal constructor(token: String, options: SvixOptions) { * endpoint to retrieve the results of the operation. */ suspend fun aggregateEventTypes(): AggregateEventTypesOut { - try { - return api.v1StatisticsAggregateEventTypes() - } catch (e: Exception) { - throw ApiException.wrap(e) - } + val url = this.newUrlBuilder().encodedPath("/api/v1/stats/usage/event-types") + return this.executeRequest("PUT", url.build()) } } From 4bf6ca8919752f21a452b1af51c0f5da7d6044dc Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 15:57:22 -0500 Subject: [PATCH 07/56] kotlin: Remove this, it's now part of Svix.kt --- kotlin/lib/src/main/kotlin/SvixOptions.kt | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 kotlin/lib/src/main/kotlin/SvixOptions.kt diff --git a/kotlin/lib/src/main/kotlin/SvixOptions.kt b/kotlin/lib/src/main/kotlin/SvixOptions.kt deleted file mode 100644 index 1ad987368..000000000 --- a/kotlin/lib/src/main/kotlin/SvixOptions.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.svix.kotlin - -data class SvixOptions( - internal var wantedServerUrl: String? = null, - val initialRetryDelayMillis: Long? = null, - val numRetries: Int? = null, -) { - private val version = "1.21.0" - - var serverUrl: String - get() = this.wantedServerUrl ?: DEFAULT_URL - set(value) { - this.wantedServerUrl = value - } - - companion object { - const val DEFAULT_URL = "https://api.svix.com" - } - - internal fun getUA(): String { - return "svix-libs/$version/kotlin" - } -} From ca28438ba27a7290effed102decd6fee57103906 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 15:57:41 -0500 Subject: [PATCH 08/56] kotlin: Refactor Svix class --- kotlin/lib/src/main/kotlin/Svix.kt | 58 +++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Svix.kt b/kotlin/lib/src/main/kotlin/Svix.kt index a7e798926..5b4e32e8b 100644 --- a/kotlin/lib/src/main/kotlin/Svix.kt +++ b/kotlin/lib/src/main/kotlin/Svix.kt @@ -1,27 +1,53 @@ package com.svix.kotlin +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull + class Svix(token: String, options: SvixOptions = SvixOptions()) { + + private val version = "1.21.0" + val application: Application + val authentication: Authentication + val endpoint: Endpoint + val eventType: EventType + val integration: Integration + val message: Message + val messageAttempt: MessageAttempt + val statistics: Statistics + val operationalWebhookEndpoint: OperationalWebhookEndpoint + init { val tokenParts = token.split(".") - if (options.wantedServerUrl == null) { + if (options.baseUrl == null) { val region = tokenParts.last() - if (region == "us") { - options.serverUrl = "https://api.us.svix.com" - } else if (region == "eu") { - options.serverUrl = "https://api.eu.svix.com" - } else if (region == "in") { - options.serverUrl = "https://api.in.svix.com" + when (region) { + "us" -> options.baseUrl = "https://api.us.svix.com" + "eu" -> options.baseUrl = "https://api.eu.svix.com" + "in" -> options.baseUrl = "https://api.in.svix.com" + else -> options.baseUrl = "https://api.svix.com" } } + val parsedUrl = options.baseUrl?.toHttpUrlOrNull() ?: throw Exception("Invalid base url") + val defaultHeaders = + mapOf("User-Agent" to "svix-libs/$version/kotlin", "Authorization" to "Bearer $token") + application = Application(parsedUrl, defaultHeaders) + authentication = Authentication(parsedUrl, defaultHeaders) + endpoint = Endpoint(parsedUrl, defaultHeaders) + eventType = EventType(parsedUrl, defaultHeaders) + integration = Integration(parsedUrl, defaultHeaders) + message = Message(parsedUrl, defaultHeaders) + messageAttempt = MessageAttempt(parsedUrl, defaultHeaders) + statistics = Statistics(parsedUrl, defaultHeaders) + operationalWebhookEndpoint = OperationalWebhookEndpoint(parsedUrl, defaultHeaders) } +} - val application = Application(token, options) - val authentication = Authentication(token, options) - val endpoint = Endpoint(token, options) - val eventType = EventType(token, options) - val integration = Integration(token, options) - val message = Message(token, options) - val messageAttempt = MessageAttempt(token, options) - val statistics = Statistics(token, options) - val operationalWebhookEndpoint = OperationalWebhookEndpoint(token, options) +data class SvixOptions( + var baseUrl: String? = null, + val retrySchedule: List = listOf(50, 100, 200), +) { + init { + if (retrySchedule.count() > 5) { + throw IllegalArgumentException("number of retries must not exceed 5") + } + } } From 2b593cf12932a6fa5b9a4b8ec18e9cbd4717b66f Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 15:59:01 -0500 Subject: [PATCH 09/56] kotlin: Fix tests --- .../lib/src/test/com/svix/kotlin/BasicTest.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt index 0b2956f63..7814abde3 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt @@ -6,10 +6,12 @@ import com.svix.kotlin.models.EndpointIn import com.svix.kotlin.models.EndpointPatch import com.svix.kotlin.models.EventTypeIn import com.svix.kotlin.models.MessageIn -import java.net.URI import kotlin.test.Test import kotlin.test.assertEquals import kotlinx.coroutines.runBlocking +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive class BasicTest { companion object { @@ -37,11 +39,11 @@ class BasicTest { MessageIn( eventType = "invoice.paid", payload = - mapOf( - "id" to "invoice_WF7WtCLFFtd8ubcTgboSFNql", - "status" to "paid", - "attempt" to 2, - ), + JsonObject(mapOf( + "id" to JsonPrimitive( "invoice_WF7WtCLFFtd8ubcTgboSFNql"), + "status" to JsonPrimitive("paid"), + "attempt" to JsonPrimitive(2), + )), ), ) svix.application.delete(applicationOut.id) @@ -81,7 +83,7 @@ class BasicTest { svix.endpoint.create( appOut.id, EndpointIn( - url = URI("https://example.svix.com"), + url = "https://example.svix.com", channels = setOf("ch0", "ch1"), ), ) @@ -91,7 +93,7 @@ class BasicTest { svix.endpoint.patch( appOut.id, epOut.id, - EndpointPatch(filterTypes = setOf("event.started", "event.ended")), + EndpointPatch(filterTypes = MaybeUnset.Present(setOf("event.started", "event.ended"))), ) assertEquals( setOf("ch0", "ch1"), From 3e9ec924930a411c0ef946e2565373e92b960f5f Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 16:00:44 -0500 Subject: [PATCH 10/56] kotlin: Removed generated code from srcDirs --- kotlin/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/build.gradle b/kotlin/build.gradle index 351fb7123..192bc013e 100644 --- a/kotlin/build.gradle +++ b/kotlin/build.gradle @@ -37,7 +37,7 @@ repositories { sourceSets { main.kotlin.srcDirs += 'lib/src/main/kotlin' - main.kotlin.srcDirs += 'lib/generated/openapi/src/main/kotlin' + // main.kotlin.srcDirs += 'lib/generated/openapi/src/main/kotlin' sourceSets.test.kotlin.srcDirs = ["lib/src/test/main/kotlin"] test.kotlin.srcDirs = ['lib/src/test'] } From ecda8b752ebf01ebf4a94a1fb9dd966624a6c90a Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 16:01:36 -0500 Subject: [PATCH 11/56] kotlin: Add newly generated models The old models took up 45k loc --- .../kotlin/models/AggregateEventTypesOut.kt | 11 ++++ .../main/kotlin/models/AppPortalAccessIn.kt | 12 +++++ .../main/kotlin/models/AppPortalAccessOut.kt | 6 +++ .../src/main/kotlin/models/AppUsageStatsIn.kt | 8 +++ .../main/kotlin/models/AppUsageStatsOut.kt | 12 +++++ .../src/main/kotlin/models/ApplicationIn.kt | 12 +++++ .../src/main/kotlin/models/ApplicationOut.kt | 16 ++++++ .../main/kotlin/models/ApplicationPatch.kt | 13 +++++ .../kotlin/models/ApplicationTokenExpireIn.kt | 6 +++ .../main/kotlin/models/BackgroundTaskOut.kt | 13 +++++ .../kotlin/models/BackgroundTaskStatus.kt | 10 ++++ .../main/kotlin/models/BackgroundTaskType.kt | 13 +++++ .../main/kotlin/models/DashboardAccessOut.kt | 6 +++ .../main/kotlin/models/EndpointHeadersIn.kt | 6 +++ .../main/kotlin/models/EndpointHeadersOut.kt | 7 +++ .../kotlin/models/EndpointHeadersPatchIn.kt | 6 +++ .../lib/src/main/kotlin/models/EndpointIn.kt | 18 +++++++ .../main/kotlin/models/EndpointMessageOut.kt | 19 +++++++ .../lib/src/main/kotlin/models/EndpointOut.kt | 21 ++++++++ .../src/main/kotlin/models/EndpointPatch.kt | 19 +++++++ .../main/kotlin/models/EndpointSecretOut.kt | 6 +++ .../kotlin/models/EndpointSecretRotateIn.kt | 6 +++ .../src/main/kotlin/models/EndpointStats.kt | 7 +++ .../kotlin/models/EndpointTransformationIn.kt | 7 +++ .../models/EndpointTransformationOut.kt | 7 +++ .../src/main/kotlin/models/EndpointUpdate.kt | 17 +++++++ .../src/main/kotlin/models/EnvironmentIn.kt | 12 +++++ .../src/main/kotlin/models/EnvironmentOut.kt | 15 ++++++ .../src/main/kotlin/models/EventExampleIn.kt | 6 +++ .../kotlin/models/EventTypeFromOpenApi.kt | 15 ++++++ .../kotlin/models/EventTypeImportOpenApiIn.kt | 13 +++++ .../models/EventTypeImportOpenApiOut.kt | 6 +++ .../models/EventTypeImportOpenApiOutData.kt | 11 ++++ .../lib/src/main/kotlin/models/EventTypeIn.kt | 16 ++++++ .../src/main/kotlin/models/EventTypeOut.kt | 19 +++++++ .../src/main/kotlin/models/EventTypePatch.kt | 16 ++++++ .../src/main/kotlin/models/EventTypeUpdate.kt | 15 ++++++ .../src/main/kotlin/models/IntegrationIn.kt | 6 +++ .../main/kotlin/models/IntegrationKeyOut.kt | 6 +++ .../src/main/kotlin/models/IntegrationOut.kt | 13 +++++ .../main/kotlin/models/IntegrationUpdate.kt | 6 +++ .../models/ListResponseApplicationOut.kt | 12 +++++ .../models/ListResponseBackgroundTaskOut.kt | 12 +++++ .../models/ListResponseEndpointMessageOut.kt | 12 +++++ .../kotlin/models/ListResponseEndpointOut.kt | 12 +++++ .../kotlin/models/ListResponseEventTypeOut.kt | 12 +++++ .../models/ListResponseIntegrationOut.kt | 12 +++++ .../models/ListResponseMessageAttemptOut.kt | 12 +++++ .../models/ListResponseMessageEndpointOut.kt | 12 +++++ .../kotlin/models/ListResponseMessageOut.kt | 12 +++++ ...stResponseOperationalWebhookEndpointOut.kt | 12 +++++ .../main/kotlin/models/MessageAttemptOut.kt | 20 ++++++++ .../models/MessageAttemptTriggerType.kt | 41 +++++++++++++++ .../main/kotlin/models/MessageEndpointOut.kt | 22 ++++++++ .../lib/src/main/kotlin/models/MessageIn.kt | 18 +++++++ .../lib/src/main/kotlin/models/MessageOut.kt | 17 +++++++ .../src/main/kotlin/models/MessageStatus.kt | 45 ++++++++++++++++ .../OperationalWebhookEndpointHeadersIn.kt | 6 +++ .../OperationalWebhookEndpointHeadersOut.kt | 10 ++++ .../models/OperationalWebhookEndpointIn.kt | 16 ++++++ .../models/OperationalWebhookEndpointOut.kt | 19 +++++++ .../OperationalWebhookEndpointSecretIn.kt | 6 +++ .../OperationalWebhookEndpointSecretOut.kt | 6 +++ .../OperationalWebhookEndpointUpdate.kt | 15 ++++++ kotlin/lib/src/main/kotlin/models/Ordering.kt | 9 ++++ .../lib/src/main/kotlin/models/RecoverIn.kt | 7 +++ .../lib/src/main/kotlin/models/RecoverOut.kt | 11 ++++ kotlin/lib/src/main/kotlin/models/ReplayIn.kt | 7 +++ .../lib/src/main/kotlin/models/ReplayOut.kt | 11 ++++ .../src/main/kotlin/models/StatusCodeClass.kt | 51 +++++++++++++++++++ .../lib/src/main/kotlin/models/TemplateIn.kt | 17 +++++++ .../lib/src/main/kotlin/models/TemplateOut.kt | 22 ++++++++ .../models/TransformationTemplateKind.kt | 19 +++++++ 73 files changed, 974 insertions(+) create mode 100644 kotlin/lib/src/main/kotlin/models/AggregateEventTypesOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/AppPortalAccessIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/AppPortalAccessOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/AppUsageStatsIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/AppUsageStatsOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ApplicationIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ApplicationOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ApplicationTokenExpireIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt create mode 100644 kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt create mode 100644 kotlin/lib/src/main/kotlin/models/DashboardAccessOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointHeadersIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointHeadersOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointHeadersPatchIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointPatch.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointSecretOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointSecretRotateIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointStats.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointTransformationIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointTransformationOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EndpointUpdate.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventExampleIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOutData.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypeIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypeOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypePatch.kt create mode 100644 kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt create mode 100644 kotlin/lib/src/main/kotlin/models/IntegrationIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/IntegrationKeyOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/IntegrationOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/MessageAttemptOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt create mode 100644 kotlin/lib/src/main/kotlin/models/MessageEndpointOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/MessageIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/MessageOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/MessageStatus.kt create mode 100644 kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointUpdate.kt create mode 100644 kotlin/lib/src/main/kotlin/models/Ordering.kt create mode 100644 kotlin/lib/src/main/kotlin/models/RecoverIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/RecoverOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ReplayIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ReplayOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt create mode 100644 kotlin/lib/src/main/kotlin/models/TemplateIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/TemplateOut.kt create mode 100644 kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt diff --git a/kotlin/lib/src/main/kotlin/models/AggregateEventTypesOut.kt b/kotlin/lib/src/main/kotlin/models/AggregateEventTypesOut.kt new file mode 100644 index 000000000..d98f25ea8 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/AggregateEventTypesOut.kt @@ -0,0 +1,11 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class AggregateEventTypesOut( + val id: String, + val status: BackgroundTaskStatus, + val task: BackgroundTaskType, +) diff --git a/kotlin/lib/src/main/kotlin/models/AppPortalAccessIn.kt b/kotlin/lib/src/main/kotlin/models/AppPortalAccessIn.kt new file mode 100644 index 000000000..b62bafa9a --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/AppPortalAccessIn.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class AppPortalAccessIn( + val application: ApplicationIn? = null, + val expiry: ULong? = null, + val featureFlags: Set? = null, + val readOnly: Boolean? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/AppPortalAccessOut.kt b/kotlin/lib/src/main/kotlin/models/AppPortalAccessOut.kt new file mode 100644 index 000000000..42357c3f6 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/AppPortalAccessOut.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class AppPortalAccessOut(val token: String, val url: String) diff --git a/kotlin/lib/src/main/kotlin/models/AppUsageStatsIn.kt b/kotlin/lib/src/main/kotlin/models/AppUsageStatsIn.kt new file mode 100644 index 000000000..37b3407d4 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/AppUsageStatsIn.kt @@ -0,0 +1,8 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class AppUsageStatsIn(val appIds: Set? = null, val since: Instant, val until: Instant) diff --git a/kotlin/lib/src/main/kotlin/models/AppUsageStatsOut.kt b/kotlin/lib/src/main/kotlin/models/AppUsageStatsOut.kt new file mode 100644 index 000000000..a282bf878 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/AppUsageStatsOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class AppUsageStatsOut( + val id: String, + val status: BackgroundTaskStatus, + val task: BackgroundTaskType, + val unresolvedAppIds: Set, +) diff --git a/kotlin/lib/src/main/kotlin/models/ApplicationIn.kt b/kotlin/lib/src/main/kotlin/models/ApplicationIn.kt new file mode 100644 index 000000000..028f0b72b --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ApplicationIn.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ApplicationIn( + val metadata: Map? = null, + val name: String, + val rateLimit: UShort? = null, + val uid: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ApplicationOut.kt b/kotlin/lib/src/main/kotlin/models/ApplicationOut.kt new file mode 100644 index 000000000..c7f7a230f --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ApplicationOut.kt @@ -0,0 +1,16 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class ApplicationOut( + val createdAt: Instant, + val id: String, + val metadata: Map, + val name: String, + val rateLimit: UShort? = null, + val uid: String? = null, + val updatedAt: Instant, +) diff --git a/kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt b/kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt new file mode 100644 index 000000000..fffe016c9 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt @@ -0,0 +1,13 @@ +// This file is @generated +package com.svix.kotlin.models + +import com.svix.kotlin.MaybeUnset +import kotlinx.serialization.Serializable + +@Serializable +data class ApplicationPatch( + val metadata: Map? = null, + val name: String? = null, + val rateLimit: MaybeUnset = MaybeUnset.Undefined, + val uid: MaybeUnset = MaybeUnset.Undefined, +) diff --git a/kotlin/lib/src/main/kotlin/models/ApplicationTokenExpireIn.kt b/kotlin/lib/src/main/kotlin/models/ApplicationTokenExpireIn.kt new file mode 100644 index 000000000..12ddf3f97 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ApplicationTokenExpireIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class ApplicationTokenExpireIn(val expiry: Long? = null) diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt new file mode 100644 index 000000000..82270afa9 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt @@ -0,0 +1,13 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class BackgroundTaskOut( + val data: JsonObject, + val id: String, + val status: BackgroundTaskStatus, + val task: BackgroundTaskType, +) diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt new file mode 100644 index 000000000..211babb47 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt @@ -0,0 +1,10 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.SerialName + +public enum class BackgroundTaskStatus { + @SerialName("running") RUNNING, + @SerialName("finished") FINISHED, + @SerialName("failed") FAILED, +} diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt new file mode 100644 index 000000000..23b8741a8 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt @@ -0,0 +1,13 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.SerialName + +public enum class BackgroundTaskType { + @SerialName("endpoint.replay") ENDPOINT_REPLAY, + @SerialName("endpoint.recover") ENDPOINT_RECOVER, + @SerialName("application.stats") APPLICATION_STATS, + @SerialName("message.broadcast") MESSAGE_BROADCAST, + @SerialName("sdk.generate") SDK_GENERATE, + @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE, +} diff --git a/kotlin/lib/src/main/kotlin/models/DashboardAccessOut.kt b/kotlin/lib/src/main/kotlin/models/DashboardAccessOut.kt new file mode 100644 index 000000000..030538c1b --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/DashboardAccessOut.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class DashboardAccessOut(val token: String, val url: String) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointHeadersIn.kt b/kotlin/lib/src/main/kotlin/models/EndpointHeadersIn.kt new file mode 100644 index 000000000..438913d73 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointHeadersIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class EndpointHeadersIn(val headers: Map) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointHeadersOut.kt b/kotlin/lib/src/main/kotlin/models/EndpointHeadersOut.kt new file mode 100644 index 000000000..9dbe190a9 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointHeadersOut.kt @@ -0,0 +1,7 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointHeadersOut(val headers: Map, val sensitive: Set) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointHeadersPatchIn.kt b/kotlin/lib/src/main/kotlin/models/EndpointHeadersPatchIn.kt new file mode 100644 index 000000000..8f3d74e5a --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointHeadersPatchIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class EndpointHeadersPatchIn(val headers: Map) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointIn.kt b/kotlin/lib/src/main/kotlin/models/EndpointIn.kt new file mode 100644 index 000000000..52a81f681 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointIn.kt @@ -0,0 +1,18 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointIn( + val channels: Set? = null, + val description: String? = null, + val disabled: Boolean? = null, + val filterTypes: Set? = null, + val metadata: Map? = null, + val rateLimit: UShort? = null, + val secret: String? = null, + val uid: String? = null, + val url: String, + val version: UShort? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt b/kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt new file mode 100644 index 000000000..1994ce9a8 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt @@ -0,0 +1,19 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EndpointMessageOut( + val channels: Set? = null, + val eventId: String? = null, + val eventType: String, + val id: String, + val nextAttempt: Instant? = null, + val payload: JsonObject, + val status: MessageStatus, + val tags: Set? = null, + val timestamp: Instant, +) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointOut.kt b/kotlin/lib/src/main/kotlin/models/EndpointOut.kt new file mode 100644 index 000000000..3baeee3b7 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointOut.kt @@ -0,0 +1,21 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointOut( + val channels: Set? = null, + val createdAt: Instant, + val description: String, + val disabled: Boolean? = null, + val filterTypes: Set? = null, + val id: String, + val metadata: Map, + val rateLimit: UShort? = null, + val uid: String? = null, + val updatedAt: Instant, + val url: String, + val version: Int, +) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointPatch.kt b/kotlin/lib/src/main/kotlin/models/EndpointPatch.kt new file mode 100644 index 000000000..ec9d3b4f2 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointPatch.kt @@ -0,0 +1,19 @@ +// This file is @generated +package com.svix.kotlin.models + +import com.svix.kotlin.MaybeUnset +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointPatch( + val channels: MaybeUnset> = MaybeUnset.Undefined, + val description: String? = null, + val disabled: Boolean? = null, + val filterTypes: MaybeUnset> = MaybeUnset.Undefined, + val metadata: Map? = null, + val rateLimit: MaybeUnset = MaybeUnset.Undefined, + val secret: MaybeUnset = MaybeUnset.Undefined, + val uid: MaybeUnset = MaybeUnset.Undefined, + val url: String? = null, + val version: UShort? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointSecretOut.kt b/kotlin/lib/src/main/kotlin/models/EndpointSecretOut.kt new file mode 100644 index 000000000..3b153042c --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointSecretOut.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class EndpointSecretOut(val key: String) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointSecretRotateIn.kt b/kotlin/lib/src/main/kotlin/models/EndpointSecretRotateIn.kt new file mode 100644 index 000000000..d6a6f4a88 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointSecretRotateIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class EndpointSecretRotateIn(val key: String? = null) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointStats.kt b/kotlin/lib/src/main/kotlin/models/EndpointStats.kt new file mode 100644 index 000000000..a4318b881 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointStats.kt @@ -0,0 +1,7 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointStats(val fail: Long, val pending: Long, val sending: Long, val success: Long) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointTransformationIn.kt b/kotlin/lib/src/main/kotlin/models/EndpointTransformationIn.kt new file mode 100644 index 000000000..2e41bc598 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointTransformationIn.kt @@ -0,0 +1,7 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointTransformationIn(val code: String? = null, val enabled: Boolean? = null) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointTransformationOut.kt b/kotlin/lib/src/main/kotlin/models/EndpointTransformationOut.kt new file mode 100644 index 000000000..ea53091c1 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointTransformationOut.kt @@ -0,0 +1,7 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointTransformationOut(val code: String? = null, val enabled: Boolean? = null) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointUpdate.kt b/kotlin/lib/src/main/kotlin/models/EndpointUpdate.kt new file mode 100644 index 000000000..cd6a44f69 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EndpointUpdate.kt @@ -0,0 +1,17 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class EndpointUpdate( + val channels: Set? = null, + val description: String? = null, + val disabled: Boolean? = null, + val filterTypes: Set? = null, + val metadata: Map? = null, + val rateLimit: UShort? = null, + val uid: String? = null, + val url: String, + val version: UShort? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt b/kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt new file mode 100644 index 000000000..61812a2ab --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EnvironmentIn( + val eventTypes: List? = null, + val settings: JsonObject? = null, + val transformationTemplates: List? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt b/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt new file mode 100644 index 000000000..2a2e4656e --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt @@ -0,0 +1,15 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EnvironmentOut( + val createdAt: Instant, + val eventTypes: List, + val settings: JsonObject, + val transformationTemplates: List, + val version: Long? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EventExampleIn.kt b/kotlin/lib/src/main/kotlin/models/EventExampleIn.kt new file mode 100644 index 000000000..2288bbe98 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventExampleIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class EventExampleIn(val eventType: String, val exampleIndex: ULong? = null) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt b/kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt new file mode 100644 index 000000000..559420365 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt @@ -0,0 +1,15 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EventTypeFromOpenApi( + val deprecated: Boolean, + val description: String, + val featureFlag: String? = null, + val groupName: String? = null, + val name: String, + val schemas: JsonObject? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt new file mode 100644 index 000000000..fe7b8ac6a --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt @@ -0,0 +1,13 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EventTypeImportOpenApiIn( + val dryRun: Boolean? = null, + val replaceAll: Boolean? = null, + val spec: JsonObject? = null, + val specRaw: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOut.kt b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOut.kt new file mode 100644 index 000000000..2c8dcafd5 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOut.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class EventTypeImportOpenApiOut(val data: EventTypeImportOpenApiOutData) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOutData.kt b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOutData.kt new file mode 100644 index 000000000..e9cf83e02 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiOutData.kt @@ -0,0 +1,11 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class EventTypeImportOpenApiOutData( + val modified: List, + @SerialName("to_modify") val toModify: List? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeIn.kt b/kotlin/lib/src/main/kotlin/models/EventTypeIn.kt new file mode 100644 index 000000000..d940bb6f4 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypeIn.kt @@ -0,0 +1,16 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EventTypeIn( + val archived: Boolean? = null, + val deprecated: Boolean? = null, + val description: String, + val featureFlag: String? = null, + val groupName: String? = null, + val name: String, + val schemas: JsonObject? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeOut.kt b/kotlin/lib/src/main/kotlin/models/EventTypeOut.kt new file mode 100644 index 000000000..20dadbbd3 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypeOut.kt @@ -0,0 +1,19 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EventTypeOut( + val archived: Boolean? = null, + val createdAt: Instant, + val deprecated: Boolean, + val description: String, + val featureFlag: String? = null, + val groupName: String? = null, + val name: String, + val schemas: JsonObject? = null, + val updatedAt: Instant, +) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt b/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt new file mode 100644 index 000000000..b961e5086 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt @@ -0,0 +1,16 @@ +// This file is @generated +package com.svix.kotlin.models + +import com.svix.kotlin.MaybeUnset +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EventTypePatch( + val archived: Boolean? = null, + val deprecated: Boolean? = null, + val description: String? = null, + val featureFlag: MaybeUnset = MaybeUnset.Undefined, + val groupName: MaybeUnset = MaybeUnset.Undefined, + val schemas: MaybeUnset = MaybeUnset.Undefined, +) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt b/kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt new file mode 100644 index 000000000..a9d2ed402 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt @@ -0,0 +1,15 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class EventTypeUpdate( + val archived: Boolean? = null, + val deprecated: Boolean? = null, + val description: String, + val featureFlag: String? = null, + val groupName: String? = null, + val schemas: JsonObject? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/IntegrationIn.kt b/kotlin/lib/src/main/kotlin/models/IntegrationIn.kt new file mode 100644 index 000000000..5292b7b50 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/IntegrationIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class IntegrationIn(val name: String) diff --git a/kotlin/lib/src/main/kotlin/models/IntegrationKeyOut.kt b/kotlin/lib/src/main/kotlin/models/IntegrationKeyOut.kt new file mode 100644 index 000000000..c65d62177 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/IntegrationKeyOut.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class IntegrationKeyOut(val key: String) diff --git a/kotlin/lib/src/main/kotlin/models/IntegrationOut.kt b/kotlin/lib/src/main/kotlin/models/IntegrationOut.kt new file mode 100644 index 000000000..246b6ba71 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/IntegrationOut.kt @@ -0,0 +1,13 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class IntegrationOut( + val createdAt: Instant, + val id: String, + val name: String, + val updatedAt: Instant, +) diff --git a/kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt b/kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt new file mode 100644 index 000000000..3a782217a --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class IntegrationUpdate(val name: String) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt new file mode 100644 index 000000000..058aeff04 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseApplicationOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt new file mode 100644 index 000000000..33cafcc58 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseBackgroundTaskOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt new file mode 100644 index 000000000..3af6efab0 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseEndpointMessageOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt new file mode 100644 index 000000000..5d36c2778 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseEndpointOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt new file mode 100644 index 000000000..416754c14 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseEventTypeOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt new file mode 100644 index 000000000..6c544f58b --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseIntegrationOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt new file mode 100644 index 000000000..db7fe3b88 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseMessageAttemptOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt new file mode 100644 index 000000000..0e3123a98 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseMessageEndpointOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt new file mode 100644 index 000000000..6e4d1795d --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseMessageOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt new file mode 100644 index 000000000..a22ad5567 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt @@ -0,0 +1,12 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ListResponseOperationalWebhookEndpointOut( + val data: List, + val done: Boolean, + val iterator: String, + val prevIterator: String? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/MessageAttemptOut.kt b/kotlin/lib/src/main/kotlin/models/MessageAttemptOut.kt new file mode 100644 index 000000000..9afda1b23 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/MessageAttemptOut.kt @@ -0,0 +1,20 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class MessageAttemptOut( + val endpointId: String, + val id: String, + val msg: MessageOut? = null, + val msgId: String, + val response: String, + val responseDurationMs: Long, + val responseStatusCode: Short, + val status: MessageStatus, + val timestamp: Instant, + val triggerType: MessageAttemptTriggerType, + val url: String, +) diff --git a/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt b/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt new file mode 100644 index 000000000..c5e25705c --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt @@ -0,0 +1,41 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.encoding.* + +public enum class MessageAttemptTriggerType { + SCHEDULED, + MANUAL, +} + +object MessageAttemptTriggerTypeSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor( + "com.svix.kotlin.models.MessageAttemptTriggerTypeSerializer", + PrimitiveKind.LONG, + ) + + override fun serialize(encoder: Encoder, value: MessageAttemptTriggerType) { + val vAsLong = + when (value) { + MessageAttemptTriggerType.SCHEDULED -> 0L + MessageAttemptTriggerType.MANUAL -> 1L + } + encoder.encodeLong(vAsLong) + } + + override fun deserialize(decoder: Decoder): MessageAttemptTriggerType { + return when (val vAsLong = decoder.decodeLong()) { + 0L -> MessageAttemptTriggerType.SCHEDULED + 1L -> MessageAttemptTriggerType.MANUAL + else -> { + throw SerializationException( + "$vAsLong is not a valid value for MessageAttemptTriggerType" + ) + } + } + } +} diff --git a/kotlin/lib/src/main/kotlin/models/MessageEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/MessageEndpointOut.kt new file mode 100644 index 000000000..937c788c8 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/MessageEndpointOut.kt @@ -0,0 +1,22 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class MessageEndpointOut( + val channels: Set? = null, + val createdAt: Instant, + val description: String, + val disabled: Boolean? = null, + val filterTypes: Set? = null, + val id: String, + val nextAttempt: Instant? = null, + val rateLimit: UShort? = null, + val status: MessageStatus, + val uid: String? = null, + val updatedAt: Instant, + val url: String, + val version: Int, +) diff --git a/kotlin/lib/src/main/kotlin/models/MessageIn.kt b/kotlin/lib/src/main/kotlin/models/MessageIn.kt new file mode 100644 index 000000000..b9186979f --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/MessageIn.kt @@ -0,0 +1,18 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class MessageIn( + val application: ApplicationIn? = null, + val channels: Set? = null, + val eventId: String? = null, + val eventType: String, + val payload: JsonObject, + val payloadRetentionHours: Long? = null, + val payloadRetentionPeriod: Long? = null, + val tags: Set? = null, + val transformationsParams: JsonObject? = null, +) diff --git a/kotlin/lib/src/main/kotlin/models/MessageOut.kt b/kotlin/lib/src/main/kotlin/models/MessageOut.kt new file mode 100644 index 000000000..c3aeeb603 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/MessageOut.kt @@ -0,0 +1,17 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonObject + +@Serializable +data class MessageOut( + val channels: Set? = null, + val eventId: String? = null, + val eventType: String, + val id: String, + val payload: JsonObject, + val tags: Set? = null, + val timestamp: Instant, +) diff --git a/kotlin/lib/src/main/kotlin/models/MessageStatus.kt b/kotlin/lib/src/main/kotlin/models/MessageStatus.kt new file mode 100644 index 000000000..c9206d3ea --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/MessageStatus.kt @@ -0,0 +1,45 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.encoding.* + +public enum class MessageStatus { + SUCCESS, + PENDING, + FAIL, + SENDING, +} + +object MessageStatusSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor( + "com.svix.kotlin.models.MessageStatusSerializer", + PrimitiveKind.LONG, + ) + + override fun serialize(encoder: Encoder, value: MessageStatus) { + val vAsLong = + when (value) { + MessageStatus.SUCCESS -> 0L + MessageStatus.PENDING -> 1L + MessageStatus.FAIL -> 2L + MessageStatus.SENDING -> 3L + } + encoder.encodeLong(vAsLong) + } + + override fun deserialize(decoder: Decoder): MessageStatus { + return when (val vAsLong = decoder.decodeLong()) { + 0L -> MessageStatus.SUCCESS + 1L -> MessageStatus.PENDING + 2L -> MessageStatus.FAIL + 3L -> MessageStatus.SENDING + else -> { + throw SerializationException("$vAsLong is not a valid value for MessageStatus") + } + } + } +} diff --git a/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersIn.kt b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersIn.kt new file mode 100644 index 000000000..275a13102 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class OperationalWebhookEndpointHeadersIn(val headers: Map) diff --git a/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersOut.kt b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersOut.kt new file mode 100644 index 000000000..41afe4171 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointHeadersOut.kt @@ -0,0 +1,10 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class OperationalWebhookEndpointHeadersOut( + val headers: Map, + val sensitive: Set, +) diff --git a/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointIn.kt b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointIn.kt new file mode 100644 index 000000000..31deb534f --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointIn.kt @@ -0,0 +1,16 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class OperationalWebhookEndpointIn( + val description: String? = null, + val disabled: Boolean? = null, + val filterTypes: Set? = null, + val metadata: Map? = null, + val rateLimit: UShort? = null, + val secret: String? = null, + val uid: String? = null, + val url: String, +) diff --git a/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointOut.kt new file mode 100644 index 000000000..30d4bd941 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointOut.kt @@ -0,0 +1,19 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class OperationalWebhookEndpointOut( + val createdAt: Instant, + val description: String, + val disabled: Boolean? = null, + val filterTypes: Set? = null, + val id: String, + val metadata: Map, + val rateLimit: UShort? = null, + val uid: String? = null, + val updatedAt: Instant, + val url: String, +) diff --git a/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretIn.kt b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretIn.kt new file mode 100644 index 000000000..e3f941e95 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretIn.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class OperationalWebhookEndpointSecretIn(val key: String? = null) diff --git a/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretOut.kt b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretOut.kt new file mode 100644 index 000000000..9e05139cb --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointSecretOut.kt @@ -0,0 +1,6 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable data class OperationalWebhookEndpointSecretOut(val key: String) diff --git a/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointUpdate.kt b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointUpdate.kt new file mode 100644 index 000000000..66d0ffd41 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/OperationalWebhookEndpointUpdate.kt @@ -0,0 +1,15 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class OperationalWebhookEndpointUpdate( + val description: String? = null, + val disabled: Boolean? = null, + val filterTypes: Set? = null, + val metadata: Map? = null, + val rateLimit: UShort? = null, + val uid: String? = null, + val url: String, +) diff --git a/kotlin/lib/src/main/kotlin/models/Ordering.kt b/kotlin/lib/src/main/kotlin/models/Ordering.kt new file mode 100644 index 000000000..d350411b7 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/Ordering.kt @@ -0,0 +1,9 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.SerialName + +public enum class Ordering { + @SerialName("ascending") ASCENDING, + @SerialName("descending") DESCENDING, +} diff --git a/kotlin/lib/src/main/kotlin/models/RecoverIn.kt b/kotlin/lib/src/main/kotlin/models/RecoverIn.kt new file mode 100644 index 000000000..430071701 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/RecoverIn.kt @@ -0,0 +1,7 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable data class RecoverIn(val since: Instant, val until: Instant? = null) diff --git a/kotlin/lib/src/main/kotlin/models/RecoverOut.kt b/kotlin/lib/src/main/kotlin/models/RecoverOut.kt new file mode 100644 index 000000000..3da31f813 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/RecoverOut.kt @@ -0,0 +1,11 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class RecoverOut( + val id: String, + val status: BackgroundTaskStatus, + val task: BackgroundTaskType, +) diff --git a/kotlin/lib/src/main/kotlin/models/ReplayIn.kt b/kotlin/lib/src/main/kotlin/models/ReplayIn.kt new file mode 100644 index 000000000..eb8d6092d --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ReplayIn.kt @@ -0,0 +1,7 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable data class ReplayIn(val since: Instant, val until: Instant? = null) diff --git a/kotlin/lib/src/main/kotlin/models/ReplayOut.kt b/kotlin/lib/src/main/kotlin/models/ReplayOut.kt new file mode 100644 index 000000000..44a8cc7e1 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ReplayOut.kt @@ -0,0 +1,11 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ReplayOut( + val id: String, + val status: BackgroundTaskStatus, + val task: BackgroundTaskType, +) diff --git a/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt b/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt new file mode 100644 index 000000000..3b6e6b22a --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt @@ -0,0 +1,51 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.KSerializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.encoding.* + +public enum class StatusCodeClass { + CODE_NONE, + CODE1XX, + CODE2XX, + CODE3XX, + CODE4XX, + CODE5XX, +} + +object StatusCodeClassSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor( + "com.svix.kotlin.models.StatusCodeClassSerializer", + PrimitiveKind.LONG, + ) + + override fun serialize(encoder: Encoder, value: StatusCodeClass) { + val vAsLong = + when (value) { + StatusCodeClass.CODE_NONE -> 0L + StatusCodeClass.CODE1XX -> 100L + StatusCodeClass.CODE2XX -> 200L + StatusCodeClass.CODE3XX -> 300L + StatusCodeClass.CODE4XX -> 400L + StatusCodeClass.CODE5XX -> 500L + } + encoder.encodeLong(vAsLong) + } + + override fun deserialize(decoder: Decoder): StatusCodeClass { + return when (val vAsLong = decoder.decodeLong()) { + 0L -> StatusCodeClass.CODE_NONE + 100L -> StatusCodeClass.CODE1XX + 200L -> StatusCodeClass.CODE2XX + 300L -> StatusCodeClass.CODE3XX + 400L -> StatusCodeClass.CODE4XX + 500L -> StatusCodeClass.CODE5XX + else -> { + throw SerializationException("$vAsLong is not a valid value for StatusCodeClass") + } + } + } +} diff --git a/kotlin/lib/src/main/kotlin/models/TemplateIn.kt b/kotlin/lib/src/main/kotlin/models/TemplateIn.kt new file mode 100644 index 000000000..c2ed29764 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/TemplateIn.kt @@ -0,0 +1,17 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class TemplateIn( + val description: String? = null, + val featureFlag: String? = null, + val filterTypes: Set? = null, + val instructions: String? = null, + val instructionsLink: String? = null, + val kind: TransformationTemplateKind? = null, + val logo: String, + val name: String, + val transformation: String, +) diff --git a/kotlin/lib/src/main/kotlin/models/TemplateOut.kt b/kotlin/lib/src/main/kotlin/models/TemplateOut.kt new file mode 100644 index 000000000..910e3937a --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/TemplateOut.kt @@ -0,0 +1,22 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.datetime.Instant +import kotlinx.serialization.Serializable + +@Serializable +data class TemplateOut( + val createdAt: Instant, + val description: String, + val featureFlag: String? = null, + val filterTypes: Set? = null, + val id: String, + val instructions: String, + val instructionsLink: String? = null, + val kind: TransformationTemplateKind, + val logo: String, + val name: String, + val orgId: String, + val transformation: String, + val updatedAt: Instant, +) diff --git a/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt new file mode 100644 index 000000000..95239eb95 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt @@ -0,0 +1,19 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.SerialName + +public enum class TransformationTemplateKind { + @SerialName("Custom") CUSTOM, + @SerialName("CustomerIO") CUSTOMER_IO, + @SerialName("Discord") DISCORD, + @SerialName("Hubspot") HUBSPOT, + @SerialName("Inngest") INNGEST, + @SerialName("Salesforce") SALESFORCE, + @SerialName("Segment") SEGMENT, + @SerialName("Slack") SLACK, + @SerialName("Teams") TEAMS, + @SerialName("TriggerDev") TRIGGER_DEV, + @SerialName("Windmill") WINDMILL, + @SerialName("Zapier") ZAPIER, +} From 8d5497d1bf886984a736994e1a870cd7ef2f69ff Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Tue, 11 Feb 2025 16:01:51 -0500 Subject: [PATCH 12/56] kotlin: Document breaking changes --- ChangeLog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index f2defb5e4..7da96bbfa 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased +* Libs/Kotlin **(Breaking)** Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` is removed +* Libs/Kotlin **(Breaking)**: All uses of `java.time.OffsetDateTime` replaced with `kotlinx.datetime.Instant` +* Libs/Kotlin **(Breaking)**: All uses of `java.net.URL` in request/response models are replaced with `String` +* Libs/Kotlin **(Breaking)**: All uses of `Map` in request/response models are replaced with `kotlinx.serialization.json.JsonObject` + ## Version 1.57.0 This version contains a big overhaul of the client libraries, with improved typing. From 30194d25a4e5d04f9ec7d5d5eb63272aeb709217 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 13:55:25 -0500 Subject: [PATCH 13/56] kotlin: Bump the version for these deps --- kotlin/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kotlin/build.gradle b/kotlin/build.gradle index 192bc013e..9c45e8e60 100644 --- a/kotlin/build.gradle +++ b/kotlin/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '2.1.0' + ext.kotlin_version = '2.1.10' ext.spotless_version = "6.25.0" repositories { @@ -14,7 +14,7 @@ buildscript { } plugins { - id 'org.jetbrains.kotlin.jvm' version '2.1.0' + id 'org.jetbrains.kotlin.jvm' version '2.1.10' id 'org.jetbrains.kotlin.plugin.serialization' version '2.1.10' } @@ -53,7 +53,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2" implementation "com.squareup.moshi:moshi-kotlin:1.12.0" - implementation "com.squareup.okhttp3:okhttp:4.9.1" + implementation "com.squareup.okhttp3:okhttp:4.12.0" testImplementation 'junit:junit:4.13.2' testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5:1.5.21' } From 52750cf963850efa06a6ad41362f4b819919638b Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 13:56:28 -0500 Subject: [PATCH 14/56] kotlin: Remove unused dependency on moshi --- kotlin/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/kotlin/build.gradle b/kotlin/build.gradle index 9c45e8e60..bdd6e044e 100644 --- a/kotlin/build.gradle +++ b/kotlin/build.gradle @@ -52,7 +52,6 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2" - implementation "com.squareup.moshi:moshi-kotlin:1.12.0" implementation "com.squareup.okhttp3:okhttp:4.12.0" testImplementation 'junit:junit:4.13.2' testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5:1.5.21' From 931f45c2d27f1199ebc47ab4017d2a66ffed0d1b Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 13:56:51 -0500 Subject: [PATCH 15/56] kotlin: Better debugging. (Will remove before merging) --- kotlin/lib/src/main/kotlin/SvixHttpClient.kt | 21 ++++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt index 0f372cf6e..d0663d245 100644 --- a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt +++ b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt @@ -20,9 +20,9 @@ constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map Date: Wed, 12 Feb 2025 14:40:15 -0500 Subject: [PATCH 16/56] kotlin: Format tests --- .../lib/src/test/com/svix/kotlin/BasicTest.kt | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt index 7814abde3..4a7385621 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt @@ -39,11 +39,13 @@ class BasicTest { MessageIn( eventType = "invoice.paid", payload = - JsonObject(mapOf( - "id" to JsonPrimitive( "invoice_WF7WtCLFFtd8ubcTgboSFNql"), - "status" to JsonPrimitive("paid"), - "attempt" to JsonPrimitive(2), - )), + JsonObject( + mapOf( + "id" to JsonPrimitive("invoice_WF7WtCLFFtd8ubcTgboSFNql"), + "status" to JsonPrimitive("paid"), + "attempt" to JsonPrimitive(2), + ) + ), ), ) svix.application.delete(applicationOut.id) @@ -82,10 +84,7 @@ class BasicTest { val epOut = svix.endpoint.create( appOut.id, - EndpointIn( - url = "https://example.svix.com", - channels = setOf("ch0", "ch1"), - ), + EndpointIn(url = "https://example.svix.com", channels = setOf("ch0", "ch1")), ) assertEquals(setOf("ch0", "ch1"), epOut.channels, "initial ep should have 2 channels") assertEquals(0, epOut.filterTypes?.size ?: 0, "initial ep should have 0 filter types") @@ -93,7 +92,9 @@ class BasicTest { svix.endpoint.patch( appOut.id, epOut.id, - EndpointPatch(filterTypes = MaybeUnset.Present(setOf("event.started", "event.ended"))), + EndpointPatch( + filterTypes = MaybeUnset.Present(setOf("event.started", "event.ended")) + ), ) assertEquals( setOf("ch0", "ch1"), From 0e15b16126dc7ee484815a8648799aa795c09374 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 15:43:20 -0500 Subject: [PATCH 17/56] kotlin: Make string enums serializable, and add a toString method --- .../lib/src/main/kotlin/models/BackgroundTaskStatus.kt | 9 ++++++++- kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt | 9 ++++++++- kotlin/lib/src/main/kotlin/models/Ordering.kt | 9 ++++++++- .../src/main/kotlin/models/TransformationTemplateKind.kt | 9 ++++++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt index 211babb47..ccc26416a 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt @@ -2,9 +2,16 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive +@Serializable public enum class BackgroundTaskStatus { @SerialName("running") RUNNING, @SerialName("finished") FINISHED, - @SerialName("failed") FAILED, + @SerialName("failed") FAILED; + + override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content } diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt index 23b8741a8..6c811abef 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt @@ -2,12 +2,19 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive +@Serializable public enum class BackgroundTaskType { @SerialName("endpoint.replay") ENDPOINT_REPLAY, @SerialName("endpoint.recover") ENDPOINT_RECOVER, @SerialName("application.stats") APPLICATION_STATS, @SerialName("message.broadcast") MESSAGE_BROADCAST, @SerialName("sdk.generate") SDK_GENERATE, - @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE, + @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE; + + override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content } diff --git a/kotlin/lib/src/main/kotlin/models/Ordering.kt b/kotlin/lib/src/main/kotlin/models/Ordering.kt index d350411b7..fab40ea36 100644 --- a/kotlin/lib/src/main/kotlin/models/Ordering.kt +++ b/kotlin/lib/src/main/kotlin/models/Ordering.kt @@ -2,8 +2,15 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive +@Serializable public enum class Ordering { @SerialName("ascending") ASCENDING, - @SerialName("descending") DESCENDING, + @SerialName("descending") DESCENDING; + + override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content } diff --git a/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt index 95239eb95..5241a3c6a 100644 --- a/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt +++ b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt @@ -2,7 +2,12 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive +@Serializable public enum class TransformationTemplateKind { @SerialName("Custom") CUSTOM, @SerialName("CustomerIO") CUSTOMER_IO, @@ -15,5 +20,7 @@ public enum class TransformationTemplateKind { @SerialName("Teams") TEAMS, @SerialName("TriggerDev") TRIGGER_DEV, @SerialName("Windmill") WINDMILL, - @SerialName("Zapier") ZAPIER, + @SerialName("Zapier") ZAPIER; + + override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content } From 9ee2ddfce1e9499d488b61009c50abcf63d4def0 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 16:12:26 -0500 Subject: [PATCH 18/56] kotlin: Mark int enums as @Serializable Also remove toString from string enums, This will be done elsewhere --- kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt | 7 +------ kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt | 7 +------ .../src/main/kotlin/models/MessageAttemptTriggerType.kt | 2 ++ kotlin/lib/src/main/kotlin/models/MessageStatus.kt | 2 ++ kotlin/lib/src/main/kotlin/models/Ordering.kt | 7 +------ kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt | 2 ++ .../src/main/kotlin/models/TransformationTemplateKind.kt | 7 +------ 7 files changed, 10 insertions(+), 24 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt index ccc26416a..d846700e7 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt @@ -3,15 +3,10 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.encodeToJsonElement -import kotlinx.serialization.json.jsonPrimitive @Serializable public enum class BackgroundTaskStatus { @SerialName("running") RUNNING, @SerialName("finished") FINISHED, - @SerialName("failed") FAILED; - - override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content + @SerialName("failed") FAILED, } diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt index 6c811abef..9494abbb2 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt @@ -3,9 +3,6 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.encodeToJsonElement -import kotlinx.serialization.json.jsonPrimitive @Serializable public enum class BackgroundTaskType { @@ -14,7 +11,5 @@ public enum class BackgroundTaskType { @SerialName("application.stats") APPLICATION_STATS, @SerialName("message.broadcast") MESSAGE_BROADCAST, @SerialName("sdk.generate") SDK_GENERATE, - @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE; - - override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content + @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE, } diff --git a/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt b/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt index c5e25705c..578379679 100644 --- a/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt +++ b/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt @@ -2,10 +2,12 @@ package com.svix.kotlin.models import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* +@Serializable(with = MessageAttemptTriggerTypeSerializer::class) public enum class MessageAttemptTriggerType { SCHEDULED, MANUAL, diff --git a/kotlin/lib/src/main/kotlin/models/MessageStatus.kt b/kotlin/lib/src/main/kotlin/models/MessageStatus.kt index c9206d3ea..30339656b 100644 --- a/kotlin/lib/src/main/kotlin/models/MessageStatus.kt +++ b/kotlin/lib/src/main/kotlin/models/MessageStatus.kt @@ -2,10 +2,12 @@ package com.svix.kotlin.models import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* +@Serializable(with = MessageStatusSerializer::class) public enum class MessageStatus { SUCCESS, PENDING, diff --git a/kotlin/lib/src/main/kotlin/models/Ordering.kt b/kotlin/lib/src/main/kotlin/models/Ordering.kt index fab40ea36..bb3990b0e 100644 --- a/kotlin/lib/src/main/kotlin/models/Ordering.kt +++ b/kotlin/lib/src/main/kotlin/models/Ordering.kt @@ -3,14 +3,9 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.encodeToJsonElement -import kotlinx.serialization.json.jsonPrimitive @Serializable public enum class Ordering { @SerialName("ascending") ASCENDING, - @SerialName("descending") DESCENDING; - - override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content + @SerialName("descending") DESCENDING, } diff --git a/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt b/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt index 3b6e6b22a..7ec22f283 100644 --- a/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt +++ b/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt @@ -2,10 +2,12 @@ package com.svix.kotlin.models import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* +@Serializable(with = StatusCodeClassSerializer::class) public enum class StatusCodeClass { CODE_NONE, CODE1XX, diff --git a/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt index 5241a3c6a..c7009e22a 100644 --- a/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt +++ b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt @@ -3,9 +3,6 @@ package com.svix.kotlin.models import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.encodeToJsonElement -import kotlinx.serialization.json.jsonPrimitive @Serializable public enum class TransformationTemplateKind { @@ -20,7 +17,5 @@ public enum class TransformationTemplateKind { @SerialName("Teams") TEAMS, @SerialName("TriggerDev") TRIGGER_DEV, @SerialName("Windmill") WINDMILL, - @SerialName("Zapier") ZAPIER; - - override fun toString(): String = Json.encodeToJsonElement(this).jsonPrimitive.content + @SerialName("Zapier") ZAPIER, } From e3ce4aea70d843b8d75b679c4cd62aabd8fcd3cf Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 16:18:20 -0500 Subject: [PATCH 19/56] kotlin: Add serializeQueryParam util --- kotlin/lib/src/main/kotlin/Utils.kt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 kotlin/lib/src/main/kotlin/Utils.kt diff --git a/kotlin/lib/src/main/kotlin/Utils.kt b/kotlin/lib/src/main/kotlin/Utils.kt new file mode 100644 index 000000000..e3c7b4380 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/Utils.kt @@ -0,0 +1,18 @@ +package com.svix.kotlin + +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive +import kotlin.reflect.full.isSubclassOf + +private fun isEnum(v: Any?): Boolean { + return v != null && v::class.isSubclassOf(Enum::class) +} + +internal fun serializeQueryParam(v: Any): String { + return if (isEnum(v)) { + Json.encodeToJsonElement(v).jsonPrimitive.content + } else { + v.toString() + } +} From f5023978f8129cb92b04637a23c7a6c125ec8221 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 16:19:48 -0500 Subject: [PATCH 20/56] kotlin: use `serializeQueryParam` for none string query params --- kotlin/lib/src/main/kotlin/Application.kt | 4 +- kotlin/lib/src/main/kotlin/BackgroundTask.kt | 8 +-- kotlin/lib/src/main/kotlin/Endpoint.kt | 8 +-- kotlin/lib/src/main/kotlin/EventType.kt | 12 ++-- kotlin/lib/src/main/kotlin/Integration.kt | 4 +- kotlin/lib/src/main/kotlin/Message.kt | 22 +++++--- kotlin/lib/src/main/kotlin/MessageAttempt.kt | 56 +++++++++++-------- .../main/kotlin/OperationalWebhookEndpoint.kt | 4 +- 8 files changed, 70 insertions(+), 48 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Application.kt b/kotlin/lib/src/main/kotlin/Application.kt index 50e724a0e..52581237c 100644 --- a/kotlin/lib/src/main/kotlin/Application.kt +++ b/kotlin/lib/src/main/kotlin/Application.kt @@ -25,9 +25,9 @@ class Application(baseUrl: HttpUrl, defaultHeaders: Map) : options: ApplicationListOptions = ApplicationListOptions() ): ListResponseApplicationOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", it.toString()) } + options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } return this.executeRequest("GET", url.build()) } diff --git a/kotlin/lib/src/main/kotlin/BackgroundTask.kt b/kotlin/lib/src/main/kotlin/BackgroundTask.kt index 63fe44e47..40e89c89c 100644 --- a/kotlin/lib/src/main/kotlin/BackgroundTask.kt +++ b/kotlin/lib/src/main/kotlin/BackgroundTask.kt @@ -24,11 +24,11 @@ class BackgroundTask(baseUrl: HttpUrl, defaultHeaders: Map) : options: BackgroundTaskListOptions = BackgroundTaskListOptions() ): ListResponseBackgroundTaskOut { var url = this.newUrlBuilder().encodedPath("/api/v1/background-task") - options.status?.let { url = url.addQueryParameter("status", it.toString()) } - options.task?.let { url = url.addQueryParameter("task", it.toString()) } - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } + options.task?.let { url = url.addQueryParameter("task", serializeQueryParam(it)) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", it.toString()) } + options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } return this.executeRequest("GET", url.build()) } diff --git a/kotlin/lib/src/main/kotlin/Endpoint.kt b/kotlin/lib/src/main/kotlin/Endpoint.kt index dbab1a844..bdb66d734 100644 --- a/kotlin/lib/src/main/kotlin/Endpoint.kt +++ b/kotlin/lib/src/main/kotlin/Endpoint.kt @@ -52,9 +52,9 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : options: EndpointListOptions = EndpointListOptions(), ): ListResponseEndpointOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", it.toString()) } + options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } return this.executeRequest("GET", url.build()) } @@ -274,8 +274,8 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : options: EndpointGetStatsOptions = EndpointGetStatsOptions(), ): EndpointStats { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/stats") - options.since?.let { url = url.addQueryParameter("since", it.toString()) } - options.until?.let { url = url.addQueryParameter("until", it.toString()) } + options.since?.let { url = url.addQueryParameter("since", serializeQueryParam(it)) } + options.until?.let { url = url.addQueryParameter("until", serializeQueryParam(it)) } return this.executeRequest("GET", url.build()) } diff --git a/kotlin/lib/src/main/kotlin/EventType.kt b/kotlin/lib/src/main/kotlin/EventType.kt index c8d275d7e..4a5dbb819 100644 --- a/kotlin/lib/src/main/kotlin/EventType.kt +++ b/kotlin/lib/src/main/kotlin/EventType.kt @@ -34,13 +34,15 @@ class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : options: EventTypeListOptions = EventTypeListOptions() ): ListResponseEventTypeOut { var url = this.newUrlBuilder().encodedPath("/api/v1/event-type") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", it.toString()) } + options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } options.includeArchived?.let { - url = url.addQueryParameter("include_archived", it.toString()) + url = url.addQueryParameter("include_archived", serializeQueryParam(it)) + } + options.withContent?.let { + url = url.addQueryParameter("with_content", serializeQueryParam(it)) } - options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } return this.executeRequest("GET", url.build()) } @@ -120,7 +122,7 @@ class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : options: EventTypeDeleteOptions = EventTypeDeleteOptions(), ) { var url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") - options.expunge?.let { url = url.addQueryParameter("expunge", it.toString()) } + options.expunge?.let { url = url.addQueryParameter("expunge", serializeQueryParam(it)) } this.executeRequest("DELETE", url.build()) } diff --git a/kotlin/lib/src/main/kotlin/Integration.kt b/kotlin/lib/src/main/kotlin/Integration.kt index 503930c37..cbc8d96f4 100644 --- a/kotlin/lib/src/main/kotlin/Integration.kt +++ b/kotlin/lib/src/main/kotlin/Integration.kt @@ -29,9 +29,9 @@ class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : options: IntegrationListOptions = IntegrationListOptions(), ): ListResponseIntegrationOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", it.toString()) } + options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } return this.executeRequest("GET", url.build()) } diff --git a/kotlin/lib/src/main/kotlin/Message.kt b/kotlin/lib/src/main/kotlin/Message.kt index 87d5c2f8c..0da159488 100644 --- a/kotlin/lib/src/main/kotlin/Message.kt +++ b/kotlin/lib/src/main/kotlin/Message.kt @@ -46,14 +46,18 @@ class Message(baseUrl: HttpUrl, defaultHeaders: Map) : options: MessageListOptions = MessageListOptions(), ): ListResponseMessageOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } options.channel?.let { url = url.addQueryParameter("channel", it) } - options.before?.let { url = url.addQueryParameter("before", it.toString()) } - options.after?.let { url = url.addQueryParameter("after", it.toString()) } - options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { + url = url.addQueryParameter("with_content", serializeQueryParam(it)) + } options.tag?.let { url = url.addQueryParameter("tag", it) } - options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + options.eventTypes?.let { + url = url.addQueryParameter("event_types", serializeQueryParam(it)) + } return this.executeRequest("GET", url.build()) } @@ -80,7 +84,9 @@ class Message(baseUrl: HttpUrl, defaultHeaders: Map) : options: MessageCreateOptions = MessageCreateOptions(), ): MessageOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") - options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + options.withContent?.let { + url = url.addQueryParameter("with_content", serializeQueryParam(it)) + } var headers = Headers.Builder() options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } @@ -99,7 +105,9 @@ class Message(baseUrl: HttpUrl, defaultHeaders: Map) : options: MessageGetOptions = MessageGetOptions(), ): MessageOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId") - options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } + options.withContent?.let { + url = url.addQueryParameter("with_content", serializeQueryParam(it)) + } return this.executeRequest("GET", url.build()) } diff --git a/kotlin/lib/src/main/kotlin/MessageAttempt.kt b/kotlin/lib/src/main/kotlin/MessageAttempt.kt index ee2b3a2fd..a76689723 100644 --- a/kotlin/lib/src/main/kotlin/MessageAttempt.kt +++ b/kotlin/lib/src/main/kotlin/MessageAttempt.kt @@ -76,19 +76,23 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : ): ListResponseMessageAttemptOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/endpoint/$endpointId") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.status?.let { url = url.addQueryParameter("status", it.toString()) } + options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } options.statusCodeClass?.let { - url = url.addQueryParameter("status_code_class", it.toString()) + url = url.addQueryParameter("status_code_class", serializeQueryParam(it)) } options.channel?.let { url = url.addQueryParameter("channel", it) } options.tag?.let { url = url.addQueryParameter("tag", it) } - options.before?.let { url = url.addQueryParameter("before", it.toString()) } - options.after?.let { url = url.addQueryParameter("after", it.toString()) } - options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } - options.withMsg?.let { url = url.addQueryParameter("with_msg", it.toString()) } - options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { + url = url.addQueryParameter("with_content", serializeQueryParam(it)) + } + options.withMsg?.let { url = url.addQueryParameter("with_msg", serializeQueryParam(it)) } + options.eventTypes?.let { + url = url.addQueryParameter("event_types", serializeQueryParam(it)) + } return this.executeRequest("GET", url.build()) } @@ -106,19 +110,23 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : options: MessageAttemptListByMsgOptions = MessageAttemptListByMsgOptions(), ): ListResponseMessageAttemptOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/msg/$msgId") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.status?.let { url = url.addQueryParameter("status", it.toString()) } + options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } options.statusCodeClass?.let { - url = url.addQueryParameter("status_code_class", it.toString()) + url = url.addQueryParameter("status_code_class", serializeQueryParam(it)) } options.channel?.let { url = url.addQueryParameter("channel", it) } options.tag?.let { url = url.addQueryParameter("tag", it) } options.endpointId?.let { url = url.addQueryParameter("endpoint_id", it) } - options.before?.let { url = url.addQueryParameter("before", it.toString()) } - options.after?.let { url = url.addQueryParameter("after", it.toString()) } - options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } - options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { + url = url.addQueryParameter("with_content", serializeQueryParam(it)) + } + options.eventTypes?.let { + url = url.addQueryParameter("event_types", serializeQueryParam(it)) + } return this.executeRequest("GET", url.build()) } @@ -141,15 +149,19 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : MessageAttemptListAttemptedMessagesOptions(), ): ListResponseEndpointMessageOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/msg") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } options.channel?.let { url = url.addQueryParameter("channel", it) } options.tag?.let { url = url.addQueryParameter("tag", it) } - options.status?.let { url = url.addQueryParameter("status", it.toString()) } - options.before?.let { url = url.addQueryParameter("before", it.toString()) } - options.after?.let { url = url.addQueryParameter("after", it.toString()) } - options.withContent?.let { url = url.addQueryParameter("with_content", it.toString()) } - options.eventTypes?.let { url = url.addQueryParameter("event_types", it.toString()) } + options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } + options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { + url = url.addQueryParameter("with_content", serializeQueryParam(it)) + } + options.eventTypes?.let { + url = url.addQueryParameter("event_types", serializeQueryParam(it)) + } return this.executeRequest("GET", url.build()) } @@ -186,7 +198,7 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : MessageAttemptListAttemptedDestinationsOptions(), ): ListResponseMessageEndpointOut { var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/endpoint") - options.limit?.let { url = url.addQueryParameter("limit", it.toString()) } + options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } options.iterator?.let { url = url.addQueryParameter("iterator", it) } return this.executeRequest("GET", url.build()) } diff --git a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt index 67820e71d..5aee049dc 100644 --- a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt +++ b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt @@ -31,9 +31,9 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map( "GET", url.build(), From f32942ef398ca2e0f9188206021c9791a347c265 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 16:24:30 -0500 Subject: [PATCH 21/56] kotlin: Comma separate list/set params in url query --- kotlin/lib/src/main/kotlin/Utils.kt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/kotlin/lib/src/main/kotlin/Utils.kt b/kotlin/lib/src/main/kotlin/Utils.kt index e3c7b4380..d622dbea1 100644 --- a/kotlin/lib/src/main/kotlin/Utils.kt +++ b/kotlin/lib/src/main/kotlin/Utils.kt @@ -1,17 +1,29 @@ package com.svix.kotlin +import kotlin.reflect.full.isSubclassOf import kotlinx.serialization.json.Json import kotlinx.serialization.json.encodeToJsonElement import kotlinx.serialization.json.jsonPrimitive -import kotlin.reflect.full.isSubclassOf private fun isEnum(v: Any?): Boolean { return v != null && v::class.isSubclassOf(Enum::class) } +private fun isList(v: Any?): Boolean { + return v != null && v::class.isSubclassOf(List::class) +} + +private fun isSet(v: Any?): Boolean { + return v != null && v::class.isSubclassOf(Set::class) +} + internal fun serializeQueryParam(v: Any): String { return if (isEnum(v)) { Json.encodeToJsonElement(v).jsonPrimitive.content + } else if (isList(v)) { + (v as List<*>).joinToString(",") + } else if (isSet(v)) { + (v as Set<*>).joinToString(",") } else { v.toString() } From a38b5938efd81a8aa310577b51af21c879c77190 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 16:40:48 -0500 Subject: [PATCH 22/56] kotlin: Add `toQueryParam` on enums --- kotlin/lib/src/main/kotlin/Utils.kt | 11 +++++++---- .../src/main/kotlin/models/BackgroundTaskStatus.kt | 10 ++++++++-- .../lib/src/main/kotlin/models/BackgroundTaskType.kt | 10 ++++++++-- .../main/kotlin/models/MessageAttemptTriggerType.kt | 10 ++++++++-- kotlin/lib/src/main/kotlin/models/MessageStatus.kt | 10 ++++++++-- kotlin/lib/src/main/kotlin/models/Ordering.kt | 10 ++++++++-- kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt | 10 ++++++++-- .../main/kotlin/models/TransformationTemplateKind.kt | 10 ++++++++-- 8 files changed, 63 insertions(+), 18 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Utils.kt b/kotlin/lib/src/main/kotlin/Utils.kt index d622dbea1..9e0520687 100644 --- a/kotlin/lib/src/main/kotlin/Utils.kt +++ b/kotlin/lib/src/main/kotlin/Utils.kt @@ -1,9 +1,6 @@ package com.svix.kotlin import kotlin.reflect.full.isSubclassOf -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.encodeToJsonElement -import kotlinx.serialization.json.jsonPrimitive private fun isEnum(v: Any?): Boolean { return v != null && v::class.isSubclassOf(Enum::class) @@ -19,7 +16,7 @@ private fun isSet(v: Any?): Boolean { internal fun serializeQueryParam(v: Any): String { return if (isEnum(v)) { - Json.encodeToJsonElement(v).jsonPrimitive.content + (v as ToQueryParam).toQueryParam() } else if (isList(v)) { (v as List<*>).joinToString(",") } else if (isSet(v)) { @@ -28,3 +25,9 @@ internal fun serializeQueryParam(v: Any): String { v.toString() } } + +internal interface ToQueryParam { + // Used to get the enums correct representation as a query param + // does not url encode the returned string + fun toQueryParam(): String +} diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt index d846700e7..b62f862ed 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskStatus.kt @@ -1,12 +1,18 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.ToQueryParam import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable -public enum class BackgroundTaskStatus { +enum class BackgroundTaskStatus : ToQueryParam { @SerialName("running") RUNNING, @SerialName("finished") FINISHED, - @SerialName("failed") FAILED, + @SerialName("failed") FAILED; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt index 9494abbb2..26bf4b161 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt @@ -1,15 +1,21 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.ToQueryParam import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable -public enum class BackgroundTaskType { +enum class BackgroundTaskType : ToQueryParam { @SerialName("endpoint.replay") ENDPOINT_REPLAY, @SerialName("endpoint.recover") ENDPOINT_RECOVER, @SerialName("application.stats") APPLICATION_STATS, @SerialName("message.broadcast") MESSAGE_BROADCAST, @SerialName("sdk.generate") SDK_GENERATE, - @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE, + @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } diff --git a/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt b/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt index 578379679..f4863fc9f 100644 --- a/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt +++ b/kotlin/lib/src/main/kotlin/models/MessageAttemptTriggerType.kt @@ -1,16 +1,22 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.ToQueryParam import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable(with = MessageAttemptTriggerTypeSerializer::class) -public enum class MessageAttemptTriggerType { +enum class MessageAttemptTriggerType : ToQueryParam { SCHEDULED, - MANUAL, + MANUAL; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } object MessageAttemptTriggerTypeSerializer : KSerializer { diff --git a/kotlin/lib/src/main/kotlin/models/MessageStatus.kt b/kotlin/lib/src/main/kotlin/models/MessageStatus.kt index 30339656b..6ae9a7115 100644 --- a/kotlin/lib/src/main/kotlin/models/MessageStatus.kt +++ b/kotlin/lib/src/main/kotlin/models/MessageStatus.kt @@ -1,18 +1,24 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.ToQueryParam import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable(with = MessageStatusSerializer::class) -public enum class MessageStatus { +enum class MessageStatus : ToQueryParam { SUCCESS, PENDING, FAIL, - SENDING, + SENDING; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } object MessageStatusSerializer : KSerializer { diff --git a/kotlin/lib/src/main/kotlin/models/Ordering.kt b/kotlin/lib/src/main/kotlin/models/Ordering.kt index bb3990b0e..e9e4c3bd2 100644 --- a/kotlin/lib/src/main/kotlin/models/Ordering.kt +++ b/kotlin/lib/src/main/kotlin/models/Ordering.kt @@ -1,11 +1,17 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.ToQueryParam import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable -public enum class Ordering { +enum class Ordering : ToQueryParam { @SerialName("ascending") ASCENDING, - @SerialName("descending") DESCENDING, + @SerialName("descending") DESCENDING; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } diff --git a/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt b/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt index 7ec22f283..a14a63ec6 100644 --- a/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt +++ b/kotlin/lib/src/main/kotlin/models/StatusCodeClass.kt @@ -1,20 +1,26 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.ToQueryParam import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.SerializationException import kotlinx.serialization.descriptors.* import kotlinx.serialization.encoding.* +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable(with = StatusCodeClassSerializer::class) -public enum class StatusCodeClass { +enum class StatusCodeClass : ToQueryParam { CODE_NONE, CODE1XX, CODE2XX, CODE3XX, CODE4XX, - CODE5XX, + CODE5XX; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } object StatusCodeClassSerializer : KSerializer { diff --git a/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt index c7009e22a..0994b4287 100644 --- a/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt +++ b/kotlin/lib/src/main/kotlin/models/TransformationTemplateKind.kt @@ -1,11 +1,15 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.ToQueryParam import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive @Serializable -public enum class TransformationTemplateKind { +enum class TransformationTemplateKind : ToQueryParam { @SerialName("Custom") CUSTOM, @SerialName("CustomerIO") CUSTOMER_IO, @SerialName("Discord") DISCORD, @@ -17,5 +21,7 @@ public enum class TransformationTemplateKind { @SerialName("Teams") TEAMS, @SerialName("TriggerDev") TRIGGER_DEV, @SerialName("Windmill") WINDMILL, - @SerialName("Zapier") ZAPIER, + @SerialName("Zapier") ZAPIER; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } From cc96401e618b01c881f306f3388b4b3ff9157878 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 16:56:50 -0500 Subject: [PATCH 23/56] kotlin: Sort lists/sets before comma separating and url encoding --- kotlin/lib/src/main/kotlin/Utils.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Utils.kt b/kotlin/lib/src/main/kotlin/Utils.kt index 9e0520687..79085f2aa 100644 --- a/kotlin/lib/src/main/kotlin/Utils.kt +++ b/kotlin/lib/src/main/kotlin/Utils.kt @@ -18,9 +18,15 @@ internal fun serializeQueryParam(v: Any): String { return if (isEnum(v)) { (v as ToQueryParam).toQueryParam() } else if (isList(v)) { - (v as List<*>).joinToString(",") + // sort before comma separating the values (helps me assert when testing) + (v as List).map { serializeQueryParam(it) }.sorted().joinToString(",") } else if (isSet(v)) { - (v as Set<*>).joinToString(",") + (v as Set) + .asSequence() + .map { serializeQueryParam(it) } + .toList() + .sorted() + .joinToString(",") } else { v.toString() } From a7062d845eec42c67fe9a2da0a0328720485d024 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 17:14:47 -0500 Subject: [PATCH 24/56] kotlin: Add test for query param encoding --- kotlin/build.gradle | 1 + kotlin/lib/src/main/kotlin/SvixHttpClient.kt | 8 +- .../src/test/com/svix/kotlin/WiremockTests.kt | 79 +++++++++++++++++++ .../__files/ListResponseApplicationOut.json | 1 + .../__files/ListResponseMessageOut.json | 1 + 5 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt create mode 100644 kotlin/lib/src/test/resources/__files/ListResponseApplicationOut.json create mode 100644 kotlin/lib/src/test/resources/__files/ListResponseMessageOut.json diff --git a/kotlin/build.gradle b/kotlin/build.gradle index bdd6e044e..4bb923f97 100644 --- a/kotlin/build.gradle +++ b/kotlin/build.gradle @@ -55,6 +55,7 @@ dependencies { implementation "com.squareup.okhttp3:okhttp:4.12.0" testImplementation 'junit:junit:4.13.2' testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5:1.5.21' + testImplementation "org.wiremock:wiremock:3.12.0" } jar { diff --git a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt index d0663d245..a684c8e1e 100644 --- a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt +++ b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt @@ -20,7 +20,7 @@ constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map Date: Wed, 12 Feb 2025 17:28:49 -0500 Subject: [PATCH 25/56] kotlin: Test datetime(Instant)/bools are encoded correctly --- .../src/test/com/svix/kotlin/WiremockTests.kt | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index eb1e757f6..02c0c282d 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -6,12 +6,14 @@ import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options import com.svix.kotlin.models.Ordering import kotlinx.coroutines.runBlocking +import kotlinx.datetime.Instant import org.junit.jupiter.api.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) class WiremockTests { - private val wireMockServer = WireMockServer(options().port(0).withRootDirectory("lib/src/test/resources")) + private val wireMockServer = + WireMockServer(options().port(0).withRootDirectory("lib/src/test/resources")) @BeforeAll fun beforeAll() { @@ -76,4 +78,30 @@ class WiremockTests { getRequestedFor(urlEqualTo("/api/v1/app/app_asd123/msg?event_types=key1%2Ckey3%2Ckey4")), ) } + + @Test + fun testInstantAndBoolQueryParamEncodedCorrectly() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.get(urlMatching("/api/v1/app/app_asd123/msg.*")) + .willReturn(WireMock.ok().withBodyFile("ListResponseMessageOut.json")) + ) + runBlocking { + svx.message.list( + "app_asd123", + MessageListOptions( + before = Instant.fromEpochSeconds(1739399072, 864755000), + withContent = true, + ), + ) + } + wireMockServer.verify( + 1, + getRequestedFor( + urlEqualTo( + "/api/v1/app/app_asd123/msg?before=2025-02-12T22%3A24%3A32.864755Z&with_content=true" + ) + ), + ) + } } From 4289efdaa420cfd1e793d12541c26bc87d22eed1 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 17:57:09 -0500 Subject: [PATCH 26/56] kotlin: Rename `MaybeUnset.Undefined` to `MaybeUnset.Unset` --- kotlin/lib/src/main/kotlin/MaybeUnset.kt | 7 ++++--- kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt | 4 ++-- kotlin/lib/src/main/kotlin/models/EndpointPatch.kt | 10 +++++----- kotlin/lib/src/main/kotlin/models/EventTypePatch.kt | 6 +++--- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/MaybeUnset.kt b/kotlin/lib/src/main/kotlin/MaybeUnset.kt index 7876f36b1..9f45ac0c5 100644 --- a/kotlin/lib/src/main/kotlin/MaybeUnset.kt +++ b/kotlin/lib/src/main/kotlin/MaybeUnset.kt @@ -12,7 +12,7 @@ import kotlinx.serialization.encoding.Encoder sealed class MaybeUnset { data object Null : MaybeUnset() - data object Undefined : MaybeUnset() + data object Unset : MaybeUnset() data class Present(val value: T) : MaybeUnset() } @@ -25,8 +25,9 @@ class MaybeUnsetSerializer(private val dataSerializer: KSerializer) : @OptIn(ExperimentalSerializationApi::class) override fun serialize(encoder: Encoder, value: MaybeUnset) { when (value) { - is MaybeUnset.Undefined -> - throw SerializationException("MaybeUnset.Undefined should not be serialized") + is MaybeUnset.Unset -> + throw SerializationException("MaybeUnset.Unset should not be serialized") + is MaybeUnset.Null -> encoder.encodeNull() is MaybeUnset.Present -> encoder.encodeSerializableValue(dataSerializer, value.value) else -> throw SerializationException("Unreachable") diff --git a/kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt b/kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt index fffe016c9..d97e9e75c 100644 --- a/kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt +++ b/kotlin/lib/src/main/kotlin/models/ApplicationPatch.kt @@ -8,6 +8,6 @@ import kotlinx.serialization.Serializable data class ApplicationPatch( val metadata: Map? = null, val name: String? = null, - val rateLimit: MaybeUnset = MaybeUnset.Undefined, - val uid: MaybeUnset = MaybeUnset.Undefined, + val rateLimit: MaybeUnset = MaybeUnset.Unset, + val uid: MaybeUnset = MaybeUnset.Unset, ) diff --git a/kotlin/lib/src/main/kotlin/models/EndpointPatch.kt b/kotlin/lib/src/main/kotlin/models/EndpointPatch.kt index ec9d3b4f2..142240ef8 100644 --- a/kotlin/lib/src/main/kotlin/models/EndpointPatch.kt +++ b/kotlin/lib/src/main/kotlin/models/EndpointPatch.kt @@ -6,14 +6,14 @@ import kotlinx.serialization.Serializable @Serializable data class EndpointPatch( - val channels: MaybeUnset> = MaybeUnset.Undefined, + val channels: MaybeUnset> = MaybeUnset.Unset, val description: String? = null, val disabled: Boolean? = null, - val filterTypes: MaybeUnset> = MaybeUnset.Undefined, + val filterTypes: MaybeUnset> = MaybeUnset.Unset, val metadata: Map? = null, - val rateLimit: MaybeUnset = MaybeUnset.Undefined, - val secret: MaybeUnset = MaybeUnset.Undefined, - val uid: MaybeUnset = MaybeUnset.Undefined, + val rateLimit: MaybeUnset = MaybeUnset.Unset, + val secret: MaybeUnset = MaybeUnset.Unset, + val uid: MaybeUnset = MaybeUnset.Unset, val url: String? = null, val version: UShort? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt b/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt index b961e5086..cc5a52971 100644 --- a/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt +++ b/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt @@ -10,7 +10,7 @@ data class EventTypePatch( val archived: Boolean? = null, val deprecated: Boolean? = null, val description: String? = null, - val featureFlag: MaybeUnset = MaybeUnset.Undefined, - val groupName: MaybeUnset = MaybeUnset.Undefined, - val schemas: MaybeUnset = MaybeUnset.Undefined, + val featureFlag: MaybeUnset = MaybeUnset.Unset, + val groupName: MaybeUnset = MaybeUnset.Unset, + val schemas: MaybeUnset = MaybeUnset.Unset, ) From c15c2afee2e461beafb0f3cd0cb1ac980017e1d1 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 17:57:56 -0500 Subject: [PATCH 27/56] kotlin: Add tests for MaybeUnset --- .../src/test/com/svix/kotlin/WiremockTests.kt | 44 +++++++++++++++++++ .../test/resources/__files/EndpointOut.json | 1 + 2 files changed, 45 insertions(+) create mode 100644 kotlin/lib/src/test/resources/__files/EndpointOut.json diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index 02c0c282d..a2d434edb 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -4,6 +4,7 @@ import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options +import com.svix.kotlin.models.EndpointPatch import com.svix.kotlin.models.Ordering import kotlinx.coroutines.runBlocking import kotlinx.datetime.Instant @@ -104,4 +105,47 @@ class WiremockTests { ), ) } + + @Test + fun maybeUnsetIsCorrectlySerialized() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.patch(urlMatching("/api/v1/app/ap/endpoint/endp")) + .willReturn(WireMock.ok().withBodyFile("EndpointOut.json")) + ) + runBlocking { + // MaybeUnset.Present + svx.endpoint.patch( + "ap", + "endp", + EndpointPatch(filterTypes = MaybeUnset.Present(setOf("ft1", "ft2"))), + ) + // MaybeUnset.Null + svx.endpoint.patch("ap", "endp", EndpointPatch(filterTypes = MaybeUnset.Null)) + // MaybeUnset.Unset + svx.endpoint.patch( + "ap", + "endp", + EndpointPatch(filterTypes = MaybeUnset.Unset, version = 42u), + ) + } + // MaybeUnset.Present + wireMockServer.verify( + 1, + patchRequestedFor(urlEqualTo("/api/v1/app/ap/endpoint/endp")) + .withRequestBody(equalTo("""{"filterTypes":["ft1","ft2"]}""")), + ) + // MaybeUnset.Null + wireMockServer.verify( + 1, + patchRequestedFor(urlEqualTo("/api/v1/app/ap/endpoint/endp")) + .withRequestBody(equalTo("""{"filterTypes":null}""")), + ) + // MaybeUnset.Unset + wireMockServer.verify( + 1, + patchRequestedFor(urlEqualTo("/api/v1/app/ap/endpoint/endp")) + .withRequestBody(equalTo("""{"version":42}""")), + ) + } } diff --git a/kotlin/lib/src/test/resources/__files/EndpointOut.json b/kotlin/lib/src/test/resources/__files/EndpointOut.json new file mode 100644 index 000000000..50ef7b1e6 --- /dev/null +++ b/kotlin/lib/src/test/resources/__files/EndpointOut.json @@ -0,0 +1 @@ +{"id":"ep_1srOrx2ZWZBpBUvZwXKQmoEYga2","metadata":{"property1":"string","property2":"string"},"description":"string","rateLimit":0,"uid":"unique-identifier","url":"https://example.com/webhook/","version":1,"disabled":false,"filterTypes":["user.signup","user.deleted"],"channels":["project_123","group_2"],"createdAt":"2019-08-24T14:15:22Z","updatedAt":"2019-08-24T14:15:22Z" } \ No newline at end of file From ecd79edf703a14c7116cd9a1c594d849273eabe9 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 20:20:38 -0500 Subject: [PATCH 28/56] kotlin: Add test for headers --- .../src/test/com/svix/kotlin/WiremockTests.kt | 27 +++++++++++++++++++ .../test/resources/__files/MessageOut.json | 1 + 2 files changed, 28 insertions(+) create mode 100644 kotlin/lib/src/test/resources/__files/MessageOut.json diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index a2d434edb..c02ab0882 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -5,9 +5,12 @@ import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options import com.svix.kotlin.models.EndpointPatch +import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.Ordering import kotlinx.coroutines.runBlocking import kotlinx.datetime.Instant +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive import org.junit.jupiter.api.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -148,4 +151,28 @@ class WiremockTests { .withRequestBody(equalTo("""{"version":42}""")), ) } + + @Test + fun optionsHeadersAreSent() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.post(urlMatching("/api/v1/app/ap/msg")) + .willReturn(WireMock.ok().withBodyFile("MessageOut.json")) + ) + runBlocking { + svx.message.create( + "ap", + MessageIn( + eventType = "event.test", + payload = JsonObject(mapOf("key" to JsonPrimitive("val"))), + ), + MessageCreateOptions(idempotencyKey = "key123"), + ) + } + wireMockServer.verify( + 1, + postRequestedFor(urlEqualTo("/api/v1/app/ap/msg")) + .withHeader("idempotency-key", equalTo("key123")), + ) + } } diff --git a/kotlin/lib/src/test/resources/__files/MessageOut.json b/kotlin/lib/src/test/resources/__files/MessageOut.json new file mode 100644 index 000000000..2c7a38381 --- /dev/null +++ b/kotlin/lib/src/test/resources/__files/MessageOut.json @@ -0,0 +1 @@ +{"eventId":"unique-identifier","eventType":"user.signup","payload":{"email":"test@example.com","type":"user.created","username":"test_user"},"channels":["project_123","group_2"],"id":"msg_1srOrx2ZWZBpBUvZwXKQmoEYga2","timestamp":"2019-08-24T14:15:22Z","tags":["project_1337"] } \ No newline at end of file From 403605b6897e1256750c5844b91cdb0216bad911 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 20:31:10 -0500 Subject: [PATCH 29/56] kotlin: Test user-agent is set --- kotlin/lib/src/main/kotlin/SvixHttpClient.kt | 8 ++++++-- .../lib/src/test/com/svix/kotlin/WiremockTests.kt | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt index a684c8e1e..c22a40791 100644 --- a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt +++ b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt @@ -13,7 +13,7 @@ constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map executeRequest( + internal suspend inline fun executeRequest( method: String, url: HttpUrl, headers: Headers? = null, @@ -42,7 +42,7 @@ constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map Date: Wed, 12 Feb 2025 20:48:15 -0500 Subject: [PATCH 30/56] kotlin: Rework codegen to make this look cleaner --- kotlin/lib/src/main/kotlin/Application.kt | 43 ++++--- kotlin/lib/src/main/kotlin/Authentication.kt | 36 +++--- kotlin/lib/src/main/kotlin/BackgroundTask.kt | 22 ++-- kotlin/lib/src/main/kotlin/Endpoint.kt | 110 ++++++++-------- kotlin/lib/src/main/kotlin/EventType.kt | 54 ++++---- kotlin/lib/src/main/kotlin/Integration.kt | 46 ++++--- kotlin/lib/src/main/kotlin/Message.kt | 52 ++++---- kotlin/lib/src/main/kotlin/MessageAttempt.kt | 118 ++++++++---------- .../main/kotlin/OperationalWebhookEndpoint.kt | 61 ++++----- kotlin/lib/src/main/kotlin/Statistics.kt | 16 ++- kotlin/lib/src/main/kotlin/Svix.kt | 19 +-- 11 files changed, 277 insertions(+), 300 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Application.kt b/kotlin/lib/src/main/kotlin/Application.kt index 52581237c..059c894ec 100644 --- a/kotlin/lib/src/main/kotlin/Application.kt +++ b/kotlin/lib/src/main/kotlin/Application.kt @@ -7,7 +7,6 @@ import com.svix.kotlin.models.ApplicationPatch import com.svix.kotlin.models.ListResponseApplicationOut import com.svix.kotlin.models.Ordering import okhttp3.Headers -import okhttp3.HttpUrl data class ApplicationListOptions( val limit: ULong? = null, @@ -17,18 +16,17 @@ data class ApplicationListOptions( data class ApplicationCreateOptions(val idempotencyKey: String? = null) -class Application(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class Application(private val client: SvixHttpClient) { /** List of all the organization's applications. */ suspend fun list( options: ApplicationListOptions = ApplicationListOptions() ): ListResponseApplicationOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.order?.let { url.addQueryParameter("order", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** Create a new application. */ @@ -36,11 +34,11 @@ class Application(baseUrl: HttpUrl, defaultHeaders: Map) : applicationIn: ApplicationIn, options: ApplicationCreateOptions = ApplicationCreateOptions(), ): ApplicationOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/app") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -54,13 +52,14 @@ class Application(baseUrl: HttpUrl, defaultHeaders: Map) : options: ApplicationCreateOptions = ApplicationCreateOptions(), ): ApplicationOut { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/app") .addQueryParameter("get_if_exists", "true") var headers = Headers.Builder() options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -70,15 +69,15 @@ class Application(baseUrl: HttpUrl, defaultHeaders: Map) : /** Get an application. */ suspend fun get(appId: String): ApplicationOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId") + return client.executeRequest("GET", url.build()) } /** Update an application. */ suspend fun update(appId: String, applicationIn: ApplicationIn): ApplicationOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId") - return this.executeRequest( + return client.executeRequest( "PUT", url.build(), reqBody = applicationIn, @@ -87,15 +86,15 @@ class Application(baseUrl: HttpUrl, defaultHeaders: Map) : /** Delete an application. */ suspend fun delete(appId: String) { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") - this.executeRequest("DELETE", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId") + client.executeRequest("DELETE", url.build()) } /** Partially update an application. */ suspend fun patch(appId: String, applicationPatch: ApplicationPatch): ApplicationOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId") + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId") - return this.executeRequest( + return client.executeRequest( "PATCH", url.build(), reqBody = applicationPatch, diff --git a/kotlin/lib/src/main/kotlin/Authentication.kt b/kotlin/lib/src/main/kotlin/Authentication.kt index 816fad9ea..2d4e0c4df 100644 --- a/kotlin/lib/src/main/kotlin/Authentication.kt +++ b/kotlin/lib/src/main/kotlin/Authentication.kt @@ -6,7 +6,6 @@ import com.svix.kotlin.models.AppPortalAccessOut import com.svix.kotlin.models.ApplicationTokenExpireIn import com.svix.kotlin.models.DashboardAccessOut import okhttp3.Headers -import okhttp3.HttpUrl data class AuthenticationAppPortalAccessOptions(val idempotencyKey: String? = null) @@ -16,8 +15,7 @@ data class AuthenticationDashboardAccessOptions(val idempotencyKey: String? = nu data class AuthenticationLogoutOptions(val idempotencyKey: String? = null) -class Authentication(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class Authentication(private val client: SvixHttpClient) { /** * Use this function to get magic links (and authentication codes) for connecting your users to @@ -28,11 +26,11 @@ class Authentication(baseUrl: HttpUrl, defaultHeaders: Map) : appPortalAccessIn: AppPortalAccessIn, options: AuthenticationAppPortalAccessOptions = AuthenticationAppPortalAccessOptions(), ): AppPortalAccessOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/auth/app-portal-access/$appId") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/auth/app-portal-access/$appId") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -46,11 +44,11 @@ class Authentication(baseUrl: HttpUrl, defaultHeaders: Map) : applicationTokenExpireIn: ApplicationTokenExpireIn, options: AuthenticationExpireAllOptions = AuthenticationExpireAllOptions(), ) { - val url = this.newUrlBuilder().encodedPath("/api/v1/auth/app/$appId/expire-all") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/auth/app/$appId/expire-all") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - this.executeRequest( + client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -71,10 +69,10 @@ class Authentication(baseUrl: HttpUrl, defaultHeaders: Map) : appId: String, options: AuthenticationDashboardAccessOptions = AuthenticationDashboardAccessOptions(), ): DashboardAccessOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/auth/dashboard-access/$appId") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } - return this.executeRequest( + val url = client.newUrlBuilder().encodedPath("/api/v1/auth/dashboard-access/$appId") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -87,9 +85,9 @@ class Authentication(baseUrl: HttpUrl, defaultHeaders: Map) : * Trying to log out other tokens will fail. */ suspend fun logout(options: AuthenticationLogoutOptions = AuthenticationLogoutOptions()) { - val url = this.newUrlBuilder().encodedPath("/api/v1/auth/logout") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } - this.executeRequest("POST", url.build(), headers = headers.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/auth/logout") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } + client.executeRequest("POST", url.build(), headers = headers.build()) } } diff --git a/kotlin/lib/src/main/kotlin/BackgroundTask.kt b/kotlin/lib/src/main/kotlin/BackgroundTask.kt index 40e89c89c..6a2444c9b 100644 --- a/kotlin/lib/src/main/kotlin/BackgroundTask.kt +++ b/kotlin/lib/src/main/kotlin/BackgroundTask.kt @@ -6,7 +6,6 @@ import com.svix.kotlin.models.BackgroundTaskStatus import com.svix.kotlin.models.BackgroundTaskType import com.svix.kotlin.models.ListResponseBackgroundTaskOut import com.svix.kotlin.models.Ordering -import okhttp3.HttpUrl data class BackgroundTaskListOptions( val status: BackgroundTaskStatus? = null, @@ -16,25 +15,24 @@ data class BackgroundTaskListOptions( val order: Ordering? = null, ) -class BackgroundTask(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class BackgroundTask(private val client: SvixHttpClient) { /** List background tasks executed in the past 90 days. */ suspend fun list( options: BackgroundTaskListOptions = BackgroundTaskListOptions() ): ListResponseBackgroundTaskOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/background-task") - options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } - options.task?.let { url = url.addQueryParameter("task", serializeQueryParam(it)) } - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/background-task") + options.status?.let { url.addQueryParameter("status", serializeQueryParam(it)) } + options.task?.let { url.addQueryParameter("task", serializeQueryParam(it)) } + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.order?.let { url.addQueryParameter("order", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** Get a background task by ID. */ suspend fun get(taskId: String): BackgroundTaskOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/background-task/$taskId") - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/background-task/$taskId") + return client.executeRequest("GET", url.build()) } } diff --git a/kotlin/lib/src/main/kotlin/Endpoint.kt b/kotlin/lib/src/main/kotlin/Endpoint.kt index bdb66d734..7fb29fd46 100644 --- a/kotlin/lib/src/main/kotlin/Endpoint.kt +++ b/kotlin/lib/src/main/kotlin/Endpoint.kt @@ -23,7 +23,6 @@ import com.svix.kotlin.models.ReplayIn import com.svix.kotlin.models.ReplayOut import kotlinx.datetime.Instant import okhttp3.Headers -import okhttp3.HttpUrl data class EndpointListOptions( val limit: ULong? = null, @@ -43,19 +42,18 @@ data class EndpointSendExampleOptions(val idempotencyKey: String? = null) data class EndpointGetStatsOptions(val since: Instant? = null, val until: Instant? = null) -class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class Endpoint(private val client: SvixHttpClient) { /** List the application's endpoints. */ suspend fun list( appId: String, options: EndpointListOptions = EndpointListOptions(), ): ListResponseEndpointOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.order?.let { url.addQueryParameter("order", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** @@ -68,11 +66,11 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : endpointIn: EndpointIn, options: EndpointCreateOptions = EndpointCreateOptions(), ): EndpointOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -82,8 +80,8 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : /** Get an endpoint. */ suspend fun get(appId: String, endpointId: String): EndpointOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + return client.executeRequest("GET", url.build()) } /** Update an endpoint. */ @@ -92,9 +90,9 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : endpointId: String, endpointUpdate: EndpointUpdate, ): EndpointOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") - return this.executeRequest( + return client.executeRequest( "PUT", url.build(), reqBody = endpointUpdate, @@ -103,8 +101,8 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : /** Delete an endpoint. */ suspend fun delete(appId: String, endpointId: String) { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") - this.executeRequest("DELETE", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + client.executeRequest("DELETE", url.build()) } /** Partially update an endpoint. */ @@ -113,9 +111,9 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : endpointId: String, endpointPatch: EndpointPatch, ): EndpointOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId") - return this.executeRequest( + return client.executeRequest( "PATCH", url.build(), reqBody = endpointPatch, @@ -125,8 +123,8 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : /** Get the additional headers to be sent with the webhook. */ suspend fun getHeaders(appId: String, endpointId: String): EndpointHeadersOut { val url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") - return this.executeRequest("GET", url.build()) + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") + return client.executeRequest("GET", url.build()) } /** Set the additional headers to be sent with the webhook. */ @@ -136,9 +134,9 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : endpointHeadersIn: EndpointHeadersIn, ) { val url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") - this.executeRequest( + client.executeRequest( "PUT", url.build(), reqBody = endpointHeadersIn, @@ -152,9 +150,9 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : endpointHeadersPatchIn: EndpointHeadersPatchIn, ) { val url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/headers") - this.executeRequest( + client.executeRequest( "PATCH", url.build(), reqBody = endpointHeadersPatchIn, @@ -173,11 +171,11 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : options: EndpointRecoverOptions = EndpointRecoverOptions(), ): RecoverOut { val url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/recover") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/recover") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -198,12 +196,13 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : options: EndpointReplayMissingOptions = EndpointReplayMissingOptions(), ): ReplayOut { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/replay-missing") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -218,8 +217,9 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : * [the consuming webhooks docs](https://docs.svix.com/consuming-webhooks/). */ suspend fun getSecret(appId: String, endpointId: String): EndpointSecretOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/secret") - return this.executeRequest("GET", url.build()) + val url = + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/secret") + return client.executeRequest("GET", url.build()) } /** @@ -234,12 +234,13 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : options: EndpointRotateSecretOptions = EndpointRotateSecretOptions(), ) { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/secret/rotate") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - this.executeRequest( + client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -255,11 +256,13 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : options: EndpointSendExampleOptions = EndpointSendExampleOptions(), ): MessageOut { val url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/send-example") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + client + .newUrlBuilder() + .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/send-example") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -273,18 +276,20 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : endpointId: String, options: EndpointGetStatsOptions = EndpointGetStatsOptions(), ): EndpointStats { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/stats") - options.since?.let { url = url.addQueryParameter("since", serializeQueryParam(it)) } - options.until?.let { url = url.addQueryParameter("until", serializeQueryParam(it)) } - return this.executeRequest("GET", url.build()) + val url = + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/stats") + options.since?.let { url.addQueryParameter("since", serializeQueryParam(it)) } + options.until?.let { url.addQueryParameter("until", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** Get the transformation code associated with this endpoint. */ suspend fun transformationGet(appId: String, endpointId: String): EndpointTransformationOut { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/transformation") - return this.executeRequest("GET", url.build()) + return client.executeRequest("GET", url.build()) } /** Set or unset the transformation code associated with this endpoint. */ @@ -294,10 +299,11 @@ class Endpoint(baseUrl: HttpUrl, defaultHeaders: Map) : endpointTransformationIn: EndpointTransformationIn, ) { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/app/$appId/endpoint/$endpointId/transformation") - this.executeRequest( + client.executeRequest( "PATCH", url.build(), reqBody = endpointTransformationIn, diff --git a/kotlin/lib/src/main/kotlin/EventType.kt b/kotlin/lib/src/main/kotlin/EventType.kt index 4a5dbb819..978d59d34 100644 --- a/kotlin/lib/src/main/kotlin/EventType.kt +++ b/kotlin/lib/src/main/kotlin/EventType.kt @@ -10,7 +10,6 @@ import com.svix.kotlin.models.EventTypeUpdate import com.svix.kotlin.models.ListResponseEventTypeOut import com.svix.kotlin.models.Ordering import okhttp3.Headers -import okhttp3.HttpUrl data class EventTypeListOptions( val limit: ULong? = null, @@ -26,24 +25,21 @@ data class EventTypeImportOpenapiOptions(val idempotencyKey: String? = null) data class EventTypeDeleteOptions(val expunge: Boolean? = null) -class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class EventType(private val client: SvixHttpClient) { /** Return the list of event types. */ suspend fun list( options: EventTypeListOptions = EventTypeListOptions() ): ListResponseEventTypeOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/event-type") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } + val url = client.newUrlBuilder().encodedPath("/api/v1/event-type") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.order?.let { url.addQueryParameter("order", serializeQueryParam(it)) } options.includeArchived?.let { - url = url.addQueryParameter("include_archived", serializeQueryParam(it)) + url.addQueryParameter("include_archived", serializeQueryParam(it)) } - options.withContent?.let { - url = url.addQueryParameter("with_content", serializeQueryParam(it)) - } - return this.executeRequest("GET", url.build()) + options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** @@ -57,11 +53,11 @@ class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : eventTypeIn: EventTypeIn, options: EventTypeCreateOptions = EventTypeCreateOptions(), ): EventTypeOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/event-type") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/event-type") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -80,11 +76,11 @@ class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : eventTypeImportOpenApiIn: EventTypeImportOpenApiIn, options: EventTypeImportOpenapiOptions = EventTypeImportOpenapiOptions(), ): EventTypeImportOpenApiOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/import/openapi") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/event-type/import/openapi") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -94,15 +90,15 @@ class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : /** Get an event type. */ suspend fun get(eventTypeName: String): EventTypeOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + return client.executeRequest("GET", url.build()) } /** Update an event type. */ suspend fun update(eventTypeName: String, eventTypeUpdate: EventTypeUpdate): EventTypeOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + val url = client.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") - return this.executeRequest( + return client.executeRequest( "PUT", url.build(), reqBody = eventTypeUpdate, @@ -121,16 +117,16 @@ class EventType(baseUrl: HttpUrl, defaultHeaders: Map) : eventTypeName: String, options: EventTypeDeleteOptions = EventTypeDeleteOptions(), ) { - var url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") - options.expunge?.let { url = url.addQueryParameter("expunge", serializeQueryParam(it)) } - this.executeRequest("DELETE", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + options.expunge?.let { url.addQueryParameter("expunge", serializeQueryParam(it)) } + client.executeRequest("DELETE", url.build()) } /** Partially update an event type. */ suspend fun patch(eventTypeName: String, eventTypePatch: EventTypePatch): EventTypeOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") + val url = client.newUrlBuilder().encodedPath("/api/v1/event-type/$eventTypeName") - return this.executeRequest( + return client.executeRequest( "PATCH", url.build(), reqBody = eventTypePatch, diff --git a/kotlin/lib/src/main/kotlin/Integration.kt b/kotlin/lib/src/main/kotlin/Integration.kt index cbc8d96f4..777ac831e 100644 --- a/kotlin/lib/src/main/kotlin/Integration.kt +++ b/kotlin/lib/src/main/kotlin/Integration.kt @@ -8,7 +8,6 @@ import com.svix.kotlin.models.IntegrationUpdate import com.svix.kotlin.models.ListResponseIntegrationOut import com.svix.kotlin.models.Ordering import okhttp3.Headers -import okhttp3.HttpUrl data class IntegrationListOptions( val limit: ULong? = null, @@ -20,19 +19,18 @@ data class IntegrationCreateOptions(val idempotencyKey: String? = null) data class IntegrationRotateKeyOptions(val idempotencyKey: String? = null) -class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class Integration(private val client: SvixHttpClient) { /** List the application's integrations. */ suspend fun list( appId: String, options: IntegrationListOptions = IntegrationListOptions(), ): ListResponseIntegrationOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.order?.let { url.addQueryParameter("order", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** Create an integration. */ @@ -41,11 +39,11 @@ class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : integrationIn: IntegrationIn, options: IntegrationCreateOptions = IntegrationCreateOptions(), ): IntegrationOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -55,8 +53,8 @@ class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : /** Get an integration. */ suspend fun get(appId: String, integId: String): IntegrationOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") + return client.executeRequest("GET", url.build()) } /** Update an integration. */ @@ -65,9 +63,9 @@ class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : integId: String, integrationUpdate: IntegrationUpdate, ): IntegrationOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") - return this.executeRequest( + return client.executeRequest( "PUT", url.build(), reqBody = integrationUpdate, @@ -76,8 +74,8 @@ class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : /** Delete an integration. */ suspend fun delete(appId: String, integId: String) { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") - this.executeRequest("DELETE", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId") + client.executeRequest("DELETE", url.build()) } /** @@ -87,8 +85,8 @@ class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : */ @Deprecated("") suspend fun getKey(appId: String, integId: String): IntegrationKeyOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId/key") - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId/key") + return client.executeRequest("GET", url.build()) } /** Rotate the integration's key. The previous key will be immediately revoked. */ @@ -98,10 +96,10 @@ class Integration(baseUrl: HttpUrl, defaultHeaders: Map) : options: IntegrationRotateKeyOptions = IntegrationRotateKeyOptions(), ): IntegrationKeyOut { val url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId/key/rotate") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } - return this.executeRequest( + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/integration/$integId/key/rotate") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } + return client.executeRequest( "POST", url.build(), headers = headers.build(), diff --git a/kotlin/lib/src/main/kotlin/Message.kt b/kotlin/lib/src/main/kotlin/Message.kt index 0da159488..89d56b9c9 100644 --- a/kotlin/lib/src/main/kotlin/Message.kt +++ b/kotlin/lib/src/main/kotlin/Message.kt @@ -6,7 +6,6 @@ import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.MessageOut import kotlinx.datetime.Instant import okhttp3.Headers -import okhttp3.HttpUrl data class MessageListOptions( val limit: ULong? = null, @@ -26,8 +25,7 @@ data class MessageCreateOptions( data class MessageGetOptions(val withContent: Boolean? = null) -class Message(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class Message(private val client: SvixHttpClient) { /** * List all of the application's messages. @@ -45,20 +43,16 @@ class Message(baseUrl: HttpUrl, defaultHeaders: Map) : appId: String, options: MessageListOptions = MessageListOptions(), ): ListResponseMessageOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.channel?.let { url = url.addQueryParameter("channel", it) } - options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } - options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } - options.withContent?.let { - url = url.addQueryParameter("with_content", serializeQueryParam(it)) - } - options.tag?.let { url = url.addQueryParameter("tag", it) } - options.eventTypes?.let { - url = url.addQueryParameter("event_types", serializeQueryParam(it)) - } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.channel?.let { url.addQueryParameter("channel", it) } + options.before?.let { url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) } + options.tag?.let { url.addQueryParameter("tag", it) } + options.eventTypes?.let { url.addQueryParameter("event_types", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** @@ -83,14 +77,12 @@ class Message(baseUrl: HttpUrl, defaultHeaders: Map) : messageIn: MessageIn, options: MessageCreateOptions = MessageCreateOptions(), ): MessageOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") - options.withContent?.let { - url = url.addQueryParameter("with_content", serializeQueryParam(it)) - } - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg") + options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) } + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -104,11 +96,9 @@ class Message(baseUrl: HttpUrl, defaultHeaders: Map) : msgId: String, options: MessageGetOptions = MessageGetOptions(), ): MessageOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId") - options.withContent?.let { - url = url.addQueryParameter("with_content", serializeQueryParam(it)) - } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId") + options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** @@ -118,7 +108,7 @@ class Message(baseUrl: HttpUrl, defaultHeaders: Map) : * can't be replayed or resent once its payload has been deleted or expired. */ suspend fun expungeContent(appId: String, msgId: String) { - val url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/content") - this.executeRequest("DELETE", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/content") + client.executeRequest("DELETE", url.build()) } } diff --git a/kotlin/lib/src/main/kotlin/MessageAttempt.kt b/kotlin/lib/src/main/kotlin/MessageAttempt.kt index a76689723..c2726f3a2 100644 --- a/kotlin/lib/src/main/kotlin/MessageAttempt.kt +++ b/kotlin/lib/src/main/kotlin/MessageAttempt.kt @@ -9,7 +9,6 @@ import com.svix.kotlin.models.MessageStatus import com.svix.kotlin.models.StatusCodeClass import kotlinx.datetime.Instant import okhttp3.Headers -import okhttp3.HttpUrl data class MessageAttemptListByEndpointOptions( val limit: ULong? = null, @@ -58,8 +57,7 @@ data class MessageAttemptListAttemptedDestinationsOptions( data class MessageAttemptResendOptions(val idempotencyKey: String? = null) -class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class MessageAttempt(private val client: SvixHttpClient) { /** * List attempts by endpoint id @@ -74,26 +72,22 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : endpointId: String, options: MessageAttemptListByEndpointOptions = MessageAttemptListByEndpointOptions(), ): ListResponseMessageAttemptOut { - var url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/endpoint/$endpointId") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } + val url = + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/endpoint/$endpointId") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.status?.let { url.addQueryParameter("status", serializeQueryParam(it)) } options.statusCodeClass?.let { - url = url.addQueryParameter("status_code_class", serializeQueryParam(it)) - } - options.channel?.let { url = url.addQueryParameter("channel", it) } - options.tag?.let { url = url.addQueryParameter("tag", it) } - options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } - options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } - options.withContent?.let { - url = url.addQueryParameter("with_content", serializeQueryParam(it)) + url.addQueryParameter("status_code_class", serializeQueryParam(it)) } - options.withMsg?.let { url = url.addQueryParameter("with_msg", serializeQueryParam(it)) } - options.eventTypes?.let { - url = url.addQueryParameter("event_types", serializeQueryParam(it)) - } - return this.executeRequest("GET", url.build()) + options.channel?.let { url.addQueryParameter("channel", it) } + options.tag?.let { url.addQueryParameter("tag", it) } + options.before?.let { url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) } + options.withMsg?.let { url.addQueryParameter("with_msg", serializeQueryParam(it)) } + options.eventTypes?.let { url.addQueryParameter("event_types", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** @@ -109,25 +103,21 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : msgId: String, options: MessageAttemptListByMsgOptions = MessageAttemptListByMsgOptions(), ): ListResponseMessageAttemptOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/msg/$msgId") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/attempt/msg/$msgId") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.status?.let { url.addQueryParameter("status", serializeQueryParam(it)) } options.statusCodeClass?.let { - url = url.addQueryParameter("status_code_class", serializeQueryParam(it)) - } - options.channel?.let { url = url.addQueryParameter("channel", it) } - options.tag?.let { url = url.addQueryParameter("tag", it) } - options.endpointId?.let { url = url.addQueryParameter("endpoint_id", it) } - options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } - options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } - options.withContent?.let { - url = url.addQueryParameter("with_content", serializeQueryParam(it)) + url.addQueryParameter("status_code_class", serializeQueryParam(it)) } - options.eventTypes?.let { - url = url.addQueryParameter("event_types", serializeQueryParam(it)) - } - return this.executeRequest("GET", url.build()) + options.channel?.let { url.addQueryParameter("channel", it) } + options.tag?.let { url.addQueryParameter("tag", it) } + options.endpointId?.let { url.addQueryParameter("endpoint_id", it) } + options.before?.let { url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) } + options.eventTypes?.let { url.addQueryParameter("event_types", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** @@ -148,28 +138,24 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : options: MessageAttemptListAttemptedMessagesOptions = MessageAttemptListAttemptedMessagesOptions(), ): ListResponseEndpointMessageOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/msg") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.channel?.let { url = url.addQueryParameter("channel", it) } - options.tag?.let { url = url.addQueryParameter("tag", it) } - options.status?.let { url = url.addQueryParameter("status", serializeQueryParam(it)) } - options.before?.let { url = url.addQueryParameter("before", serializeQueryParam(it)) } - options.after?.let { url = url.addQueryParameter("after", serializeQueryParam(it)) } - options.withContent?.let { - url = url.addQueryParameter("with_content", serializeQueryParam(it)) - } - options.eventTypes?.let { - url = url.addQueryParameter("event_types", serializeQueryParam(it)) - } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/endpoint/$endpointId/msg") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.channel?.let { url.addQueryParameter("channel", it) } + options.tag?.let { url.addQueryParameter("tag", it) } + options.status?.let { url.addQueryParameter("status", serializeQueryParam(it)) } + options.before?.let { url.addQueryParameter("before", serializeQueryParam(it)) } + options.after?.let { url.addQueryParameter("after", serializeQueryParam(it)) } + options.withContent?.let { url.addQueryParameter("with_content", serializeQueryParam(it)) } + options.eventTypes?.let { url.addQueryParameter("event_types", serializeQueryParam(it)) } + return client.executeRequest("GET", url.build()) } /** `msg_id`: Use a message id or a message `eventId` */ suspend fun get(appId: String, msgId: String, attemptId: String): MessageAttemptOut { val url = - this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/attempt/$attemptId") - return this.executeRequest("GET", url.build()) + client.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/attempt/$attemptId") + return client.executeRequest("GET", url.build()) } /** @@ -180,9 +166,10 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : */ suspend fun expungeContent(appId: String, msgId: String, attemptId: String) { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/app/$appId/msg/$msgId/attempt/$attemptId/content") - this.executeRequest("DELETE", url.build()) + client.executeRequest("DELETE", url.build()) } /** @@ -197,10 +184,10 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : options: MessageAttemptListAttemptedDestinationsOptions = MessageAttemptListAttemptedDestinationsOptions(), ): ListResponseMessageEndpointOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/endpoint") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - return this.executeRequest("GET", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/app/$appId/msg/$msgId/endpoint") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + return client.executeRequest("GET", url.build()) } /** Resend a message to the specified endpoint. */ @@ -211,10 +198,11 @@ class MessageAttempt(baseUrl: HttpUrl, defaultHeaders: Map) : options: MessageAttemptResendOptions = MessageAttemptResendOptions(), ) { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/app/$appId/msg/$msgId/endpoint/$endpointId/resend") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } - this.executeRequest("POST", url.build(), headers = headers.build()) + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } + client.executeRequest("POST", url.build(), headers = headers.build()) } } diff --git a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt index 5aee049dc..04bbc62c1 100644 --- a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt +++ b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt @@ -11,7 +11,6 @@ import com.svix.kotlin.models.OperationalWebhookEndpointSecretOut import com.svix.kotlin.models.OperationalWebhookEndpointUpdate import com.svix.kotlin.models.Ordering import okhttp3.Headers -import okhttp3.HttpUrl data class OperationalWebhookEndpointListOptions( val limit: ULong? = null, @@ -23,18 +22,17 @@ data class OperationalWebhookEndpointCreateOptions(val idempotencyKey: String? = data class OperationalWebhookEndpointRotateSecretOptions(val idempotencyKey: String? = null) -class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class OperationalWebhookEndpoint(private val client: SvixHttpClient) { /** List operational webhook endpoints. */ suspend fun list( options: OperationalWebhookEndpointListOptions = OperationalWebhookEndpointListOptions() ): ListResponseOperationalWebhookEndpointOut { - var url = this.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint") - options.limit?.let { url = url.addQueryParameter("limit", serializeQueryParam(it)) } - options.iterator?.let { url = url.addQueryParameter("iterator", it) } - options.order?.let { url = url.addQueryParameter("order", serializeQueryParam(it)) } - return this.executeRequest( + val url = client.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint") + options.limit?.let { url.addQueryParameter("limit", serializeQueryParam(it)) } + options.iterator?.let { url.addQueryParameter("iterator", it) } + options.order?.let { url.addQueryParameter("order", serializeQueryParam(it)) } + return client.executeRequest( "GET", url.build(), ) @@ -45,11 +43,11 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -60,8 +58,8 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map("GET", url.build()) + client.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint/$endpointId") + return client.executeRequest("GET", url.build()) } /** Update an operational webhook endpoint. */ @@ -70,9 +68,12 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map( + return client.executeRequest< + OperationalWebhookEndpointUpdate, + OperationalWebhookEndpointOut, + >( "PUT", url.build(), reqBody = operationalWebhookEndpointUpdate, @@ -82,16 +83,17 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map("DELETE", url.build()) + client.newUrlBuilder().encodedPath("/api/v1/operational-webhook/endpoint/$endpointId") + client.executeRequest("DELETE", url.build()) } /** Get the additional headers to be sent with the operational webhook. */ suspend fun getHeaders(endpointId: String): OperationalWebhookEndpointHeadersOut { val url = - this.newUrlBuilder() + client + .newUrlBuilder() .encodedPath("/api/v1/operational-webhook/endpoint/$endpointId/headers") - return this.executeRequest("GET", url.build()) + return client.executeRequest("GET", url.build()) } /** Set the additional headers to be sent with the operational webhook. */ @@ -100,10 +102,11 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map( + client.executeRequest( "PUT", url.build(), reqBody = operationalWebhookEndpointHeadersIn, @@ -118,9 +121,10 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map("GET", url.build()) + return client.executeRequest("GET", url.build()) } /** @@ -135,12 +139,13 @@ class OperationalWebhookEndpoint(baseUrl: HttpUrl, defaultHeaders: Map( + client.executeRequest( "POST", url.build(), headers = headers.build(), diff --git a/kotlin/lib/src/main/kotlin/Statistics.kt b/kotlin/lib/src/main/kotlin/Statistics.kt index a0f415f68..e578a1925 100644 --- a/kotlin/lib/src/main/kotlin/Statistics.kt +++ b/kotlin/lib/src/main/kotlin/Statistics.kt @@ -5,12 +5,10 @@ import com.svix.kotlin.models.AggregateEventTypesOut import com.svix.kotlin.models.AppUsageStatsIn import com.svix.kotlin.models.AppUsageStatsOut import okhttp3.Headers -import okhttp3.HttpUrl data class StatisticsAggregateAppStatsOptions(val idempotencyKey: String? = null) -class Statistics(baseUrl: HttpUrl, defaultHeaders: Map) : - SvixHttpClient(baseUrl, defaultHeaders) { +class Statistics(private val client: SvixHttpClient) { /** * Creates a background task to calculate the message destinations for all applications in the @@ -23,11 +21,11 @@ class Statistics(baseUrl: HttpUrl, defaultHeaders: Map) : appUsageStatsIn: AppUsageStatsIn, options: StatisticsAggregateAppStatsOptions = StatisticsAggregateAppStatsOptions(), ): AppUsageStatsOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/stats/usage/app") - var headers = Headers.Builder() - options.idempotencyKey?.let { headers = headers.add("idempotency-key", it) } + val url = client.newUrlBuilder().encodedPath("/api/v1/stats/usage/app") + val headers = Headers.Builder() + options.idempotencyKey?.let { headers.add("idempotency-key", it) } - return this.executeRequest( + return client.executeRequest( "POST", url.build(), headers = headers.build(), @@ -43,7 +41,7 @@ class Statistics(baseUrl: HttpUrl, defaultHeaders: Map) : * endpoint to retrieve the results of the operation. */ suspend fun aggregateEventTypes(): AggregateEventTypesOut { - val url = this.newUrlBuilder().encodedPath("/api/v1/stats/usage/event-types") - return this.executeRequest("PUT", url.build()) + val url = client.newUrlBuilder().encodedPath("/api/v1/stats/usage/event-types") + return client.executeRequest("PUT", url.build()) } } diff --git a/kotlin/lib/src/main/kotlin/Svix.kt b/kotlin/lib/src/main/kotlin/Svix.kt index 5b4e32e8b..c1e5eba11 100644 --- a/kotlin/lib/src/main/kotlin/Svix.kt +++ b/kotlin/lib/src/main/kotlin/Svix.kt @@ -29,15 +29,16 @@ class Svix(token: String, options: SvixOptions = SvixOptions()) { val parsedUrl = options.baseUrl?.toHttpUrlOrNull() ?: throw Exception("Invalid base url") val defaultHeaders = mapOf("User-Agent" to "svix-libs/$version/kotlin", "Authorization" to "Bearer $token") - application = Application(parsedUrl, defaultHeaders) - authentication = Authentication(parsedUrl, defaultHeaders) - endpoint = Endpoint(parsedUrl, defaultHeaders) - eventType = EventType(parsedUrl, defaultHeaders) - integration = Integration(parsedUrl, defaultHeaders) - message = Message(parsedUrl, defaultHeaders) - messageAttempt = MessageAttempt(parsedUrl, defaultHeaders) - statistics = Statistics(parsedUrl, defaultHeaders) - operationalWebhookEndpoint = OperationalWebhookEndpoint(parsedUrl, defaultHeaders) + val httpClient = SvixHttpClient(parsedUrl, defaultHeaders, options.retrySchedule) + application = Application(httpClient) + authentication = Authentication(httpClient) + endpoint = Endpoint(httpClient) + eventType = EventType(httpClient) + integration = Integration(httpClient) + message = Message(httpClient) + messageAttempt = MessageAttempt(httpClient) + statistics = Statistics(httpClient) + operationalWebhookEndpoint = OperationalWebhookEndpoint(httpClient) } } From cebf63690ac8cd06760b1acf5c594d3368a519da Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 21:44:13 -0500 Subject: [PATCH 31/56] kotlin: Add retry logic for status code >= 500 TODO: Remove all debugging code --- kotlin/lib/src/main/kotlin/SvixHttpClient.kt | 77 +++++++++++++++---- .../src/test/com/svix/kotlin/WiremockTests.kt | 34 ++++++++ 2 files changed, 94 insertions(+), 17 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt index c22a40791..79282f900 100644 --- a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt +++ b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt @@ -1,13 +1,20 @@ package com.svix.kotlin import com.svix.kotlin.exceptions.ApiException +import kotlin.random.Random +import kotlin.random.nextULong +import kotlinx.coroutines.delay import kotlinx.serialization.json.Json import okhttp3.* import okhttp3.RequestBody.Companion.toRequestBody open class SvixHttpClient -constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map) { - val client: OkHttpClient = OkHttpClient() +internal constructor( + private val baseUrl: HttpUrl, + private val defaultHeaders: Map, + private val retrySchedule: List, +) { + private val client: OkHttpClient = OkHttpClient() fun newUrlBuilder(): HttpUrl.Builder { return HttpUrl.Builder().scheme(baseUrl.scheme).host(baseUrl.host).port(baseUrl.port) @@ -23,35 +30,29 @@ constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map("true") } @@ -61,8 +62,50 @@ constructor(private val baseUrl: HttpUrl, val defaultHeaders: Map { + + var (res, bodyString) = executeRequestWithDebug(request, jsonBody) + + if (res.code >= 500) { + retrySchedule.forEachIndexed { index, sleepTime -> + run { + delay(sleepTime) + val newReq = + request + .newBuilder() + .header("svix-retry-count", (index + 1).toString()) + .build() + val ret = executeRequestWithDebug(newReq, jsonBody) + res = ret.first + bodyString = ret.second + } + } + } + // val bodyString = res.body!!.string() + + return Pair(res, bodyString) + } + + suspend fun executeRequestWithDebug( + request: Request, + jsonBody: String?, + ): Pair { + val debug: String = System.getenv("DEBUG") ?: "no" + if (debug == "yes") { + dbgRequest(request, jsonBody) + } + + val res = client.newCall(request).execute() + + val bodyString = res.body!!.string() + + if (debug == "yes") { + dbgResponse(res, bodyString) + } + return Pair(res, bodyString) } } diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index f69bdf847..0f109a13d 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -4,9 +4,11 @@ import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options +import com.svix.kotlin.exceptions.ApiException import com.svix.kotlin.models.EndpointPatch import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.Ordering +import kotlin.test.assertEquals import kotlinx.coroutines.runBlocking import kotlinx.datetime.Instant import kotlinx.serialization.json.JsonObject @@ -190,4 +192,36 @@ class WiremockTests { .withHeader("User-Agent", matching("svix-libs/.*/kotlin")), ) } + + @Test + fun defaultRetryStatusCode500() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.get(urlMatching("/api/v1/app/ap/msg")) + .willReturn(WireMock.status(500).withBodyFile("ListResponseMessageOut.json")) + ) + runBlocking { + try { + svx.message.list("ap") + } catch (e: ApiException) { + assertEquals(500, e.statusCode) + } + } + + wireMockServer.verify( + 1, + getRequestedFor(urlEqualTo("/api/v1/app/ap/msg")) + // first request does not have `svix-retry-count` header + .withHeader("svix-retry-count", absent()), + ) + + // check the svix-retry-count are set correctly + for (retryCount in 1..3) { + wireMockServer.verify( + 1, + getRequestedFor(urlEqualTo("/api/v1/app/ap/msg")) + .withHeader("svix-retry-count", equalTo("$retryCount")), + ) + } + } } From 71bb142e6c0a2a83f865d6bbbe9f918cd78d095d Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 22:01:44 -0500 Subject: [PATCH 32/56] kotlin: Add instant(timestamp) tests --- .../src/test/com/svix/kotlin/WiremockTests.kt | 49 +++++++++++++++++++ .../test/resources/__files/MessageOut.json | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index 0f109a13d..f4c3e410d 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -5,6 +5,7 @@ import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock.* import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options import com.svix.kotlin.exceptions.ApiException +import com.svix.kotlin.models.AppUsageStatsIn import com.svix.kotlin.models.EndpointPatch import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.Ordering @@ -224,4 +225,52 @@ class WiremockTests { ) } } + + @Test + fun instantSerializedCorrectly() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.get(urlMatching("/api/v1/app/ap/msg/msg_asd123")) + // this file includes a string timestamp `2025-02-12T22:24:32.864755Z` + .willReturn(WireMock.ok().withBodyFile("MessageOut.json")) + ) + runBlocking { + val res = svx.message.get("ap", "msg_asd123") + assertEquals(Instant.fromEpochSeconds(1739399072, 864755000), res.timestamp) + } + + wireMockServer.verify(1, getRequestedFor(urlEqualTo("/api/v1/app/ap/msg/msg_asd123"))) + } + + @Test + fun instantDeserializedCorrectly() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.post(urlMatching("/api/v1/stats/usage/app")) + .willReturn( + WireMock.ok() + .withBody( + """{"unresolvedAppIds":["unique-identifier"],"id":"qtask_1srOrx2ZWZBpBUvZwXKQmoEYga2","status":"running","task":"endpoint.replay"}""" + ) + ) + ) + runBlocking { + svx.statistics.aggregateAppStats( + AppUsageStatsIn( + since = Instant.fromEpochSeconds(1739399072, 864755000), + until = Instant.fromEpochSeconds(1739399072, 864755000), + ) + ) + } + + wireMockServer.verify( + 1, + postRequestedFor(urlEqualTo("/api/v1/stats/usage/app")) + .withRequestBody( + equalTo( + """{"since":"2025-02-12T22:24:32.864755Z","until":"2025-02-12T22:24:32.864755Z"}""" + ) + ), + ) + } } diff --git a/kotlin/lib/src/test/resources/__files/MessageOut.json b/kotlin/lib/src/test/resources/__files/MessageOut.json index 2c7a38381..018de1bb0 100644 --- a/kotlin/lib/src/test/resources/__files/MessageOut.json +++ b/kotlin/lib/src/test/resources/__files/MessageOut.json @@ -1 +1 @@ -{"eventId":"unique-identifier","eventType":"user.signup","payload":{"email":"test@example.com","type":"user.created","username":"test_user"},"channels":["project_123","group_2"],"id":"msg_1srOrx2ZWZBpBUvZwXKQmoEYga2","timestamp":"2019-08-24T14:15:22Z","tags":["project_1337"] } \ No newline at end of file +{"eventId":"unique-identifier","eventType":"user.signup","payload":{"email":"test@example.com","type":"user.created","username":"test_user"},"channels":["project_123","group_2"],"id":"msg_1srOrx2ZWZBpBUvZwXKQmoEYga2","timestamp":"2025-02-12T22:24:32.864755Z","tags":["project_1337"]} \ No newline at end of file From 834a7e11bec522332592f6b358df57068a952dc7 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 22:05:48 -0500 Subject: [PATCH 33/56] kotlin: Remove debug logic --- kotlin/lib/src/main/kotlin/SvixHttpClient.kt | 71 +++----------------- 1 file changed, 8 insertions(+), 63 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt index 79282f900..e5f717b5a 100644 --- a/kotlin/lib/src/main/kotlin/SvixHttpClient.kt +++ b/kotlin/lib/src/main/kotlin/SvixHttpClient.kt @@ -26,11 +26,9 @@ internal constructor( headers: Headers? = null, reqBody: Req? = null, ): Res { - var reqBuilder = Request.Builder().url(url) - var jsonBody: String? = null + val reqBuilder = Request.Builder().url(url) if (reqBody != null) { - jsonBody = Json.encodeToString(reqBody) - reqBuilder.method(method, jsonBody.toRequestBody()) + reqBuilder.method(method, Json.encodeToString(reqBody).toRequestBody()) } else { reqBuilder.method(method, null) } @@ -46,13 +44,13 @@ internal constructor( reqBuilder.addHeader("svix-req-id", Random.nextULong().toString()) val request = reqBuilder.build() - val (res, _bodyString) = executeRequestWithRetry(request, jsonBody) + val res = executeRequestWithRetry(request) // if body is null panic if (res.body == null) { throw ApiException("Body is null", res.code) } - val bodyString = _bodyString // res.body!!.string() + val bodyString = res.body!!.string() if (res.code == 204) { return Json.decodeFromString("true") } @@ -62,12 +60,9 @@ internal constructor( throw ApiException("None 200 status code", res.code, bodyString) } - suspend fun executeRequestWithRetry( - request: Request, - jsonBody: String?, - ): Pair { + suspend fun executeRequestWithRetry(request: Request): Response { - var (res, bodyString) = executeRequestWithDebug(request, jsonBody) + var res = client.newCall(request).execute() if (res.code >= 500) { retrySchedule.forEachIndexed { index, sleepTime -> @@ -78,60 +73,10 @@ internal constructor( .newBuilder() .header("svix-retry-count", (index + 1).toString()) .build() - val ret = executeRequestWithDebug(newReq, jsonBody) - res = ret.first - bodyString = ret.second + res = client.newCall(newReq).execute() } } } - // val bodyString = res.body!!.string() - - return Pair(res, bodyString) - } - - suspend fun executeRequestWithDebug( - request: Request, - jsonBody: String?, - ): Pair { - val debug: String = System.getenv("DEBUG") ?: "no" - if (debug == "yes") { - dbgRequest(request, jsonBody) - } - - val res = client.newCall(request).execute() - - val bodyString = res.body!!.string() - - if (debug == "yes") { - dbgResponse(res, bodyString) - } - return Pair(res, bodyString) - } -} - -fun dbgRequest(request: Request, jsonBody: String?) { - println("_____ start dbg _____") - println("Url: ${request.url}") - println("${request.method} /${request.url.toString().split("/").drop(3).joinToString("/")}") - for ((k, v) in request.headers) { - println("$k: $v") - } - println() - if (jsonBody != null) { - println(jsonBody) - println() - } -} - -fun dbgResponse(response: Response, bodyString: String?) { - println("Status code: ${response.code}") - for ((k, v) in response.headers) { - println("$k: $v") - } - println() - - if (response.body != null) { - println(bodyString) - println() + return res } } From 3daadf761fe900a6cc0b8cdc09f6616ca500211e Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 22:17:22 -0500 Subject: [PATCH 34/56] kotlin: Enable tests in CI --- .github/workflows/kotlin-lint.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/kotlin-lint.yml b/.github/workflows/kotlin-lint.yml index 053946731..911c566be 100644 --- a/.github/workflows/kotlin-lint.yml +++ b/.github/workflows/kotlin-lint.yml @@ -21,12 +21,7 @@ jobs: distribution: 'temurin' java-version: '11' - - name: Regen openapi libs - run: | - yarn - ./regen_openapi.sh - - name: Build run: | cd kotlin - ./gradlew build -x test + ./gradlew build From 827c370f2bb635e832719325c683bdef3d86fedd Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Wed, 12 Feb 2025 22:18:36 -0500 Subject: [PATCH 35/56] Fix typo --- ChangeLog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 7da96bbfa..a94fe9b5c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,7 +1,7 @@ # Changelog ## Unreleased -* Libs/Kotlin **(Breaking)** Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` is removed +* Libs/Kotlin **(Breaking)** Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` are removed * Libs/Kotlin **(Breaking)**: All uses of `java.time.OffsetDateTime` replaced with `kotlinx.datetime.Instant` * Libs/Kotlin **(Breaking)**: All uses of `java.net.URL` in request/response models are replaced with `String` * Libs/Kotlin **(Breaking)**: All uses of `Map` in request/response models are replaced with `kotlinx.serialization.json.JsonObject` From 258ef6e814ecdaf3065b629421c80e93dad903db Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 10:55:34 -0500 Subject: [PATCH 36/56] kotlin: Add `messageInRaw` --- kotlin/lib/src/main/kotlin/Message.kt | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/kotlin/lib/src/main/kotlin/Message.kt b/kotlin/lib/src/main/kotlin/Message.kt index 89d56b9c9..53570623c 100644 --- a/kotlin/lib/src/main/kotlin/Message.kt +++ b/kotlin/lib/src/main/kotlin/Message.kt @@ -112,3 +112,49 @@ class Message(private val client: SvixHttpClient) { client.executeRequest("DELETE", url.build()) } } + +/** + * Creates a [MessageIn] with a pre-serialized payload. + * + * The payload is not normalized on the server. Normally, payloads are required to be JSON, and Svix + * will minify the payload before sending the webhooks (for example, by removing extraneous + * whitespace or unnecessarily escaped characters in strings). With this function, the payload will + * be sent "as is", without any minification or other processing. + * + * @param payload Serialized message payload + * @param contentType The value to use for the Content-Type header of the webhook sent by Svix, + * overwriting the default of `application/json` if specified + * + * See the class documentation for details about the other parameters. + */ +fun messageInRaw( + eventType: String, + payload: String, + contentType: String? = null, + application: ApplicationIn? = null, + channels: Set? = null, + eventId: String? = null, + payloadRetentionHours: Long? = null, + payloadRetentionPeriod: Long? = 90L, + tags: Set? = null, + transformationsParams: Map = mapOf(), +): MessageIn { + val transformationsParams = transformationsParams.toMutableMap() + transformationsParams.put("rawPayload", payload) + if (contentType != null) { + val headers = mapOf("content-type" to contentType) + transformationsParams.put("headers", headers) + } + + return MessageIn( + eventType = eventType, + payload = mapOf(), + application = application, + channels = channels, + eventId = eventId, + payloadRetentionHours = payloadRetentionHours, + payloadRetentionPeriod = payloadRetentionPeriod, + tags = tags, + transformationsParams = transformationsParams, + ) +} From 7cb3a4b92c00b64e8158f37201474da051467347 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 11:00:18 -0500 Subject: [PATCH 37/56] kotlin: Document all breaking changes --- ChangeLog.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index a94fe9b5c..479814983 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,7 +1,11 @@ # Changelog ## Unreleased -* Libs/Kotlin **(Breaking)** Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` are removed +* Libs/C#, Libs/Go and Libs/Kotlin **(Breaking)**: All uses of `ListOptions`/`PostOptions` are removed, and renamed to `{Resource}{Operation}Options`. For example in `Endpoint.List` you would now use `EndpointListOptions` +* Libs/Kotlin **(Breaking)**: `SvixOptions` no longer has `initialRetryDelayMillis` or `numRetries` instead use `retrySchedule` +* Libs/Kotlin: Fix the parameter names of `Endpoint.get` - `appId` and `endpointId` were swapped +* Libs/Kotlin **(Breaking)**: All `{Resource}{Operation}Options` and model classes (`ApplicationIn`/`MessageOut`) are now data classes +* Libs/Kotlin **(Breaking)**: Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` are removed * Libs/Kotlin **(Breaking)**: All uses of `java.time.OffsetDateTime` replaced with `kotlinx.datetime.Instant` * Libs/Kotlin **(Breaking)**: All uses of `java.net.URL` in request/response models are replaced with `String` * Libs/Kotlin **(Breaking)**: All uses of `Map` in request/response models are replaced with `kotlinx.serialization.json.JsonObject` @@ -15,7 +19,6 @@ This version contains a big overhaul of the client libraries, with improved typi * Libs/Go **(Breaking)**: All custom model types are now imported from `github.com/svix/svix-webhooks/go/models` instead of `github.com/svix/svix-webhooks/go` * Libs/Go **(Breaking)**: All `-WithOptions` methods are now removed. Their regular counterparts now take a pointer to an Options type which can be nil when not needed. For example in `Endpoint.RecoverWithOptions` is now `Endpoint.Recover` -* Libs/C# and Libs/Go **(Breaking)**: All uses of `ListOptions`/`PostOptions` are removed, and renamed to `{Resource}{Operation}Options`. For example in `Endpoint.List` you would now use `EndpointListOptions` * Libs/C# **(Breaking)**: All `IdempotencyKey` method parameters are removed, and are now part of `{Resource}{Operation}Options`. For example in `Message.Create`; to the use `IdempotencyKey`, simply pass it in the `MessageCreateOptions` * Libs/C# **(Breaking)**: The `Throw` parameter is removed from `SvixOptions` * Libs/C# **(Breaking)**: All redundant interfaces along with the `Svix.Abstractions` namespace are removed @@ -28,8 +31,6 @@ This version contains a big overhaul of the client libraries, with improved typi * Libs/Python **(Breaking)**: `MessageAttemptListOptions` is removed in favor of call specific `{Resource}{Operation}Options` * Libs/Python **(Breaking)**: For `Statistics` in the `aggregate_event_types` method the `task_id` parameter is removed, Please note that previously this parameter was ignored and had no affect (Both sync and async) -* Libs/Kotlin **(Breaking)**: Mark `api` field of all API resource classes as `private` (previously - only some were private, accidentally) * Libs/Kotlin **(Breaking)**: Update `recover` to return `RecoverOut` (instead of nothing) * Libs/Kotlin **(Breaking)**: Update `replayMissing` to return `ReplayOut` (instead of nothing) * Libs/Kotlin **(Breaking)**: Update `sendExample` to return `MessageOut` (instead of nothing) From 9d4e78e8d4b091ed8243eab4736473a3b85a16c5 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 11:06:32 -0500 Subject: [PATCH 38/56] kotlin: Fix `messageInRaw` Changing the type of the `transformationsParams` from `Map` to `Map` is already documented --- kotlin/lib/src/main/kotlin/Message.kt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Message.kt b/kotlin/lib/src/main/kotlin/Message.kt index 53570623c..bb46f7e4a 100644 --- a/kotlin/lib/src/main/kotlin/Message.kt +++ b/kotlin/lib/src/main/kotlin/Message.kt @@ -1,10 +1,14 @@ // this file is @generated package com.svix.kotlin +import com.svix.kotlin.models.ApplicationIn import com.svix.kotlin.models.ListResponseMessageOut import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.MessageOut import kotlinx.datetime.Instant +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive import okhttp3.Headers data class MessageListOptions( @@ -137,24 +141,24 @@ fun messageInRaw( payloadRetentionHours: Long? = null, payloadRetentionPeriod: Long? = 90L, tags: Set? = null, - transformationsParams: Map = mapOf(), + transformationsParams: Map = mapOf(), ): MessageIn { val transformationsParams = transformationsParams.toMutableMap() - transformationsParams.put("rawPayload", payload) + transformationsParams["rawPayload"] = JsonPrimitive(payload) if (contentType != null) { - val headers = mapOf("content-type" to contentType) - transformationsParams.put("headers", headers) + val headers = mapOf("content-type" to JsonPrimitive(contentType)) + transformationsParams["headers"] = JsonObject(headers) } return MessageIn( eventType = eventType, - payload = mapOf(), + payload = JsonObject(mapOf()), application = application, channels = channels, eventId = eventId, payloadRetentionHours = payloadRetentionHours, payloadRetentionPeriod = payloadRetentionPeriod, tags = tags, - transformationsParams = transformationsParams, + transformationsParams = JsonObject(transformationsParams), ) } From 44e3213a813ce18a39894c6cf14bc57b05f8bc04 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 11:13:07 -0500 Subject: [PATCH 39/56] kotlin: Ensure version is set correctly --- kotlin/lib/src/main/kotlin/Svix.kt | 3 +-- kotlin/lib/src/main/kotlin/Version.kt | 3 +++ tools/bump_version.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 kotlin/lib/src/main/kotlin/Version.kt diff --git a/kotlin/lib/src/main/kotlin/Svix.kt b/kotlin/lib/src/main/kotlin/Svix.kt index c1e5eba11..867e4328b 100644 --- a/kotlin/lib/src/main/kotlin/Svix.kt +++ b/kotlin/lib/src/main/kotlin/Svix.kt @@ -4,7 +4,6 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull class Svix(token: String, options: SvixOptions = SvixOptions()) { - private val version = "1.21.0" val application: Application val authentication: Authentication val endpoint: Endpoint @@ -28,7 +27,7 @@ class Svix(token: String, options: SvixOptions = SvixOptions()) { } val parsedUrl = options.baseUrl?.toHttpUrlOrNull() ?: throw Exception("Invalid base url") val defaultHeaders = - mapOf("User-Agent" to "svix-libs/$version/kotlin", "Authorization" to "Bearer $token") + mapOf("User-Agent" to "svix-libs/${Version}/kotlin", "Authorization" to "Bearer $token") val httpClient = SvixHttpClient(parsedUrl, defaultHeaders, options.retrySchedule) application = Application(httpClient) authentication = Authentication(httpClient) diff --git a/kotlin/lib/src/main/kotlin/Version.kt b/kotlin/lib/src/main/kotlin/Version.kt new file mode 100644 index 000000000..51b5c4661 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/Version.kt @@ -0,0 +1,3 @@ +package com.svix.kotlin + +const val Version = "1.56.0" diff --git a/tools/bump_version.js b/tools/bump_version.js index e41514536..b0e7ec10f 100755 --- a/tools/bump_version.js +++ b/tools/bump_version.js @@ -30,7 +30,7 @@ const filesPaths = [ // Kotlin "kotlin/gradle.properties", "kotlin/README.md", - "kotlin/lib/src/main/kotlin/SvixOptions.kt", + "kotlin/lib/src/main/kotlin/Version.kt", // Python "python/svix/__init__.py", // Ruby From 65be62aa447c884479033d8eb4ca608c851f19b2 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 12:41:57 -0500 Subject: [PATCH 40/56] kotlin: This is the last undocumented breaking change --- ChangeLog.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 479814983..fc50ebb47 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -3,7 +3,8 @@ ## Unreleased * Libs/C#, Libs/Go and Libs/Kotlin **(Breaking)**: All uses of `ListOptions`/`PostOptions` are removed, and renamed to `{Resource}{Operation}Options`. For example in `Endpoint.List` you would now use `EndpointListOptions` * Libs/Kotlin **(Breaking)**: `SvixOptions` no longer has `initialRetryDelayMillis` or `numRetries` instead use `retrySchedule` -* Libs/Kotlin: Fix the parameter names of `Endpoint.get` - `appId` and `endpointId` were swapped +* Libs/Kotlin **(Breaking)**: Fix the parameter names of `Endpoint.get` - `appId` and `endpointId` were swapped +* Libs/Kotlin **(Breaking)**: Fix the parameter names of `Message.get` and `Message.expungeContent` - `appId` and `msgId` were swapped * Libs/Kotlin **(Breaking)**: All `{Resource}{Operation}Options` and model classes (`ApplicationIn`/`MessageOut`) are now data classes * Libs/Kotlin **(Breaking)**: Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` are removed * Libs/Kotlin **(Breaking)**: All uses of `java.time.OffsetDateTime` replaced with `kotlinx.datetime.Instant` From 3150c2966c1ab952cdb0b3145ae41ab34914f5b2 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 13:59:31 -0500 Subject: [PATCH 41/56] kotlin: Add serializer for Map --- .../src/main/kotlin/StringAnyMapSerializer.kt | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 kotlin/lib/src/main/kotlin/StringAnyMapSerializer.kt diff --git a/kotlin/lib/src/main/kotlin/StringAnyMapSerializer.kt b/kotlin/lib/src/main/kotlin/StringAnyMapSerializer.kt new file mode 100644 index 000000000..0e9bc6515 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/StringAnyMapSerializer.kt @@ -0,0 +1,138 @@ +package com.svix.kotlin + +import kotlinx.serialization.* +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.* +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive + +@OptIn(ExperimentalSerializationApi::class) +object StringAnyMapSerializer : KSerializer> { + override val descriptor: SerialDescriptor = JsonObject.serializer().descriptor + + override fun serialize(encoder: Encoder, value: Map) { + val jsonEncoder = + encoder as? JsonEncoder + ?: throw SerializationException("This serializer can only be used with JSON") + val jsonObject = value.toJsonElement() + jsonEncoder.encodeJsonElement(jsonObject) + } + + override fun deserialize(decoder: Decoder): Map { + val jsonDecoder = + decoder as? JsonDecoder + ?: throw SerializationException("This serializer can only be used with JSON") + val element = jsonDecoder.decodeJsonElement() + + if (element !is JsonObject) throw SerializationException("Expected JsonObject") + + return element.mapValues { (_, value) -> + deserializeJsonElement(value) ?: throw SerializationException("Null values not allowed") + } + } + + private fun deserializeJsonElement(element: JsonElement): Any? { + return when (element) { + is JsonPrimitive -> + when { + element.isString -> element.content + element.intOrNull != null -> element.int + element.longOrNull != null -> element.long + element.doubleOrNull != null -> element.double + element.booleanOrNull != null -> element.boolean + else -> element.content + } + + is JsonArray -> + element.map { + deserializeJsonElement(it) + ?: throw SerializationException("Null values not allowed in arrays") + } + + is JsonObject -> + element.mapValues { (_, value) -> + deserializeJsonElement(value) + ?: throw SerializationException("Null values not allowed in objects") + } + + JsonNull -> null + } + } +} + +@OptIn(ExperimentalSerializationApi::class) +object MaybeUnsetStringAnyMapSerializer : KSerializer>> { + override val descriptor: SerialDescriptor = JsonObject.serializer().descriptor + + override fun serialize(encoder: Encoder, value: MaybeUnset>) { + val jsonEncoder = + encoder as? JsonEncoder + ?: throw SerializationException("This serializer can only be used with JSON") + + when (value) { + is MaybeUnset.Unset -> + throw SerializationException("MaybeUnset.Unset should not be serialized") + is MaybeUnset.Null -> jsonEncoder.encodeJsonElement(JsonNull) + is MaybeUnset.Present -> StringAnyMapSerializer.serialize(encoder, value.value) + } + } + + override fun deserialize(decoder: Decoder): MaybeUnset> { + val jsonDecoder = + decoder as? JsonDecoder + ?: throw SerializationException("This serializer can only be used with JSON") + val element = jsonDecoder.decodeJsonElement() + + return when (element) { + JsonNull -> MaybeUnset.Null + is JsonObject -> MaybeUnset.Present(StringAnyMapSerializer.deserialize(decoder)) + else -> throw SerializationException("Expected JsonObject or null") + } + } +} + +fun Any?.toJsonElement(): JsonElement = + when (this) { + null -> JsonNull + is Map<*, *> -> toJsonElement() + is Collection<*> -> toJsonElement() + is ByteArray -> this.toList().toJsonElement() + is CharArray -> this.toList().toJsonElement() + is ShortArray -> this.toList().toJsonElement() + is IntArray -> this.toList().toJsonElement() + is LongArray -> this.toList().toJsonElement() + is FloatArray -> this.toList().toJsonElement() + is DoubleArray -> this.toList().toJsonElement() + is BooleanArray -> this.toList().toJsonElement() + is Array<*> -> toJsonElement() + is Boolean -> JsonPrimitive(this) + is Number -> JsonPrimitive(this) + is String -> JsonPrimitive(this) + is Enum<*> -> JsonPrimitive(this.toString()) + else -> { + throw IllegalStateException("Can't serialize unknown type: $this") + } + } + +fun Map<*, *>.toJsonElement(): JsonElement { + val map = mutableMapOf() + this.forEach { key, value -> + key as String + map[key] = value.toJsonElement() + } + return JsonObject(map) +} + +fun Collection<*>.toJsonElement(): JsonElement { + return JsonArray(this.map { it.toJsonElement() }) +} + +fun Array<*>.toJsonElement(): JsonElement { + return JsonArray(this.map { it.toJsonElement() }) +} From 1ea2ce5aa0ae0f131a9301d9337b5fca76f31411 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:00:29 -0500 Subject: [PATCH 42/56] kotlin: Swap `JsonObject` with `Map` --- .../lib/src/main/kotlin/models/BackgroundTaskOut.kt | 4 ++-- .../src/main/kotlin/models/EndpointMessageOut.kt | 4 ++-- kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt | 4 ++-- kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt | 4 ++-- .../src/main/kotlin/models/EventTypeFromOpenApi.kt | 4 ++-- .../main/kotlin/models/EventTypeImportOpenApiIn.kt | 4 ++-- kotlin/lib/src/main/kotlin/models/EventTypeIn.kt | 4 ++-- kotlin/lib/src/main/kotlin/models/EventTypeOut.kt | 4 ++-- kotlin/lib/src/main/kotlin/models/EventTypePatch.kt | 5 +++-- .../lib/src/main/kotlin/models/EventTypeUpdate.kt | 4 ++-- kotlin/lib/src/main/kotlin/models/MessageIn.kt | 7 ++++--- kotlin/lib/src/main/kotlin/models/MessageOut.kt | 4 ++-- kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt | 13 ++++--------- .../lib/src/test/com/svix/kotlin/WiremockTests.kt | 7 +------ 14 files changed, 32 insertions(+), 40 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt index 82270afa9..83be0130c 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskOut.kt @@ -1,12 +1,12 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class BackgroundTaskOut( - val data: JsonObject, + @Serializable(with = StringAnyMapSerializer::class) val data: Map, val id: String, val status: BackgroundTaskStatus, val task: BackgroundTaskType, diff --git a/kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt b/kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt index 1994ce9a8..57967aec9 100644 --- a/kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt +++ b/kotlin/lib/src/main/kotlin/models/EndpointMessageOut.kt @@ -1,9 +1,9 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.datetime.Instant import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EndpointMessageOut( @@ -12,7 +12,7 @@ data class EndpointMessageOut( val eventType: String, val id: String, val nextAttempt: Instant? = null, - val payload: JsonObject, + @Serializable(with = StringAnyMapSerializer::class) val payload: Map, val status: MessageStatus, val tags: Set? = null, val timestamp: Instant, diff --git a/kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt b/kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt index 61812a2ab..e0a2bee72 100644 --- a/kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt +++ b/kotlin/lib/src/main/kotlin/models/EnvironmentIn.kt @@ -1,12 +1,12 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EnvironmentIn( val eventTypes: List? = null, - val settings: JsonObject? = null, + @Serializable(with = StringAnyMapSerializer::class) val settings: Map? = null, val transformationTemplates: List? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt b/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt index 2a2e4656e..661de8189 100644 --- a/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt +++ b/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt @@ -1,15 +1,15 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.datetime.Instant import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EnvironmentOut( val createdAt: Instant, val eventTypes: List, - val settings: JsonObject, + @Serializable(with = StringAnyMapSerializer::class) val settings: Map, val transformationTemplates: List, val version: Long? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt b/kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt index 559420365..8e74b5fe6 100644 --- a/kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt +++ b/kotlin/lib/src/main/kotlin/models/EventTypeFromOpenApi.kt @@ -1,8 +1,8 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EventTypeFromOpenApi( @@ -11,5 +11,5 @@ data class EventTypeFromOpenApi( val featureFlag: String? = null, val groupName: String? = null, val name: String, - val schemas: JsonObject? = null, + @Serializable(with = StringAnyMapSerializer::class) val schemas: Map? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt index fe7b8ac6a..344224837 100644 --- a/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt +++ b/kotlin/lib/src/main/kotlin/models/EventTypeImportOpenApiIn.kt @@ -1,13 +1,13 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EventTypeImportOpenApiIn( val dryRun: Boolean? = null, val replaceAll: Boolean? = null, - val spec: JsonObject? = null, + @Serializable(with = StringAnyMapSerializer::class) val spec: Map? = null, val specRaw: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeIn.kt b/kotlin/lib/src/main/kotlin/models/EventTypeIn.kt index d940bb6f4..ef5f368d0 100644 --- a/kotlin/lib/src/main/kotlin/models/EventTypeIn.kt +++ b/kotlin/lib/src/main/kotlin/models/EventTypeIn.kt @@ -1,8 +1,8 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EventTypeIn( @@ -12,5 +12,5 @@ data class EventTypeIn( val featureFlag: String? = null, val groupName: String? = null, val name: String, - val schemas: JsonObject? = null, + @Serializable(with = StringAnyMapSerializer::class) val schemas: Map? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeOut.kt b/kotlin/lib/src/main/kotlin/models/EventTypeOut.kt index 20dadbbd3..a91b555f3 100644 --- a/kotlin/lib/src/main/kotlin/models/EventTypeOut.kt +++ b/kotlin/lib/src/main/kotlin/models/EventTypeOut.kt @@ -1,9 +1,9 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.datetime.Instant import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EventTypeOut( @@ -14,6 +14,6 @@ data class EventTypeOut( val featureFlag: String? = null, val groupName: String? = null, val name: String, - val schemas: JsonObject? = null, + @Serializable(with = StringAnyMapSerializer::class) val schemas: Map? = null, val updatedAt: Instant, ) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt b/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt index cc5a52971..473bac896 100644 --- a/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt +++ b/kotlin/lib/src/main/kotlin/models/EventTypePatch.kt @@ -2,8 +2,8 @@ package com.svix.kotlin.models import com.svix.kotlin.MaybeUnset +import com.svix.kotlin.MaybeUnsetStringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EventTypePatch( @@ -12,5 +12,6 @@ data class EventTypePatch( val description: String? = null, val featureFlag: MaybeUnset = MaybeUnset.Unset, val groupName: MaybeUnset = MaybeUnset.Unset, - val schemas: MaybeUnset = MaybeUnset.Unset, + @Serializable(with = MaybeUnsetStringAnyMapSerializer::class) + val schemas: MaybeUnset> = MaybeUnset.Unset, ) diff --git a/kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt b/kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt index a9d2ed402..edf7ed91d 100644 --- a/kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt +++ b/kotlin/lib/src/main/kotlin/models/EventTypeUpdate.kt @@ -1,8 +1,8 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class EventTypeUpdate( @@ -11,5 +11,5 @@ data class EventTypeUpdate( val description: String, val featureFlag: String? = null, val groupName: String? = null, - val schemas: JsonObject? = null, + @Serializable(with = StringAnyMapSerializer::class) val schemas: Map? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/MessageIn.kt b/kotlin/lib/src/main/kotlin/models/MessageIn.kt index b9186979f..5575f2a82 100644 --- a/kotlin/lib/src/main/kotlin/models/MessageIn.kt +++ b/kotlin/lib/src/main/kotlin/models/MessageIn.kt @@ -1,8 +1,8 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class MessageIn( @@ -10,9 +10,10 @@ data class MessageIn( val channels: Set? = null, val eventId: String? = null, val eventType: String, - val payload: JsonObject, + @Serializable(with = StringAnyMapSerializer::class) val payload: Map, val payloadRetentionHours: Long? = null, val payloadRetentionPeriod: Long? = null, val tags: Set? = null, - val transformationsParams: JsonObject? = null, + @Serializable(with = StringAnyMapSerializer::class) + val transformationsParams: Map? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/MessageOut.kt b/kotlin/lib/src/main/kotlin/models/MessageOut.kt index c3aeeb603..5e572e506 100644 --- a/kotlin/lib/src/main/kotlin/models/MessageOut.kt +++ b/kotlin/lib/src/main/kotlin/models/MessageOut.kt @@ -1,9 +1,9 @@ // This file is @generated package com.svix.kotlin.models +import com.svix.kotlin.StringAnyMapSerializer import kotlinx.datetime.Instant import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonObject @Serializable data class MessageOut( @@ -11,7 +11,7 @@ data class MessageOut( val eventId: String? = null, val eventType: String, val id: String, - val payload: JsonObject, + @Serializable(with = StringAnyMapSerializer::class) val payload: Map, val tags: Set? = null, val timestamp: Instant, ) diff --git a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt index 4a7385621..7ba62c258 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt @@ -9,9 +9,6 @@ import com.svix.kotlin.models.MessageIn import kotlin.test.Test import kotlin.test.assertEquals import kotlinx.coroutines.runBlocking -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive class BasicTest { companion object { @@ -39,12 +36,10 @@ class BasicTest { MessageIn( eventType = "invoice.paid", payload = - JsonObject( - mapOf( - "id" to JsonPrimitive("invoice_WF7WtCLFFtd8ubcTgboSFNql"), - "status" to JsonPrimitive("paid"), - "attempt" to JsonPrimitive(2), - ) + mapOf( + "id" to "invoice_WF7WtCLFFtd8ubcTgboSFNql", + "status" to "paid", + "attempt" to 2, ), ), ) diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index f4c3e410d..b009b2367 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -12,8 +12,6 @@ import com.svix.kotlin.models.Ordering import kotlin.test.assertEquals import kotlinx.coroutines.runBlocking import kotlinx.datetime.Instant -import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive import org.junit.jupiter.api.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -165,10 +163,7 @@ class WiremockTests { runBlocking { svx.message.create( "ap", - MessageIn( - eventType = "event.test", - payload = JsonObject(mapOf("key" to JsonPrimitive("val"))), - ), + MessageIn(eventType = "event.test", payload = mapOf("key" to "val")), MessageCreateOptions(idempotencyKey = "key123"), ) } From ee8b9e1f1c5fc66dcd4d6ce40274da5a7e6e9cf4 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:01:12 -0500 Subject: [PATCH 43/56] kotlin: This is no longer changed --- ChangeLog.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index fc50ebb47..ce6f506c9 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,7 +1,7 @@ # Changelog ## Unreleased -* Libs/C#, Libs/Go and Libs/Kotlin **(Breaking)**: All uses of `ListOptions`/`PostOptions` are removed, and renamed to `{Resource}{Operation}Options`. For example in `Endpoint.List` you would now use `EndpointListOptions` +* Libs/Kotlin **(Breaking)**: All uses of `ListOptions`/`PostOptions` are removed, and renamed to `{Resource}{Operation}Options`. For example in `Endpoint.List` you would now use `EndpointListOptions` * Libs/Kotlin **(Breaking)**: `SvixOptions` no longer has `initialRetryDelayMillis` or `numRetries` instead use `retrySchedule` * Libs/Kotlin **(Breaking)**: Fix the parameter names of `Endpoint.get` - `appId` and `endpointId` were swapped * Libs/Kotlin **(Breaking)**: Fix the parameter names of `Message.get` and `Message.expungeContent` - `appId` and `msgId` were swapped @@ -9,7 +9,6 @@ * Libs/Kotlin **(Breaking)**: Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` are removed * Libs/Kotlin **(Breaking)**: All uses of `java.time.OffsetDateTime` replaced with `kotlinx.datetime.Instant` * Libs/Kotlin **(Breaking)**: All uses of `java.net.URL` in request/response models are replaced with `String` -* Libs/Kotlin **(Breaking)**: All uses of `Map` in request/response models are replaced with `kotlinx.serialization.json.JsonObject` ## Version 1.57.0 This version contains a big overhaul of the client libraries, with improved typing. From 37622e2ce7d16ac1001a9645f8ac4c3aba6e9894 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:03:50 -0500 Subject: [PATCH 44/56] kotlin: Document this breaking change --- ChangeLog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index ce6f506c9..c19af3ef2 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,10 +1,10 @@ # Changelog ## Unreleased + +* Libs/Kotlin **(VERY IMPORTANT)**: The parameter order `appId` and `msgId` were swapped on `Message.get` and `Message.expungeContent` * Libs/Kotlin **(Breaking)**: All uses of `ListOptions`/`PostOptions` are removed, and renamed to `{Resource}{Operation}Options`. For example in `Endpoint.List` you would now use `EndpointListOptions` * Libs/Kotlin **(Breaking)**: `SvixOptions` no longer has `initialRetryDelayMillis` or `numRetries` instead use `retrySchedule` -* Libs/Kotlin **(Breaking)**: Fix the parameter names of `Endpoint.get` - `appId` and `endpointId` were swapped -* Libs/Kotlin **(Breaking)**: Fix the parameter names of `Message.get` and `Message.expungeContent` - `appId` and `msgId` were swapped * Libs/Kotlin **(Breaking)**: All `{Resource}{Operation}Options` and model classes (`ApplicationIn`/`MessageOut`) are now data classes * Libs/Kotlin **(Breaking)**: Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` are removed * Libs/Kotlin **(Breaking)**: All uses of `java.time.OffsetDateTime` replaced with `kotlinx.datetime.Instant` From f37162bd4110c974104184cba04fb324f365a0f8 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:12:42 -0500 Subject: [PATCH 45/56] kotlin: Add test for MaybeUnset> --- .../src/test/com/svix/kotlin/WiremockTests.kt | 57 +++++++++++++++++++ .../test/resources/__files/EventTypeOut.json | 1 + 2 files changed, 58 insertions(+) create mode 100644 kotlin/lib/src/test/resources/__files/EventTypeOut.json diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index b009b2367..763c17f9a 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -7,6 +7,7 @@ import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options import com.svix.kotlin.exceptions.ApiException import com.svix.kotlin.models.AppUsageStatsIn import com.svix.kotlin.models.EndpointPatch +import com.svix.kotlin.models.EventTypePatch import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.Ordering import kotlin.test.assertEquals @@ -153,6 +154,62 @@ class WiremockTests { ) } + @Test + fun maybeUnsetOnMapStringAnyIsCorrectlySerialized() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.patch(urlMatching("/api/v1/event-type/event")) + .willReturn(WireMock.ok().withBodyFile("EventTypeOut.json")) + ) + runBlocking { + // MaybeUnset.Present + svx.eventType.patch( + "event", + EventTypePatch( + schemas = + MaybeUnset.Present( + mapOf( + "str_key" to "val", + "int_key" to 1, + "bool_key" to false, + "list_key" to listOf("val1", "val2"), + "map_key" to mapOf("key" to "val"), + ) + ) + ), + ) + // MaybeUnset.Null + svx.eventType.patch("event", EventTypePatch(schemas = MaybeUnset.Null)) + // MaybeUnset.Unset + svx.eventType.patch( + "event", + EventTypePatch(description = "42", schemas = MaybeUnset.Unset), + ) + } + // MaybeUnset.Present + wireMockServer.verify( + 1, + patchRequestedFor(urlEqualTo("/api/v1/event-type/event")) + .withRequestBody( + equalTo( + """{"schemas":{"str_key":"val","int_key":1,"bool_key":false,"list_key":["val1","val2"],"map_key":{"key":"val"}}}""" + ) + ), + ) + // MaybeUnset.Null + wireMockServer.verify( + 1, + patchRequestedFor(urlEqualTo("/api/v1/event-type/event")) + .withRequestBody(equalTo("""{"schemas":null}""")), + ) + // MaybeUnset.Unset + wireMockServer.verify( + 1, + patchRequestedFor(urlEqualTo("/api/v1/event-type/event")) + .withRequestBody(equalTo("""{"description":"42"}""")), + ) + } + @Test fun optionsHeadersAreSent() { val svx = testClient() diff --git a/kotlin/lib/src/test/resources/__files/EventTypeOut.json b/kotlin/lib/src/test/resources/__files/EventTypeOut.json new file mode 100644 index 000000000..6342c8a20 --- /dev/null +++ b/kotlin/lib/src/test/resources/__files/EventTypeOut.json @@ -0,0 +1 @@ +{"name":"user.signup","description":"A user has signed up","archived":false,"deprecated":true,"schemas":{"1":{"description":"An invoice was paid by a user","properties":{"invoiceId":{"description":"The invoice id","type":"string"},"userId":{"description":"The user id","type":"string"}},"required":["invoiceId","userId"],"title":"Invoice Paid Event","type":"object"}},"createdAt":"2019-08-24T14:15:22Z","updatedAt":"2019-08-24T14:15:22Z","featureFlag":"cool-new-feature","groupName":"user" } \ No newline at end of file From 8ffeac20ab7331e05354494e89c271a7b3f2de1d Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:38:07 -0500 Subject: [PATCH 46/56] kotlin: Add test for _very_ nested json --- .../src/test/com/svix/kotlin/WiremockTests.kt | 42 ++++++++++ .../test/resources/__files/VeryNestedMap.json | 81 +++++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 kotlin/lib/src/test/resources/__files/VeryNestedMap.json diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index 763c17f9a..127445734 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -7,6 +7,7 @@ import com.github.tomakehurst.wiremock.core.WireMockConfiguration.options import com.svix.kotlin.exceptions.ApiException import com.svix.kotlin.models.AppUsageStatsIn import com.svix.kotlin.models.EndpointPatch +import com.svix.kotlin.models.EventTypeIn import com.svix.kotlin.models.EventTypePatch import com.svix.kotlin.models.MessageIn import com.svix.kotlin.models.Ordering @@ -154,6 +155,47 @@ class WiremockTests { ) } + @Test + fun deeplyNestedMapStringAnyIsCorrectlySerialized() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.post(urlMatching("/api/v1/event-type")) + .willReturn(WireMock.ok().withBodyFile("EventTypeOut.json")) + ) + val nestedList = listOf("l1", listOf("l2", listOf("l3"))) + val sampleMap = + mapOf( + "str_key" to "val", + "int_key" to 1, + "bool_key" to false, + "list_key" to listOf("val1", "val2", nestedList), + "map_key" to mapOf("key" to "val", "list" to nestedList), + ) + val nestedMap = + mapOf( + "l1" to mapOf("l2" to mapOf("l3" to sampleMap, "more_list" to nestedList)), + "m2" to sampleMap, + ) + + runBlocking { + svx.eventType.create( + EventTypeIn(description = "", name = "", schemas = mapOf("nestedMap" to nestedMap)) + ) + } + wireMockServer.verify( + 1, + postRequestedFor(urlEqualTo("/api/v1/event-type")) + .withRequestBody( + equalToJson( + wireMockServer.options.stores.filesBlobStore + .get("VeryNestedMap.json") + .get() + .toString(Charsets.UTF_8) + ) + ), + ) + } + @Test fun maybeUnsetOnMapStringAnyIsCorrectlySerialized() { val svx = testClient() diff --git a/kotlin/lib/src/test/resources/__files/VeryNestedMap.json b/kotlin/lib/src/test/resources/__files/VeryNestedMap.json new file mode 100644 index 000000000..428395fc3 --- /dev/null +++ b/kotlin/lib/src/test/resources/__files/VeryNestedMap.json @@ -0,0 +1,81 @@ +{ + "description": "", + "name": "", + "schemas": { + "nestedMap": { + "l1": { + "l2": { + "l3": { + "str_key": "val", + "int_key": 1, + "bool_key": false, + "list_key": [ + "val1", + "val2", + [ + "l1", + [ + "l2", + [ + "l3" + ] + ] + ] + ], + "map_key": { + "key": "val", + "list": [ + "l1", + [ + "l2", + [ + "l3" + ] + ] + ] + } + }, + "more_list": [ + "l1", + [ + "l2", + [ + "l3" + ] + ] + ] + } + }, + "m2": { + "str_key": "val", + "int_key": 1, + "bool_key": false, + "list_key": [ + "val1", + "val2", + [ + "l1", + [ + "l2", + [ + "l3" + ] + ] + ] + ], + "map_key": { + "key": "val", + "list": [ + "l1", + [ + "l2", + [ + "l3" + ] + ] + ] + } + } + } + } +} \ No newline at end of file From 6d344f877d3562af49f0369451e60f8ba810a795 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:42:20 -0500 Subject: [PATCH 47/56] kotlin: Document `MaybeUnset` --- ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.md b/ChangeLog.md index c19af3ef2..261312fb3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,6 +4,7 @@ * Libs/Kotlin **(VERY IMPORTANT)**: The parameter order `appId` and `msgId` were swapped on `Message.get` and `Message.expungeContent` * Libs/Kotlin **(Breaking)**: All uses of `ListOptions`/`PostOptions` are removed, and renamed to `{Resource}{Operation}Options`. For example in `Endpoint.List` you would now use `EndpointListOptions` +* Libs/Kotlin **(Breaking)**: In the 4 `*Patch` patch models, nullable fields are of type `MaybeUnset` instead of `T`. call `MaybeUnset.Present(val)` to initialize this value * Libs/Kotlin **(Breaking)**: `SvixOptions` no longer has `initialRetryDelayMillis` or `numRetries` instead use `retrySchedule` * Libs/Kotlin **(Breaking)**: All `{Resource}{Operation}Options` and model classes (`ApplicationIn`/`MessageOut`) are now data classes * Libs/Kotlin **(Breaking)**: Deprecated functions `MessageAttempt.list` and `MessageAttempt.listAttemptsForEndpoint` are removed From 8399b4205c1b7675e8e7c24163e84bd7818ca19c Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:43:59 -0500 Subject: [PATCH 48/56] kotlin: Break this test to show that it does something --- kotlin/lib/src/test/resources/__files/VeryNestedMap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/lib/src/test/resources/__files/VeryNestedMap.json b/kotlin/lib/src/test/resources/__files/VeryNestedMap.json index 428395fc3..6a5b1b133 100644 --- a/kotlin/lib/src/test/resources/__files/VeryNestedMap.json +++ b/kotlin/lib/src/test/resources/__files/VeryNestedMap.json @@ -1,6 +1,6 @@ { "description": "", - "name": "", + "name": "now tests will break", "schemas": { "nestedMap": { "l1": { From 6f6f30898560f8035e0314b4ae5303e001916552 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:45:51 -0500 Subject: [PATCH 49/56] kotlin: Now tests pass --- kotlin/lib/src/test/resources/__files/VeryNestedMap.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/lib/src/test/resources/__files/VeryNestedMap.json b/kotlin/lib/src/test/resources/__files/VeryNestedMap.json index 6a5b1b133..428395fc3 100644 --- a/kotlin/lib/src/test/resources/__files/VeryNestedMap.json +++ b/kotlin/lib/src/test/resources/__files/VeryNestedMap.json @@ -1,6 +1,6 @@ { "description": "", - "name": "now tests will break", + "name": "", "schemas": { "nestedMap": { "l1": { From 1a84a58795b02f640f92e5d95cb5be26ed50641c Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:49:41 -0500 Subject: [PATCH 50/56] kotlin: Show full logs if tests fail --- kotlin/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kotlin/build.gradle b/kotlin/build.gradle index 4bb923f97..5f0d1655b 100644 --- a/kotlin/build.gradle +++ b/kotlin/build.gradle @@ -44,6 +44,10 @@ sourceSets { test { useJUnitPlatform() + testLogging { + events "failed" + exceptionFormat "full" + } } dependencies { From c21d5714e4f4cb122acae47a3be8d4c3332c082e Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 14:51:40 -0500 Subject: [PATCH 51/56] kotlin: Remove openapi-generator config for kotlin --- .../openapi/.openapi-generator-ignore | 23 - kotlin/openapi-generator-config.json | 5 - .../infrastructure/ApiClient.kt.mustache | 474 ------------------ regen_openapi.sh | 2 - 4 files changed, 504 deletions(-) delete mode 100644 kotlin/lib/generated/openapi/.openapi-generator-ignore delete mode 100644 kotlin/openapi-generator-config.json delete mode 100644 kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache diff --git a/kotlin/lib/generated/openapi/.openapi-generator-ignore b/kotlin/lib/generated/openapi/.openapi-generator-ignore deleted file mode 100644 index 7484ee590..000000000 --- a/kotlin/lib/generated/openapi/.openapi-generator-ignore +++ /dev/null @@ -1,23 +0,0 @@ -# OpenAPI Generator Ignore -# Generated by openapi-generator https://github.com/openapitools/openapi-generator - -# Use this file to prevent files from being overwritten by the generator. -# The patterns follow closely to .gitignore or .dockerignore. - -# As an example, the C# client generator defines ApiClient.cs. -# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: -#ApiClient.cs - -# You can match any string of characters against a directory, file or extension with a single asterisk (*): -#foo/*/qux -# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux - -# You can recursively match patterns against a directory, file or extension with a double asterisk (**): -#foo/**/qux -# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux - -# You can also negate patterns with an exclamation (!). -# For example, you can ignore all files in a docs folder with the file extension .md: -#docs/*.md -# Then explicitly reverse the ignore rule for a single file: -#!docs/README.md diff --git a/kotlin/openapi-generator-config.json b/kotlin/openapi-generator-config.json deleted file mode 100644 index d92146d86..000000000 --- a/kotlin/openapi-generator-config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "packageName": "com.svix.kotlin.internal", - "modelPackage": "com.svix.kotlin.models", - "useCoroutines": true -} diff --git a/kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache b/kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache deleted file mode 100644 index e3c4729f2..000000000 --- a/kotlin/templates/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache +++ /dev/null @@ -1,474 +0,0 @@ -package {{packageName}}.infrastructure - -{{#supportAndroidApiLevel25AndBelow}} -import android.os.Build -{{/supportAndroidApiLevel25AndBelow}} -import okhttp3.OkHttpClient -import okhttp3.RequestBody -import okhttp3.RequestBody.Companion.asRequestBody -import okhttp3.RequestBody.Companion.toRequestBody -import okhttp3.FormBody -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull -import okhttp3.ResponseBody -import okhttp3.MediaType.Companion.toMediaTypeOrNull -import okhttp3.Request -import okhttp3.Headers -import okhttp3.Headers.Companion.toHeaders -import okhttp3.MultipartBody -import okhttp3.Call -import okhttp3.Callback -import okhttp3.Response -import java.io.BufferedWriter -import java.io.File -import java.io.FileWriter -import java.io.IOException -import java.net.URLConnection -{{^threetenbp}} -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.LocalTime -import java.time.OffsetDateTime -import java.time.OffsetTime -{{/threetenbp}} -import java.util.Locale -import java.util.regex.Pattern -{{#useCoroutines}} -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException -import kotlinx.coroutines.suspendCancellableCoroutine -{{/useCoroutines}} -{{#kotlinx_serialization}} -import kotlinx.serialization.decodeFromString -import kotlinx.serialization.encodeToString -{{/kotlinx_serialization}} -{{#threetenbp}} -import org.threeten.bp.LocalDate -import org.threeten.bp.LocalDateTime -import org.threeten.bp.LocalTime -import org.threeten.bp.OffsetDateTime -import org.threeten.bp.OffsetTime -{{/threetenbp}} -{{#gson}} -import com.google.gson.reflect.TypeToken -{{/gson}} -{{#jackson}} -import com.fasterxml.jackson.core.type.TypeReference -{{/jackson}} -{{#moshi}} -import com.squareup.moshi.adapter -{{/moshi}} -import kotlinx.coroutines.delay -import kotlin.random.Random - -{{#nonPublicApi}}internal {{/nonPublicApi}}val EMPTY_REQUEST: RequestBody = ByteArray(0).toRequestBody() - -{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient(val baseUrl: String, val client: Call.Factory = defaultClient) { - {{#nonPublicApi}}internal {{/nonPublicApi}}companion object { - protected const val ContentType = "Content-Type" - protected const val Accept = "Accept" - protected const val Authorization = "Authorization" - protected const val JsonMediaType = "application/json" - protected const val FormDataMediaType = "multipart/form-data" - protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded" - protected const val XmlMediaType = "application/xml" - protected const val UserAgent = "User-Agent" - protected const val OctetMediaType = "application/octet-stream" - - val apiKey: MutableMap = mutableMapOf() - val apiKeyPrefix: MutableMap = mutableMapOf() - var username: String? = null - var password: String? = null - const val baseUrlKey = "{{packageName}}.baseUrl" - - @JvmStatic - val defaultClient: OkHttpClient by lazy { - builder.build() - } - - @JvmStatic - val builder: OkHttpClient.Builder = OkHttpClient.Builder() - } - - var accessToken: String? = null - var userAgent: String? = null - var initialRetryDelayMillis = 50L - var numRetries: Int = 3 - - /** - * Guess Content-Type header from the given file (defaults to "application/octet-stream"). - * - * @param file The given file - * @return The guessed Content-Type - */ - protected fun guessContentTypeFromFile(file: File): String { - val contentType = URLConnection.guessContentTypeFromName(file.name) - return contentType ?: "application/octet-stream" - } - - protected inline fun requestBody(content: T, mediaType: String?): RequestBody = - when { - content is File -> content.asRequestBody((mediaType ?: guessContentTypeFromFile(content)).toMediaTypeOrNull()) - mediaType == FormDataMediaType -> - MultipartBody.Builder() - .setType(MultipartBody.FORM) - .apply { - // content's type *must* be Map> - @Suppress("UNCHECKED_CAST") - (content as Map>).forEach { (name, part) -> - if (part.body is File) { - val partHeaders = part.headers.toMutableMap() + - ("Content-Disposition" to "form-data; name=\"$name\"; filename=\"${part.body.name}\"") - val fileMediaType = guessContentTypeFromFile(part.body).toMediaTypeOrNull() - addPart( - partHeaders.toHeaders(), - part.body.asRequestBody(fileMediaType) - ) - } else { - val partHeaders = part.headers.toMutableMap() + - ("Content-Disposition" to "form-data; name=\"$name\"") - addPart( - partHeaders.toHeaders(), - parameterToString(part.body).toRequestBody(null) - ) - } - } - }.build() - mediaType == FormUrlEncMediaType -> { - FormBody.Builder().apply { - // content's type *must* be Map> - @Suppress("UNCHECKED_CAST") - (content as Map>).forEach { (name, part) -> - add(name, parameterToString(part.body)) - } - }.build() - } - mediaType == null || mediaType.startsWith("application/") && mediaType.endsWith("json") -> - if (content == null) { - // FIXME(onelson): double check that this is where we land on DELETE requests - // We initially had to patch the client for responses without a body. - // Ref: https://github.com/svix/svix-webhooks/pull/1124 - EMPTY_REQUEST - } else { - {{#moshi}} - Serializer.moshi.adapter(T::class.java).toJson(content) - {{/moshi}} - {{#gson}} - Serializer.gson.toJson(content, T::class.java) - {{/gson}} - {{#jackson}} - Serializer.jacksonObjectMapper.writeValueAsString(content) - {{/jackson}} - {{#kotlinx_serialization}} - Serializer.kotlinxSerializationJson.encodeToString(content) - {{/kotlinx_serialization}} - .toRequestBody((mediaType ?: JsonMediaType).toMediaTypeOrNull()) - } - mediaType == XmlMediaType -> throw UnsupportedOperationException("xml not currently supported.") - mediaType == OctetMediaType && content is ByteArray -> - content.toRequestBody(OctetMediaType.toMediaTypeOrNull()) - // TODO: this should be extended with other serializers - else -> throw UnsupportedOperationException("requestBody currently only supports JSON body, byte body and File body.") - } - - {{#moshi}} - @OptIn(ExperimentalStdlibApi::class) - {{/moshi}} - protected inline fun responseBody(response: Response, mediaType: String? = JsonMediaType): T? { - val body = response.body - if(body == null) { - return null - } else if (T::class.java == Unit::class.java) { - // No need to parse the body when we're not interested in the body - // Useful when API is returning other Content-Type - return null - } else if (T::class.java == File::class.java) { - // return tempFile - val contentDisposition = response.header("Content-Disposition") - - val fileName = if (contentDisposition != null) { - // Get filename from the Content-Disposition header. - val pattern = Pattern.compile("filename=['\"]?([^'\"\\s]+)['\"]?") - val matcher = pattern.matcher(contentDisposition) - if (matcher.find()) { - matcher.group(1) - ?.replace(".*[/\\\\]", "") - ?.replace(";", "") - } else { - null - } - } else { - null - } - - var prefix: String? - val suffix: String? - if (fileName == null) { - prefix = "download" - suffix = "" - } else { - val pos = fileName.lastIndexOf(".") - if (pos == -1) { - prefix = fileName - suffix = null - } else { - prefix = fileName.substring(0, pos) - suffix = fileName.substring(pos) - } - // Files.createTempFile requires the prefix to be at least three characters long - if (prefix.length < 3) { - prefix = "download" - } - } - - {{^supportAndroidApiLevel25AndBelow}} - // Attention: if you are developing an android app that supports API Level 25 and bellow, please check flag supportAndroidApiLevel25AndBelow in https://openapi-generator.tech/docs/generators/kotlin#config-options - val tempFile = java.nio.file.Files.createTempFile(prefix, suffix).toFile() - {{/supportAndroidApiLevel25AndBelow}} - {{#supportAndroidApiLevel25AndBelow}} - val tempFile = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - java.nio.file.Files.createTempFile(prefix, suffix).toFile() - } else { - @Suppress("DEPRECATION") - createTempFile(prefix, suffix) - } - {{/supportAndroidApiLevel25AndBelow}} - tempFile.deleteOnExit() - body.byteStream().use { inputStream -> - tempFile.outputStream().use { tempFileOutputStream -> - inputStream.copyTo(tempFileOutputStream) - } - } - return tempFile as T - } - - return when { - mediaType == null || (mediaType.startsWith("application/") && mediaType.endsWith("json")) -> { - val bodyContent = body.string() - if (bodyContent.isEmpty()) { - return null - } - {{#moshi}}Serializer.moshi.adapter().fromJson(bodyContent){{/moshi}}{{! - }}{{#gson}}Serializer.gson.fromJson(bodyContent, (object: TypeToken(){}).getType()){{/gson}}{{! - }}{{#jackson}}Serializer.jacksonObjectMapper.readValue(bodyContent, object: TypeReference() {}){{/jackson}}{{! - }}{{#kotlinx_serialization}}Serializer.kotlinxSerializationJson.decodeFromString(bodyContent){{/kotlinx_serialization}} - } - mediaType == OctetMediaType -> body.bytes() as? T - else -> throw UnsupportedOperationException("responseBody currently only supports JSON body.") - } - } - - {{#hasAuthMethods}} - protected fun updateAuthParams(requestConfig: RequestConfig) { - {{#authMethods}} - {{#isApiKey}} - {{#isKeyInHeader}} - if (requestConfig.headers["{{keyParamName}}"].isNullOrEmpty()) { - {{/isKeyInHeader}} - {{#isKeyInQuery}} - if (requestConfig.query["{{keyParamName}}"].isNullOrEmpty()) { - {{/isKeyInQuery}} - if (apiKey["{{keyParamName}}"] != null) { - if (apiKeyPrefix["{{keyParamName}}"] != null) { - {{#isKeyInHeader}} - requestConfig.headers["{{keyParamName}}"] = apiKeyPrefix["{{keyParamName}}"]!! + " " + apiKey["{{keyParamName}}"]!! - {{/isKeyInHeader}} - {{#isKeyInQuery}} - requestConfig.query["{{keyParamName}}"] = listOf(apiKeyPrefix["{{keyParamName}}"]!! + " " + apiKey["{{keyParamName}}"]!!) - {{/isKeyInQuery}} - } else { - {{#isKeyInHeader}} - requestConfig.headers["{{keyParamName}}"] = apiKey["{{keyParamName}}"]!! - {{/isKeyInHeader}} - {{#isKeyInQuery}} - requestConfig.query["{{keyParamName}}"] = listOf(apiKey["{{keyParamName}}"]!!) - {{/isKeyInQuery}} - } - } - {{#isKeyInQuery}} - } - {{/isKeyInQuery}} - {{#isKeyInHeader}} - } - {{/isKeyInHeader}} - {{/isApiKey}} - {{#isBasic}} - {{#isBasicBasic}} - if (requestConfig.headers[Authorization].isNullOrEmpty()) { - username?.let { username -> - password?.let { password -> - requestConfig.headers[Authorization] = okhttp3.Credentials.basic(username, password) - } - } - } - {{/isBasicBasic}} - {{#isBasicBearer}} - if (requestConfig.headers[Authorization].isNullOrEmpty()) { - accessToken?.let { accessToken -> - requestConfig.headers[Authorization] = "Bearer $accessToken" - } - } - {{/isBasicBearer}} - {{/isBasic}} - {{#isOAuth}} - if (requestConfig.headers[Authorization].isNullOrEmpty()) { - accessToken?.let { accessToken -> - requestConfig.headers[Authorization] = "Bearer $accessToken " - } - } - {{/isOAuth}} - {{/authMethods}} - } - {{/hasAuthMethods}} - - protected {{#useCoroutines}}suspend {{/useCoroutines}}inline fun request(requestConfig: RequestConfig): ApiResponse { - val httpUrl = baseUrl.toHttpUrlOrNull() ?: throw IllegalStateException("baseUrl is invalid.") - {{#hasAuthMethods}} - - // take authMethod from operation - updateAuthParams(requestConfig) - {{/hasAuthMethods}} - - // add user agent - if (requestConfig.headers[UserAgent].isNullOrEmpty()) { - userAgent?.let { userAgent -> - requestConfig.headers[UserAgent] = userAgent - } - } - - val url = httpUrl.newBuilder() - .addEncodedPathSegments(requestConfig.path.trimStart('/')) - .apply { - requestConfig.query.forEach { query -> - query.value.forEach { queryValue -> - addQueryParameter(query.key, queryValue) - } - } - }.build() - - // take content-type/accept from spec or set to default (application/json) if not defined - if (requestConfig.body != null && requestConfig.headers[ContentType].isNullOrEmpty()) { - requestConfig.headers[ContentType] = JsonMediaType - } - if (requestConfig.headers["svix-req-id"].isNullOrEmpty()) { - requestConfig.headers["svix-req-id"] = Math.abs(Random.nextBits(32)).toString() - } - if (requestConfig.headers[Accept].isNullOrEmpty()) { - requestConfig.headers[Accept] = JsonMediaType - } - val headers = requestConfig.headers - - if (headers[Accept].isNullOrEmpty()) { - throw kotlin.IllegalStateException("Missing Accept header. This is required.") - } - - val contentType = if (headers[ContentType] != null) { - // TODO: support multiple contentType options here. - (headers[ContentType] as String).substringBefore(";").lowercase(Locale.US) - } else { - null - } - - val request = when (requestConfig.method) { - RequestMethod.DELETE -> Request.Builder().url(url).delete(requestBody(requestConfig.body, contentType)) - RequestMethod.GET -> Request.Builder().url(url) - RequestMethod.HEAD -> Request.Builder().url(url).head() - RequestMethod.PATCH -> Request.Builder().url(url).patch(requestBody(requestConfig.body, contentType)) - RequestMethod.PUT -> Request.Builder().url(url).put(requestBody(requestConfig.body, contentType)) - RequestMethod.POST -> Request.Builder().url(url).post(requestBody(requestConfig.body, contentType)) - RequestMethod.OPTIONS -> Request.Builder().url(url).method("OPTIONS", null) - }.apply { - headers.forEach { header -> addHeader(header.key, header.value) } - }.build() - - - // FIXME(onelson): the upstream generator template has the below block for the useCoroutines=false case. - // More reading up on kotlin required before it's clear how to do a retry loop over a suspendable. - // For now, we'll do the non-coroutine thing. - // Ref: https://github.com/OpenAPITools/openapi-generator/blob/4145000dfebe7a9edea4555c8515383da7602458/modules/openapi-generator/src/main/resources/kotlin-client/libraries/jvm-okhttp/infrastructure/ApiClient.kt.mustache#L363-L376 - var response = client.newCall(request).execute() - - var sleepTime = initialRetryDelayMillis - var retryCount = 0 - for (i in 0 until numRetries-1) { - if (response.isSuccessful || response.code < 500) { - break - } - response.close() - retryCount = retryCount.inc() - delay(sleepTime) - sleepTime = sleepTime * 2 - var newRequest = request.newBuilder().header("svix-retry-count", retryCount.toString()).build() - response = client.newCall(newRequest).execute() - } - - val accept = response.header(ContentType)?.substringBefore(";")?.lowercase(Locale.US) - - // TODO: handle specific mapping types. e.g. Map> - @Suppress("UNNECESSARY_SAFE_CALL") - return response.use { - when { - it.isRedirect -> Redirection( - it.code, - it.headers.toMultimap() - ) - it.isInformational -> Informational( - it.message, - it.code, - it.headers.toMultimap() - ) - it.isSuccessful -> Success( - responseBody(it, accept), - it.code, - it.headers.toMultimap() - ) - it.isClientError -> ClientError( - it.message, - it.body?.string(), - it.code, - it.headers.toMultimap() - ) - else -> ServerError( - it.message, - it.body?.string(), - it.code, - it.headers.toMultimap() - ) - } - } - } - - protected fun parameterToString(value: Any?): String = when (value) { - null -> "" - is Array<*> -> toMultiValue(value, "csv").toString() - is Iterable<*> -> toMultiValue(value, "csv").toString() - is OffsetDateTime, is OffsetTime, is LocalDateTime, is LocalDate, is LocalTime -> - parseDateToQueryString(value) - else -> value.toString() - } - - protected inline fun parseDateToQueryString(value : T): String { - {{#toJson}} - /* - .replace("\"", "") converts the json object string to an actual string for the query parameter. - The moshi or gson adapter allows a more generic solution instead of trying to use a native - formatter. It also easily allows to provide a simple way to define a custom date format pattern - inside a gson/moshi adapter. - */ - {{#moshi}} - return Serializer.moshi.adapter(T::class.java).toJson(value).replace("\"", "") - {{/moshi}} - {{#gson}} - return Serializer.gson.toJson(value, T::class.java).replace("\"", "") - {{/gson}} - {{#jackson}} - return Serializer.jacksonObjectMapper.writeValueAsString(value).replace("\"", "") - {{/jackson}} - {{#kotlinx_serialization}} - return Serializer.kotlinxSerializationJson.encodeToString(value).replace("\"", "") - {{/kotlinx_serialization}} - {{/toJson}} - {{^toJson}} - return value.toString() - {{/toJson}} - } -} diff --git a/regen_openapi.sh b/regen_openapi.sh index ad9138670..f21fbf827 100755 --- a/regen_openapi.sh +++ b/regen_openapi.sh @@ -57,8 +57,6 @@ yarn openapi-generator-cli generate -i .codegen-tmp/openapi.json -g typescript - yarn openapi-generator-cli generate -i .codegen-tmp/openapi.json -g java -o java/lib/generated/openapi -c java/openapi-generator-config.json -t java/templates -yarn openapi-generator-cli generate -i .codegen-tmp/openapi.json -g kotlin -o kotlin/lib/generated/openapi -c kotlin/openapi-generator-config.json -t kotlin/templates - yarn openapi-generator-cli generate -i .codegen-tmp/openapi.json -g ruby -o ruby -c ruby/openapi-generator-config.json -t ruby/templates rm -rf .codegen-tmp From 0a7642747805ae28a4c6df51fd35ac3cbc48dce0 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Thu, 13 Feb 2025 18:26:40 -0500 Subject: [PATCH 52/56] kotlin: Add doc comments to *Options fields --- kotlin/lib/src/main/kotlin/Application.kt | 3 ++ kotlin/lib/src/main/kotlin/BackgroundTask.kt | 5 +++ kotlin/lib/src/main/kotlin/Endpoint.kt | 10 ++++- kotlin/lib/src/main/kotlin/EventType.kt | 13 +++++- kotlin/lib/src/main/kotlin/Integration.kt | 3 ++ kotlin/lib/src/main/kotlin/Message.kt | 14 ++++++- kotlin/lib/src/main/kotlin/MessageAttempt.kt | 42 +++++++++++++++++++ .../main/kotlin/OperationalWebhookEndpoint.kt | 3 ++ 8 files changed, 90 insertions(+), 3 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/Application.kt b/kotlin/lib/src/main/kotlin/Application.kt index 059c894ec..dc768cb0a 100644 --- a/kotlin/lib/src/main/kotlin/Application.kt +++ b/kotlin/lib/src/main/kotlin/Application.kt @@ -9,8 +9,11 @@ import com.svix.kotlin.models.Ordering import okhttp3.Headers data class ApplicationListOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** The sorting order of the returned items */ val order: Ordering? = null, ) diff --git a/kotlin/lib/src/main/kotlin/BackgroundTask.kt b/kotlin/lib/src/main/kotlin/BackgroundTask.kt index 6a2444c9b..3f13bad70 100644 --- a/kotlin/lib/src/main/kotlin/BackgroundTask.kt +++ b/kotlin/lib/src/main/kotlin/BackgroundTask.kt @@ -8,10 +8,15 @@ import com.svix.kotlin.models.ListResponseBackgroundTaskOut import com.svix.kotlin.models.Ordering data class BackgroundTaskListOptions( + /** Filter the response based on the status. */ val status: BackgroundTaskStatus? = null, + /** Filter the response based on the type. */ val task: BackgroundTaskType? = null, + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** The sorting order of the returned items */ val order: Ordering? = null, ) diff --git a/kotlin/lib/src/main/kotlin/Endpoint.kt b/kotlin/lib/src/main/kotlin/Endpoint.kt index 7fb29fd46..64dfb4024 100644 --- a/kotlin/lib/src/main/kotlin/Endpoint.kt +++ b/kotlin/lib/src/main/kotlin/Endpoint.kt @@ -25,8 +25,11 @@ import kotlinx.datetime.Instant import okhttp3.Headers data class EndpointListOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** The sorting order of the returned items */ val order: Ordering? = null, ) @@ -40,7 +43,12 @@ data class EndpointRotateSecretOptions(val idempotencyKey: String? = null) data class EndpointSendExampleOptions(val idempotencyKey: String? = null) -data class EndpointGetStatsOptions(val since: Instant? = null, val until: Instant? = null) +data class EndpointGetStatsOptions( + /** Filter the range to data starting from this date. */ + val since: Instant? = null, + /** Filter the range to data ending by this date. */ + val until: Instant? = null, +) class Endpoint(private val client: SvixHttpClient) { diff --git a/kotlin/lib/src/main/kotlin/EventType.kt b/kotlin/lib/src/main/kotlin/EventType.kt index 978d59d34..c19ef07ab 100644 --- a/kotlin/lib/src/main/kotlin/EventType.kt +++ b/kotlin/lib/src/main/kotlin/EventType.kt @@ -12,10 +12,15 @@ import com.svix.kotlin.models.Ordering import okhttp3.Headers data class EventTypeListOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** The sorting order of the returned items */ val order: Ordering? = null, + /** When `true` archived (deleted but not expunged) items are included in the response. */ val includeArchived: Boolean? = null, + /** When `true` the full item (including the schema) is included in the response. */ val withContent: Boolean? = null, ) @@ -23,7 +28,13 @@ data class EventTypeCreateOptions(val idempotencyKey: String? = null) data class EventTypeImportOpenapiOptions(val idempotencyKey: String? = null) -data class EventTypeDeleteOptions(val expunge: Boolean? = null) +data class EventTypeDeleteOptions( + /** + * By default event types are archived when "deleted". Passing this to `true` deletes them + * entirely. + */ + val expunge: Boolean? = null +) class EventType(private val client: SvixHttpClient) { diff --git a/kotlin/lib/src/main/kotlin/Integration.kt b/kotlin/lib/src/main/kotlin/Integration.kt index 777ac831e..fecdbdd42 100644 --- a/kotlin/lib/src/main/kotlin/Integration.kt +++ b/kotlin/lib/src/main/kotlin/Integration.kt @@ -10,8 +10,11 @@ import com.svix.kotlin.models.Ordering import okhttp3.Headers data class IntegrationListOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** The sorting order of the returned items */ val order: Ordering? = null, ) diff --git a/kotlin/lib/src/main/kotlin/Message.kt b/kotlin/lib/src/main/kotlin/Message.kt index bb46f7e4a..85428c720 100644 --- a/kotlin/lib/src/main/kotlin/Message.kt +++ b/kotlin/lib/src/main/kotlin/Message.kt @@ -12,22 +12,34 @@ import kotlinx.serialization.json.JsonPrimitive import okhttp3.Headers data class MessageListOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** Filter response based on the channel. */ val channel: String? = null, + /** Only include items created before a certain date. */ val before: Instant? = null, + /** Only include items created after a certain date. */ val after: Instant? = null, + /** When `true` message payloads are included in the response. */ val withContent: Boolean? = null, + /** Filter messages matching the provided tag. */ val tag: String? = null, + /** Filter response based on the event type */ val eventTypes: Set? = null, ) data class MessageCreateOptions( + /** When `true`, message payloads are included in the response. */ val withContent: Boolean? = null, val idempotencyKey: String? = null, ) -data class MessageGetOptions(val withContent: Boolean? = null) +data class MessageGetOptions( + /** When `true` message payloads are included in the response. */ + val withContent: Boolean? = null +) class Message(private val client: SvixHttpClient) { diff --git a/kotlin/lib/src/main/kotlin/MessageAttempt.kt b/kotlin/lib/src/main/kotlin/MessageAttempt.kt index c2726f3a2..dd7e99fd2 100644 --- a/kotlin/lib/src/main/kotlin/MessageAttempt.kt +++ b/kotlin/lib/src/main/kotlin/MessageAttempt.kt @@ -11,47 +11,89 @@ import kotlinx.datetime.Instant import okhttp3.Headers data class MessageAttemptListByEndpointOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** + * Filter response based on the status of the attempt: Success (0), Pending (1), Failed (2), or + * Sending (3) + */ val status: MessageStatus? = null, + /** Filter response based on the HTTP status code */ val statusCodeClass: StatusCodeClass? = null, + /** Filter response based on the channel */ val channel: String? = null, + /** Filter response based on the tag */ val tag: String? = null, + /** Only include items created before a certain date */ val before: Instant? = null, + /** Only include items created after a certain date */ val after: Instant? = null, + /** When `true` attempt content is included in the response */ val withContent: Boolean? = null, + /** When `true`, the message information is included in the response */ val withMsg: Boolean? = null, + /** Filter response based on the event type */ val eventTypes: Set? = null, ) data class MessageAttemptListByMsgOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** + * Filter response based on the status of the attempt: Success (0), Pending (1), Failed (2), or + * Sending (3) + */ val status: MessageStatus? = null, + /** Filter response based on the HTTP status code */ val statusCodeClass: StatusCodeClass? = null, + /** Filter response based on the channel */ val channel: String? = null, + /** Filter response based on the tag */ val tag: String? = null, + /** Filter the attempts based on the attempted endpoint */ val endpointId: String? = null, + /** Only include items created before a certain date */ val before: Instant? = null, + /** Only include items created after a certain date */ val after: Instant? = null, + /** When `true` attempt content is included in the response */ val withContent: Boolean? = null, + /** Filter response based on the event type */ val eventTypes: Set? = null, ) data class MessageAttemptListAttemptedMessagesOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** Filter response based on the channel */ val channel: String? = null, + /** Filter response based on the message tags */ val tag: String? = null, + /** + * Filter response based on the status of the attempt: Success (0), Pending (1), Failed (2), or + * Sending (3) + */ val status: MessageStatus? = null, + /** Only include items created before a certain date */ val before: Instant? = null, + /** Only include items created after a certain date */ val after: Instant? = null, + /** When `true` message payloads are included in the response */ val withContent: Boolean? = null, + /** Filter response based on the event type */ val eventTypes: Set? = null, ) data class MessageAttemptListAttemptedDestinationsOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt index 04bbc62c1..8a38de1ae 100644 --- a/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt +++ b/kotlin/lib/src/main/kotlin/OperationalWebhookEndpoint.kt @@ -13,8 +13,11 @@ import com.svix.kotlin.models.Ordering import okhttp3.Headers data class OperationalWebhookEndpointListOptions( + /** Limit the number of returned items */ val limit: ULong? = null, + /** The iterator returned from a prior invocation */ val iterator: String? = null, + /** The sorting order of the returned items */ val order: Ordering? = null, ) From 93a9a46ae6bbda7759be54b6b14945b19b8a4cd7 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Sun, 16 Feb 2025 13:52:01 -0500 Subject: [PATCH 53/56] kotlin: Delete app after tests are completed --- kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt index 7ba62c258..89a285e12 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/BasicTest.kt @@ -101,6 +101,7 @@ class BasicTest { epPatched.filterTypes, "patched ep should have 2 filter types", ) + svix.application.delete(appOut.id) } } } From a8c62c13a8ecf94960c8da8014ee20eca75b2ff7 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Sun, 16 Feb 2025 13:56:36 -0500 Subject: [PATCH 54/56] kotlin: Pull in changes from new `lib-openapi.json` --- .../main/kotlin/models/BackgroundTaskType.kt | 3 ++- .../lib/src/main/kotlin/models/ConnectorIn.kt | 17 ++++++++++++ .../src/main/kotlin/models/ConnectorKind.kt | 27 +++++++++++++++++++ .../kotlin/models/ExpungAllContentsOut.kt | 11 ++++++++ .../src/main/kotlin/models/IntegrationIn.kt | 2 +- .../src/main/kotlin/models/IntegrationOut.kt | 1 + .../main/kotlin/models/IntegrationUpdate.kt | 2 +- 7 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 kotlin/lib/src/main/kotlin/models/ConnectorIn.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ConnectorKind.kt create mode 100644 kotlin/lib/src/main/kotlin/models/ExpungAllContentsOut.kt diff --git a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt index 26bf4b161..2f9a2b652 100644 --- a/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt +++ b/kotlin/lib/src/main/kotlin/models/BackgroundTaskType.kt @@ -15,7 +15,8 @@ enum class BackgroundTaskType : ToQueryParam { @SerialName("application.stats") APPLICATION_STATS, @SerialName("message.broadcast") MESSAGE_BROADCAST, @SerialName("sdk.generate") SDK_GENERATE, - @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE; + @SerialName("event-type.aggregate") EVENT_TYPE_AGGREGATE, + @SerialName("application.purge_content") APPLICATION_PURGE_CONTENT; override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content } diff --git a/kotlin/lib/src/main/kotlin/models/ConnectorIn.kt b/kotlin/lib/src/main/kotlin/models/ConnectorIn.kt new file mode 100644 index 000000000..07c35f089 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ConnectorIn.kt @@ -0,0 +1,17 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ConnectorIn( + val description: String? = null, + val featureFlag: String? = null, + val filterTypes: Set? = null, + val instructions: String? = null, + val instructionsLink: String? = null, + val kind: ConnectorKind? = null, + val logo: String, + val name: String, + val transformation: String, +) diff --git a/kotlin/lib/src/main/kotlin/models/ConnectorKind.kt b/kotlin/lib/src/main/kotlin/models/ConnectorKind.kt new file mode 100644 index 000000000..11ef1cfd9 --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ConnectorKind.kt @@ -0,0 +1,27 @@ +// This file is @generated +package com.svix.kotlin.models + +import com.svix.kotlin.ToQueryParam +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.encodeToJsonElement +import kotlinx.serialization.json.jsonPrimitive + +@Serializable +enum class ConnectorKind : ToQueryParam { + @SerialName("Custom") CUSTOM, + @SerialName("CustomerIO") CUSTOMER_IO, + @SerialName("Discord") DISCORD, + @SerialName("Hubspot") HUBSPOT, + @SerialName("Inngest") INNGEST, + @SerialName("Salesforce") SALESFORCE, + @SerialName("Segment") SEGMENT, + @SerialName("Slack") SLACK, + @SerialName("Teams") TEAMS, + @SerialName("TriggerDev") TRIGGER_DEV, + @SerialName("Windmill") WINDMILL, + @SerialName("Zapier") ZAPIER; + + override fun toQueryParam() = Json.encodeToJsonElement(this).jsonPrimitive.content +} diff --git a/kotlin/lib/src/main/kotlin/models/ExpungAllContentsOut.kt b/kotlin/lib/src/main/kotlin/models/ExpungAllContentsOut.kt new file mode 100644 index 000000000..0e3c0c30d --- /dev/null +++ b/kotlin/lib/src/main/kotlin/models/ExpungAllContentsOut.kt @@ -0,0 +1,11 @@ +// This file is @generated +package com.svix.kotlin.models + +import kotlinx.serialization.Serializable + +@Serializable +data class ExpungAllContentsOut( + val id: String, + val status: BackgroundTaskStatus, + val task: BackgroundTaskType, +) diff --git a/kotlin/lib/src/main/kotlin/models/IntegrationIn.kt b/kotlin/lib/src/main/kotlin/models/IntegrationIn.kt index 5292b7b50..7d8ff5e1c 100644 --- a/kotlin/lib/src/main/kotlin/models/IntegrationIn.kt +++ b/kotlin/lib/src/main/kotlin/models/IntegrationIn.kt @@ -3,4 +3,4 @@ package com.svix.kotlin.models import kotlinx.serialization.Serializable -@Serializable data class IntegrationIn(val name: String) +@Serializable data class IntegrationIn(val featureFlags: Set? = null, val name: String) diff --git a/kotlin/lib/src/main/kotlin/models/IntegrationOut.kt b/kotlin/lib/src/main/kotlin/models/IntegrationOut.kt index 246b6ba71..1cf590c6d 100644 --- a/kotlin/lib/src/main/kotlin/models/IntegrationOut.kt +++ b/kotlin/lib/src/main/kotlin/models/IntegrationOut.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.Serializable @Serializable data class IntegrationOut( val createdAt: Instant, + val featureFlags: Set? = null, val id: String, val name: String, val updatedAt: Instant, diff --git a/kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt b/kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt index 3a782217a..0efe711cc 100644 --- a/kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt +++ b/kotlin/lib/src/main/kotlin/models/IntegrationUpdate.kt @@ -3,4 +3,4 @@ package com.svix.kotlin.models import kotlinx.serialization.Serializable -@Serializable data class IntegrationUpdate(val name: String) +@Serializable data class IntegrationUpdate(val featureFlags: Set? = null, val name: String) From ca963c42bc7bebb1a0d4b4256ace01277633184d Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Sun, 16 Feb 2025 14:01:41 -0500 Subject: [PATCH 55/56] kotlin: Add test for `"iterator":null` on `listResponseApplicationOut` --- .../lib/src/test/com/svix/kotlin/WiremockTests.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt index 127445734..9e098ae7e 100644 --- a/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt +++ b/kotlin/lib/src/test/com/svix/kotlin/WiremockTests.kt @@ -367,4 +367,17 @@ class WiremockTests { ), ) } + + @Test + fun listResponseOutCorrectlyDeserialized() { + val svx = testClient() + wireMockServer.stubFor( + WireMock.get(urlMatching("/api/v1/app")) + .willReturn( + WireMock.ok() + .withBody("""{"data":[],"iterator":null,"prevIterator":null,"done":true}""") + ) + ) + runBlocking { svx.application.list() } + } } From e44571a0cfbaf698e8bcea741f06690032700542 Mon Sep 17 00:00:00 2001 From: Mendy Man Date: Sun, 16 Feb 2025 14:03:41 -0500 Subject: [PATCH 56/56] kotlin: Correctly handel nullable types --- kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt | 2 +- kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt | 2 +- .../lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt | 2 +- .../src/main/kotlin/models/ListResponseEndpointMessageOut.kt | 2 +- kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt | 2 +- kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt | 2 +- kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt | 2 +- .../lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt | 2 +- .../src/main/kotlin/models/ListResponseMessageEndpointOut.kt | 2 +- kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt | 2 +- .../kotlin/models/ListResponseOperationalWebhookEndpointOut.kt | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt b/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt index 661de8189..81b64f842 100644 --- a/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt +++ b/kotlin/lib/src/main/kotlin/models/EnvironmentOut.kt @@ -9,7 +9,7 @@ import kotlinx.serialization.Serializable data class EnvironmentOut( val createdAt: Instant, val eventTypes: List, - @Serializable(with = StringAnyMapSerializer::class) val settings: Map, + @Serializable(with = StringAnyMapSerializer::class) val settings: Map? = null, val transformationTemplates: List, val version: Long? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt index 058aeff04..ce1bf7b36 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseApplicationOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseApplicationOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt index 33cafcc58..57aa7bbfd 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseBackgroundTaskOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseBackgroundTaskOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt index 3af6efab0..58c230cd7 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointMessageOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseEndpointMessageOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt index 5d36c2778..b28e38c44 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseEndpointOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseEndpointOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt index 416754c14..329708c16 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseEventTypeOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseEventTypeOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt index 6c544f58b..3aa5c95b6 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseIntegrationOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseIntegrationOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt index db7fe3b88..c5c2063fe 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseMessageAttemptOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseMessageAttemptOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt index 0e3123a98..aeb5c5872 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseMessageEndpointOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseMessageEndpointOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt index 6e4d1795d..68f9e9485 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseMessageOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseMessageOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, ) diff --git a/kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt b/kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt index a22ad5567..9d1c46991 100644 --- a/kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt +++ b/kotlin/lib/src/main/kotlin/models/ListResponseOperationalWebhookEndpointOut.kt @@ -7,6 +7,6 @@ import kotlinx.serialization.Serializable data class ListResponseOperationalWebhookEndpointOut( val data: List, val done: Boolean, - val iterator: String, + val iterator: String? = null, val prevIterator: String? = null, )