{"id":16213654,"url":"https://github.com/rickclephas/nserrorkt","last_synced_at":"2025-03-19T09:31:04.686Z","repository":{"id":65507899,"uuid":"456219938","full_name":"rickclephas/NSErrorKt","owner":"rickclephas","description":"A Kotlin Multiplatform Library to improve NSError interop","archived":false,"fork":false,"pushed_at":"2024-01-05T12:51:36.000Z","size":179,"stargazers_count":55,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-17T05:44:45.148Z","etag":null,"topics":["kmm","kmp","kotlin","kotlin-multiplatform","kotlin-multiplatform-mobile","kotlin-native"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rickclephas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-06T17:24:20.000Z","updated_at":"2025-02-08T16:50:58.000Z","dependencies_parsed_at":"2024-10-27T20:29:34.833Z","dependency_job_id":"8816f845-d157-45d4-bd6d-14080097d533","html_url":"https://github.com/rickclephas/NSErrorKt","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rickclephas%2FNSErrorKt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rickclephas%2FNSErrorKt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rickclephas%2FNSErrorKt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rickclephas%2FNSErrorKt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rickclephas","download_url":"https://codeload.github.com/rickclephas/NSErrorKt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244398604,"owners_count":20446438,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kmm","kmp","kotlin","kotlin-multiplatform","kotlin-multiplatform-mobile","kotlin-native"],"created_at":"2024-10-10T11:07:22.006Z","updated_at":"2025-03-19T09:31:03.932Z","avatar_url":"https://github.com/rickclephas.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NSErrorKt\n\nA Kotlin Multiplatform Library to improve `NSError` interop.\n\n## Why do we need this?\n\nKotlin already has `Throwable` to `NSError` interop for straightforward cases as described in \n[the docs](https://kotlinlang.org/docs/native-objc-interop.html#errors-and-exceptions).  \nThough currently there is [no way][KT-50539] for application or library code to use this interop directly,\nmeaning applications and libraries need to create their own instead.\n\n[KT-50539]: https://youtrack.jetbrains.com/issue/KT-50539\n\n### Ktor\n\nThe [Ktor](https://ktor.io/) Darwin client does this by [wrapping][ktor-wrapping] a `NSError` in a custom `Exception`:\n```kotlin\n@OptIn(UnsafeNumber::class)\ninternal fun handleNSError(requestData: HttpRequestData, error: NSError): Throwable = when (error.code) {\n    NSURLErrorTimedOut -\u003e SocketTimeoutException(requestData)\n    else -\u003e DarwinHttpRequestException(error)\n}\n```\n\n[ktor-wrapping]: https://github.com/ktorio/ktor/blob/0877d6a91f3879b91853d412abd167054dccb333/ktor-client/ktor-client-darwin/darwin/src/io/ktor/client/engine/darwin/TimeoutUtils.kt#L27-L31\n\nWhich is a great solution for your Kotlin code as it allows you to access the wrapped `NSError`.  \nHowever once these `Exception`s reach Swift/ObjC, Kotlin will convert them to a `NSError`.  \nSince Kotlin doesn't know this `Exception` is a wrapped `NSError` it will wrap the `Exception` in a `NSError` again.\n\nThis results in hard to log errors like this [one](https://kotlinlang.slack.com/archives/C3PQML5NU/p1640081553385000).\n\n### KMP-NativeCoroutines\n\n[KMP-NativeCoroutines](https://github.com/rickclephas/KMP-NativeCoroutines) has a similar problem \nwhere it needs to [convert][kmp-nc-convert] `Exception`s to `NSError`s:\n```kotlin\n@OptIn(UnsafeNumber::class)\ninternal fun Throwable.asNSError(): NSError {\n    val userInfo = mutableMapOf\u003cAny?, Any\u003e()\n    userInfo[\"KotlinException\"] = this.freeze()\n    val message = message\n    if (message != null) {\n        userInfo[NSLocalizedDescriptionKey] = message\n    }\n    return NSError.errorWithDomain(\"KotlinException\", 0.convert(), userInfo)\n}\n```\n\n[kmp-nc-convert]: https://github.com/rickclephas/KMP-NativeCoroutines/blob/c1b7821bfb822cdc458d5fae1a1939abb3e7b1e0/kmp-nativecoroutines-core/src/appleMain/kotlin/com/rickclephas/kmp/nativecoroutines/NSError.kt#L17-L26\n\nIt produces similar `NSError`s to the once Kotlin creates, but it doesn't unwrap an already wrapped `NSError`.  \nAnd in case such an `NSError` reaches Kotlin again it will be wrapped in an `Exception` instead of being unwrapped.\n\nSo depending on your code this might result in hard to log errors as well.\n\n## Compatibility\n\nThe latest version of the library uses Kotlin version `1.9.22`.\n\n\u003e [!WARNING]\n\u003e This library exposes the Kotlin `NSError` interop logic provided by the Kotlin Native runtime.  \n\u003e These internals aren't part of any public API and are considered to be an implementation detail!  \n\u003e Use at your own risk and beware that using the library with other Kotlin versions might not work as expected.\n\n## Installation\n\nSimply add the dependency to the `appleMain` source-set of your Kotlin module: \n\n```kotlin\nkotlin {\n    sourceSets {\n        appleMain {\n            dependencies {\n                api(\"com.rickclephas.kmp:nserror-kt:0.2.0\")\n            }\n        }\n    }\n}\n```\n\nIf you want to use the library in your Swift code, make sure to export it from your shared Kotlin module:\n```kotlin\nkotlin {\n    targets.withType(KotlinNativeTarget::class) {\n        if (!konanTarget.family.isAppleFamily) return@withType\n        binaries.framework {\n            export(\"com.rickclephas.kmp:nserror-kt:0.2.0\")\n        }\n    }\n}\n```\n\n## Usage\n\nTo solve the interop issues this library exposes the Kotlin `NSError` interop logic to your application and library code.\n\nConsisting of 3 extension functions:\n- [`Throwable.asNSError`](#asnserror)\n- [`Throwable.throwAsNSError`](#throwasnserror)\n- [`NSError.asThrowable`](#asthrowable)\n\nand 2 extension properties:\n- [`Throwable.isNSError`](#isnserror)\n- [`NSError.isThrowable`](#isthrowable)\n\n### asNSError\n\n``````kotlin\n/**\n * Converts `this` [Throwable] to a [NSError].\n *\n * If `this` [Throwable] represents a [NSError], the original [NSError] is returned.\n * For other [Throwable]s a `KotlinException` [NSError] is returned:\n * ```\n * NSError.errorWithDomain(\"KotlinException\", 0, mapOf(\n *     \"KotlinException\" to this,\n *     NSLocalizedDescriptionKey to this.message\n * ))\n * ```\n *\n * @see throwAsNSError\n * @see asThrowable\n */\nfun Throwable.asNSError(): NSError\n``````\n\n### throwAsNSError\n\n``````kotlin\n/**\n * Tries to convert `this` [Throwable] to a [NSError].\n *\n * If `this` [Throwable] is an instance of one of the [exceptionClasses] or their subclasses,\n * it is converted to a [NSError] in the same way [asNSError] would.\n *\n * Other [Throwable]s are considered unhandled and will cause program termination\n * in the same way a [Throws] annotated function would.\n *\n * @see asNSError\n * @see asThrowable\n * @see Throws\n */\nfun Throwable.throwAsNSError(vararg exceptionClasses: KClass\u003cout Throwable\u003e): NSError\n``````\n\n### asThrowable\n\n``````kotlin\n/**\n * Converts `this` [NSError] to a [Throwable].\n *\n * If `this` [NSError] represents a [Throwable], the original [Throwable] is returned.\n * For other [NSError]s an [ObjCErrorException] will be returned.\n *\n * @see asNSError\n */\nfun NSError.asThrowable(): Throwable\n``````\n\n### isNSError\n\n``````kotlin\n/**\n * Indicates if `this` [Throwable] represents a [NSError].\n */\nval Throwable.isNSError: Boolean\n``````\n\n### isThrowable\n\n``````kotlin\n/**\n * Indicates if `this` [NSError] represents a [Throwable].\n */\nval NSError.isThrowable: Boolean\n``````\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frickclephas%2Fnserrorkt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frickclephas%2Fnserrorkt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frickclephas%2Fnserrorkt/lists"}