From db96ada4fa1c1762999580862bc8a75197ecb0e4 Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Fri, 19 Sep 2025 15:43:58 +0900 Subject: [PATCH 1/6] Port ApiResult type mapping --- gradle/libs.versions.toml | 2 + integrations/ktor/build.gradle.kts | 46 ++++++++++++++++ integrations/ktor/gradle.properties | 3 + .../ktor/ktorEitherNetExtensions.kt | 55 +++++++++++++++++++ settings.gradle.kts | 2 + 5 files changed, 108 insertions(+) create mode 100644 integrations/ktor/build.gradle.kts create mode 100644 integrations/ktor/gradle.properties create mode 100644 integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 30eaf80..1d9b450 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ jdk = "23" jvmTarget = "11" ksp = "2.2.20-2.0.3" ktfmt = "0.54" +ktor = "3.3.0" moshi = "1.15.1" okhttp = "5.1.0" retrofit = "2.9.0" @@ -29,6 +30,7 @@ junit = "junit:junit:4.13.2" kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } ktfmt = { module = "com.facebook:ktfmt", version.ref = "ktfmt" } +ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } moshi = { module = "com.squareup.moshi:moshi", version.ref = "moshi" } moshi-kotlin = { module = "com.squareup.moshi:moshi-kotlin", version.ref = "moshi" } okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } diff --git a/integrations/ktor/build.gradle.kts b/integrations/ktor/build.gradle.kts new file mode 100644 index 0000000..25578f9 --- /dev/null +++ b/integrations/ktor/build.gradle.kts @@ -0,0 +1,46 @@ +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl + +plugins { + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.dokka) + alias(libs.plugins.mavenPublish) +} + +kotlin { + // region KMP Targets + jvm() + iosX64() + iosArm64() + iosSimulatorArm64() + js(IR) { + outputModuleName.set(property("POM_ARTIFACT_ID").toString()) + browser() + } + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + outputModuleName.set(property("POM_ARTIFACT_ID").toString()) + browser() + } + // endregion + + applyDefaultHierarchyTemplate() + + + sourceSets { + commonMain { + dependencies { + api(project(":eithernet")) + api(libs.ktor.client) + implementation(libs.coroutines.core) + } + } + commonTest { + dependencies { + implementation(libs.coroutines.core) + implementation(libs.coroutines.test) + implementation(libs.kotlin.test) + } + } + } +} \ No newline at end of file diff --git a/integrations/ktor/gradle.properties b/integrations/ktor/gradle.properties new file mode 100644 index 0000000..eb15690 --- /dev/null +++ b/integrations/ktor/gradle.properties @@ -0,0 +1,3 @@ +POM_ARTIFACT_ID=eithernet-integration-ktor +POM_NAME=EitherNet Ktor Integration +POM_DESCRIPTION=Ktor integration for EitherNet ApiResult types \ No newline at end of file diff --git a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt new file mode 100644 index 0000000..40e7d5d --- /dev/null +++ b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt @@ -0,0 +1,55 @@ +// Copyright (C) 2025 Slack Technologies, LLC +// SPDX-License-Identifier: Apache-2.0 +package com.slack.eithernet.integration.ktor + +import com.slack.eithernet.ApiResult +import io.ktor.client.HttpClient +import io.ktor.client.call.body +import io.ktor.client.network.sockets.ConnectTimeoutException +import io.ktor.client.network.sockets.SocketTimeoutException +import io.ktor.client.plugins.ClientRequestException +import io.ktor.client.plugins.ServerResponseException +import io.ktor.client.statement.HttpResponse +import io.ktor.util.network.UnresolvedAddressException +import okio.IOException + +/** + * Converts an [HttpResponse] returned by [block] to an [ApiResult] with the response body as the + * success value. + */ +public suspend inline fun HttpClient.apiResultOf( + block: HttpClient.() -> HttpResponse +): ApiResult { + return try { + val response = block() + ApiResult.success(response.body()) + } catch (e: Exception) { + e.asKtorApiResult() + } +} + +@PublishedApi +internal fun Exception.asKtorApiResult(): ApiResult { + return when (this) { + is ClientRequestException -> { + // 4xx errors + ApiResult.httpFailure(response.status.value) + } + is ServerResponseException -> { + // 5xx errors + ApiResult.httpFailure(response.status.value) + } + is ConnectTimeoutException -> { + ApiResult.networkFailure(IOException("", cause = this)) + } + is SocketTimeoutException -> { + ApiResult.networkFailure(IOException("", cause = this)) + } + is UnresolvedAddressException -> { + ApiResult.networkFailure(IOException("", cause = this)) + } + else -> { + ApiResult.unknownFailure(this) + } + } +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 0c24344..aeb2850 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -32,3 +32,5 @@ include(":eithernet") include(":eithernet:test-fixtures") include(":integrations:retrofit") + +include(":integrations:ktor") From 858d942d506d93db9243b6b9c1924fb601f465f1 Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Fri, 19 Sep 2025 15:57:06 +0900 Subject: [PATCH 2/6] tests --- integrations/ktor/build.gradle.kts | 1 + .../ktor/ktorEitherNetExtensions.kt | 6 +- .../ktor/KtorEitherNetExtensionsTest.kt | 78 +++++++++++++ kotlin-js-store/package-lock.json | 110 +++++++++++++++++- kotlin-js-store/wasm/package-lock.json | 59 +++++++++- 5 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt diff --git a/integrations/ktor/build.gradle.kts b/integrations/ktor/build.gradle.kts index 25578f9..ac574b2 100644 --- a/integrations/ktor/build.gradle.kts +++ b/integrations/ktor/build.gradle.kts @@ -33,6 +33,7 @@ kotlin { api(project(":eithernet")) api(libs.ktor.client) implementation(libs.coroutines.core) + implementation(libs.okio) } } commonTest { diff --git a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt index 40e7d5d..d258610 100644 --- a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt +++ b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt @@ -40,13 +40,13 @@ internal fun Exception.asKtorApiResult(): ApiResult { ApiResult.httpFailure(response.status.value) } is ConnectTimeoutException -> { - ApiResult.networkFailure(IOException("", cause = this)) + ApiResult.networkFailure(IOException(message = "", cause = this)) } is SocketTimeoutException -> { - ApiResult.networkFailure(IOException("", cause = this)) + ApiResult.networkFailure(IOException(message = "", cause = this)) } is UnresolvedAddressException -> { - ApiResult.networkFailure(IOException("", cause = this)) + ApiResult.networkFailure(IOException(message = "", cause = this)) } else -> { ApiResult.unknownFailure(this) diff --git a/integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt b/integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt new file mode 100644 index 0000000..2406b34 --- /dev/null +++ b/integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt @@ -0,0 +1,78 @@ +// Copyright (C) 2025 Slack Technologies, LLC +// SPDX-License-Identifier: Apache-2.0 +package com.slack.eithernet.integration.ktor + +import com.slack.eithernet.ApiResult +import io.ktor.client.network.sockets.ConnectTimeoutException +import io.ktor.client.network.sockets.SocketTimeoutException +import io.ktor.util.network.UnresolvedAddressException +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertTrue +import okio.IOException + +class KtorEitherNetExtensionsTest { + + @Test + fun `asKtorApiResult converts ConnectTimeoutException to networkFailure`() { + val exception = ConnectTimeoutException("Connection timeout") + + val result: ApiResult = exception.asKtorApiResult() + + assertIs(result) + assertIs(result.error) + assertEquals(exception, result.error.cause) + } + + @Test + fun `asKtorApiResult converts SocketTimeoutException to networkFailure`() { + val exception = SocketTimeoutException("Socket timeout") + + val result: ApiResult = exception.asKtorApiResult() + + assertIs(result) + assertIs(result.error) + assertEquals(exception, result.error.cause) + } + + @Test + fun `asKtorApiResult converts UnresolvedAddressException to networkFailure`() { + val exception = UnresolvedAddressException() + + val result: ApiResult = exception.asKtorApiResult() + + assertIs(result) + assertIs(result.error) + assertEquals(exception, result.error.cause) + } + + @Test + fun `asKtorApiResult converts unknown exceptions to unknownFailure`() { + val exception = RuntimeException("Unknown error") + + val result: ApiResult = exception.asKtorApiResult() + + assertIs(result) + assertEquals(exception, result.error) + } + + @Test + fun `asKtorApiResult preserves exception types for network errors`() { + val connectTimeout = ConnectTimeoutException("Connect timeout") + val socketTimeout = SocketTimeoutException("Socket timeout") + val unresolvedAddress = UnresolvedAddressException() + + val connectResult: ApiResult = connectTimeout.asKtorApiResult() + val socketResult: ApiResult = socketTimeout.asKtorApiResult() + val addressResult: ApiResult = unresolvedAddress.asKtorApiResult() + + assertIs(connectResult) + assertIs(socketResult) + assertIs(addressResult) + + assertTrue(connectResult.error.cause is ConnectTimeoutException) + assertTrue(socketResult.error.cause is SocketTimeoutException) + assertTrue(addressResult.error.cause is UnresolvedAddressException) + } +} diff --git a/kotlin-js-store/package-lock.json b/kotlin-js-store/package-lock.json index 8b622e2..7abd51b 100644 --- a/kotlin-js-store/package-lock.json +++ b/kotlin-js-store/package-lock.json @@ -11,7 +11,10 @@ "packages/eithernet", "packages/eithernet-test", "packages/eithernet-test-fixtures", - "packages/eithernet-test-fixtures-test" + "packages/eithernet-test-fixtures-test", + "packages/eithernet-integration-ktor", + "packages/eithernet-integration-ktor-test", + "packages_imported/ktor-ktor-client-core/3.3.0" ], "devDependencies": {} }, @@ -1164,6 +1167,14 @@ "resolved": "packages/eithernet", "link": true }, + "node_modules/eithernet-integration-ktor": { + "resolved": "packages/eithernet-integration-ktor", + "link": true + }, + "node_modules/eithernet-integration-ktor-test": { + "resolved": "packages/eithernet-integration-ktor-test", + "link": true + }, "node_modules/eithernet-test": { "resolved": "packages/eithernet-test", "link": true @@ -2196,6 +2207,10 @@ "format-util": "^1.0.5" } }, + "node_modules/ktor-ktor-client-core": { + "resolved": "packages_imported/ktor-ktor-client-core/3.3.0", + "link": true + }, "node_modules/loader-runner": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", @@ -3900,10 +3915,103 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages_imported/ktor-ktor-client-core/3.3.0": { + "name": "ktor-ktor-client-core", + "version": "3.3.0", + "dependencies": { + "ws": "8.18.3" + }, + "devDependencies": {} + }, + "packages_imported/ktor-ktor-client-core/3.3.0/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "packages/eithernet": { "version": "2.1.0-SNAPSHOT", "devDependencies": {} }, + "packages/eithernet-integration-ktor": { + "version": "2.1.0-SNAPSHOT", + "dependencies": { + "ws": "8.18.3" + }, + "devDependencies": {} + }, + "packages/eithernet-integration-ktor-test": { + "version": "2.1.0-SNAPSHOT", + "dependencies": { + "ws": "8.18.3" + }, + "devDependencies": { + "karma": "6.4.4", + "karma-chrome-launcher": "3.2.0", + "karma-mocha": "2.0.1", + "karma-sourcemap-loader": "0.4.0", + "karma-webpack": "5.0.1", + "kotlin-web-helpers": "2.1.0", + "mocha": "11.7.1", + "source-map-loader": "5.0.0", + "webpack": "5.100.2", + "webpack-cli": "6.0.1" + } + }, + "packages/eithernet-integration-ktor-test/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "packages/eithernet-integration-ktor/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "packages/eithernet-test": { "version": "2.1.0-SNAPSHOT", "devDependencies": { diff --git a/kotlin-js-store/wasm/package-lock.json b/kotlin-js-store/wasm/package-lock.json index ed6962d..64cee4b 100644 --- a/kotlin-js-store/wasm/package-lock.json +++ b/kotlin-js-store/wasm/package-lock.json @@ -11,7 +11,10 @@ "packages/eithernet", "packages/eithernet-test", "packages/eithernet-test-fixtures", - "packages/eithernet-test-fixtures-test" + "packages/eithernet-test-fixtures-test", + "packages/eithernet-integration-ktor", + "packages/eithernet-integration-ktor-test", + "packages_imported/ktor-ktor-client-core/3.3.0" ], "devDependencies": {} }, @@ -19,6 +22,14 @@ "resolved": "packages/eithernet", "link": true }, + "node_modules/eithernet-integration-ktor": { + "resolved": "packages/eithernet-integration-ktor", + "link": true + }, + "node_modules/eithernet-integration-ktor-test": { + "resolved": "packages/eithernet-integration-ktor-test", + "link": true + }, "node_modules/eithernet-test": { "resolved": "packages/eithernet-test", "link": true @@ -31,10 +42,56 @@ "resolved": "packages/eithernet-test-fixtures-test", "link": true }, + "node_modules/ktor-ktor-client-core": { + "resolved": "packages_imported/ktor-ktor-client-core/3.3.0", + "link": true + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "packages_imported/ktor-ktor-client-core/3.3.0": { + "name": "ktor-ktor-client-core", + "version": "3.3.0", + "dependencies": { + "ws": "8.18.3" + }, + "devDependencies": {} + }, "packages/eithernet": { "version": "2.1.0-SNAPSHOT", "devDependencies": {} }, + "packages/eithernet-integration-ktor": { + "version": "2.1.0-SNAPSHOT", + "dependencies": { + "ws": "8.18.3" + }, + "devDependencies": {} + }, + "packages/eithernet-integration-ktor-test": { + "version": "2.1.0-SNAPSHOT", + "dependencies": { + "ws": "8.18.3" + }, + "devDependencies": {} + }, "packages/eithernet-test": { "version": "2.1.0-SNAPSHOT", "devDependencies": {} From aba8fe9d855b9fe5019692f25e60426195801fb6 Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Fri, 19 Sep 2025 16:04:49 +0900 Subject: [PATCH 3/6] Spotless --- integrations/ktor/build.gradle.kts | 19 ++++++++++++++++--- .../ktor/ktorEitherNetExtensions.kt | 19 ++++++++++++++++--- .../ktor/KtorEitherNetExtensionsTest.kt | 17 +++++++++++++++-- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/integrations/ktor/build.gradle.kts b/integrations/ktor/build.gradle.kts index ac574b2..d01dfbc 100644 --- a/integrations/ktor/build.gradle.kts +++ b/integrations/ktor/build.gradle.kts @@ -1,4 +1,18 @@ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi +/* + * Copyright (C) 2025 Slack Technologies, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl plugins { @@ -26,7 +40,6 @@ kotlin { applyDefaultHierarchyTemplate() - sourceSets { commonMain { dependencies { @@ -44,4 +57,4 @@ kotlin { } } } -} \ No newline at end of file +} diff --git a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt index d258610..5f6d56e 100644 --- a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt +++ b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt @@ -1,5 +1,18 @@ -// Copyright (C) 2025 Slack Technologies, LLC -// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2025 Slack Technologies, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.slack.eithernet.integration.ktor import com.slack.eithernet.ApiResult @@ -52,4 +65,4 @@ internal fun Exception.asKtorApiResult(): ApiResult { ApiResult.unknownFailure(this) } } -} \ No newline at end of file +} diff --git a/integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt b/integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt index 2406b34..0f09482 100644 --- a/integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt +++ b/integrations/ktor/src/commonTest/kotlin/com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsTest.kt @@ -1,5 +1,18 @@ -// Copyright (C) 2025 Slack Technologies, LLC -// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright (C) 2025 Slack Technologies, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.slack.eithernet.integration.ktor import com.slack.eithernet.ApiResult From 4cc44089df5da2c0824e65f3599a62a1dba5dde3 Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Fri, 19 Sep 2025 16:08:17 +0900 Subject: [PATCH 4/6] Is it the names? --- .../eithernet/integration/ktor/ktorEitherNetExtensions.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt index 5f6d56e..20f6808 100644 --- a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt +++ b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt @@ -53,13 +53,13 @@ internal fun Exception.asKtorApiResult(): ApiResult { ApiResult.httpFailure(response.status.value) } is ConnectTimeoutException -> { - ApiResult.networkFailure(IOException(message = "", cause = this)) + ApiResult.networkFailure(IOException(this)) } is SocketTimeoutException -> { - ApiResult.networkFailure(IOException(message = "", cause = this)) + ApiResult.networkFailure(IOException(this)) } is UnresolvedAddressException -> { - ApiResult.networkFailure(IOException(message = "", cause = this)) + ApiResult.networkFailure(IOException(this)) } else -> { ApiResult.unknownFailure(this) From eea80b9183351143bab1195d7d59e9d66f95bdbb Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Fri, 19 Sep 2025 16:11:06 +0900 Subject: [PATCH 5/6] Is it the names? --- .../eithernet/integration/ktor/ktorEitherNetExtensions.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt index 20f6808..4d6fea6 100644 --- a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt +++ b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt @@ -53,13 +53,13 @@ internal fun Exception.asKtorApiResult(): ApiResult { ApiResult.httpFailure(response.status.value) } is ConnectTimeoutException -> { - ApiResult.networkFailure(IOException(this)) + ApiResult.networkFailure(IOException("", this)) } is SocketTimeoutException -> { - ApiResult.networkFailure(IOException(this)) + ApiResult.networkFailure(IOException("", this)) } is UnresolvedAddressException -> { - ApiResult.networkFailure(IOException(this)) + ApiResult.networkFailure(IOException("", this)) } else -> { ApiResult.unknownFailure(this) From d605beeb6bc3c0e71f22b801850fd6b8f86ccb85 Mon Sep 17 00:00:00 2001 From: Zac Sweers Date: Mon, 22 Sep 2025 14:42:15 +0900 Subject: [PATCH 6/6] Now it works? --- integrations/ktor/api/ktor.api | 4 ++++ integrations/ktor/api/ktor.klib.api | 10 ++++++++++ .../integration/ktor/ktorEitherNetExtensions.kt | 7 ++++--- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 integrations/ktor/api/ktor.api create mode 100644 integrations/ktor/api/ktor.klib.api diff --git a/integrations/ktor/api/ktor.api b/integrations/ktor/api/ktor.api new file mode 100644 index 0000000..70b394b --- /dev/null +++ b/integrations/ktor/api/ktor.api @@ -0,0 +1,4 @@ +public final class com/slack/eithernet/integration/ktor/KtorEitherNetExtensionsKt { + public static final fun asKtorApiResult (Ljava/lang/Exception;)Lcom/slack/eithernet/ApiResult; +} + diff --git a/integrations/ktor/api/ktor.klib.api b/integrations/ktor/api/ktor.klib.api new file mode 100644 index 0000000..cf7584d --- /dev/null +++ b/integrations/ktor/api/ktor.klib.api @@ -0,0 +1,10 @@ +// Klib ABI Dump +// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, wasmJs] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: +final fun <#A: kotlin/Any> (kotlin/Exception).com.slack.eithernet.integration.ktor/asKtorApiResult(): com.slack.eithernet/ApiResult // com.slack.eithernet.integration.ktor/asKtorApiResult|asKtorApiResult@kotlin.Exception(){0§}[0] +final suspend inline fun <#A: reified kotlin/Any, #B: kotlin/Any> (io.ktor.client/HttpClient).com.slack.eithernet.integration.ktor/apiResultOf(kotlin/Function1): com.slack.eithernet/ApiResult<#A, #B> // com.slack.eithernet.integration.ktor/apiResultOf|apiResultOf@io.ktor.client.HttpClient(kotlin.Function1){0§;1§}[0] diff --git a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt index 4d6fea6..8a7dba9 100644 --- a/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt +++ b/integrations/ktor/src/commonMain/kotlin/com/slack/eithernet/integration/ktor/ktorEitherNetExtensions.kt @@ -43,6 +43,7 @@ public suspend inline fun HttpClient.apiResultOf( @PublishedApi internal fun Exception.asKtorApiResult(): ApiResult { + // For some reason the smart cast here fails return when (this) { is ClientRequestException -> { // 4xx errors @@ -53,13 +54,13 @@ internal fun Exception.asKtorApiResult(): ApiResult { ApiResult.httpFailure(response.status.value) } is ConnectTimeoutException -> { - ApiResult.networkFailure(IOException("", this)) + ApiResult.networkFailure(IOException("", this as Throwable)) } is SocketTimeoutException -> { - ApiResult.networkFailure(IOException("", this)) + ApiResult.networkFailure(IOException("", this as Throwable)) } is UnresolvedAddressException -> { - ApiResult.networkFailure(IOException("", this)) + ApiResult.networkFailure(IOException("", this as Throwable)) } else -> { ApiResult.unknownFailure(this)