diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000..4da3fd5 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,17 @@ +name: kuri CodeQL config + +# SAST-first. security-and-quality is a superset of security-extended, so this runs CodeQL's full +# security query set (injection / SSRF / path-traversal / unsafe-parsing / crypto / etc. — the ones +# that matter for a URL/URI library that turns untrusted text into hosts, paths and queries) plus +# its reliability and maintainability queries. Security is the goal; the quality queries are the +# "whatever else it provides". +queries: + - uses: security-and-quality + +# The IDNA/UTS-46 mapping + validity tables and the NFC table are machine-generated from the Unicode +# UCD (thousands of entries, regenerated by the codegen tasks, never hand-edited). Findings in them +# are noise, not defects, so keep them out of the alert list and focus scanning on hand-written code. +paths-ignore: + - '**/idna/IdnaMappingTableData.kt' + - '**/idna/IdnaValidityData.kt' + - '**/idna/NfcData.kt' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31eff44..a09a1bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,9 +52,32 @@ jobs: distribution: corretto java-version: '21' - uses: gradle/actions/setup-gradle@v4 + # Restore the Kotlin/Native toolchain (~1 GB: compiler bundle + LLVM/sysroot/gcc deps under + # ~/.konan). setup-gradle caches ~/.gradle but not ~/.konan, and apiCheck's KLIB ABI validation + # compiles every native klib here, so without this the whole bundle re-downloads each run. + # The key is scoped `-gate-` (the native job below uses `-native-`) so the two Linux jobs each + # cache the toolchain subset they actually pull and never race to write one shared key on main. + # Restore runs on every branch (PRs reuse main's cache); only main writes it (see the save step + # below). The key tracks the version catalog; restore-keys give a partial hit when it changes. + - name: Restore Kotlin/Native toolchain + id: konan-cache + uses: actions/cache/restore@v4 + with: + path: ~/.konan + key: ${{ runner.os }}-konan-gate-${{ hashFiles('gradle/libs.versions.toml') }} + restore-keys: ${{ runner.os }}-konan-gate- - name: ktlint, detekt, binary-compatibility and JVM coverage floor # koverVerify pulls in jvmTest and enforces the 80% line-coverage rule. run: ./gradlew ktlintCheck detekt apiCheck jvmTest koverVerify --stacktrace + # Write the toolchain cache only from main, and only when the restore was not an exact hit + # (GitHub caches are write-once per key). PRs never write, so parallel branches can't evict + # main's warm cache. + - name: Save Kotlin/Native toolchain + if: github.ref == 'refs/heads/main' && steps.konan-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ~/.konan + key: ${{ runner.os }}-konan-gate-${{ hashFiles('gradle/libs.versions.toml') }} web: name: JS · Wasm tests (Linux x64) @@ -117,8 +140,27 @@ jobs: distribution: corretto java-version: '21' - uses: gradle/actions/setup-gradle@v4 + # Restore the Kotlin/Native toolchain (~1 GB under ~/.konan) that this native job compiles and + # links against; setup-gradle caches ~/.gradle but not ~/.konan. runner.os in the key keeps the + # Linux/Windows/macOS legs separate, and the `-native-` scope keeps the Linux leg from colliding + # with the quality-gate job's `-gate-` cache. Restore runs on every branch; only main writes it. + - name: Restore Kotlin/Native toolchain + id: konan-cache + uses: actions/cache/restore@v4 + with: + path: ~/.konan + key: ${{ runner.os }}-konan-native-${{ hashFiles('gradle/libs.versions.toml') }} + restore-keys: ${{ runner.os }}-konan-native- - name: ${{ matrix.name }} run: ./gradlew ${{ matrix.tasks }} --stacktrace + # Write the toolchain cache only from main, and only on a non-exact restore (caches are + # write-once per key), so PR legs never evict main's warm per-OS cache. + - name: Save Kotlin/Native toolchain + if: github.ref == 'refs/heads/main' && steps.konan-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ~/.konan + key: ${{ runner.os }}-konan-native-${{ hashFiles('gradle/libs.versions.toml') }} android-unit: name: Android unit tests (Linux x64) @@ -131,8 +173,6 @@ jobs: with: distribution: corretto java-version: '21' - # AGP needs an Android SDK at configuration time; this installs it and accepts licenses. - - uses: android-actions/setup-android@v3 - uses: gradle/actions/setup-gradle@v4 - name: Android host (JVM) unit tests # Runs commonTest compiled for the Android target on the JVM — no emulator. @@ -157,6 +197,35 @@ jobs: echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules sudo udevadm trigger --name-match=kvm + # Restore the cached AVD (system image, created device, boot snapshot) under ~/.android so a run + # can skip the image download, AVD creation and cold boot and load a warm snapshot instead. + # Restore runs on every branch (PRs reuse main's snapshot); only main writes it (see save below). + # The key pins every coordinate that affects the snapshot; bump the -v suffix if the emulator + # options change, since GitHub caches are write-once per key. + - name: Restore AVD snapshot + id: avd-cache + uses: actions/cache/restore@v4 + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-30-aosp_atd-x86_64-pixel6-v1 + # On main with no cached snapshot, boot once to create the AVD and write a clean boot snapshot + # for the cache. Emulator options match the test run so the snapshot stays valid. Gated to main + # because only main persists it — PRs skip this create-and-snapshot step and run the test step + # below once, warm-booting from main's cached snapshot when present (a single boot, not two). + - name: Create AVD and generate snapshot for caching + if: github.ref == 'refs/heads/main' && steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 30 + target: aosp_atd + arch: x86_64 + profile: pixel_6 + force-avd-creation: false + disable-animations: false + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + script: echo "Generated AVD snapshot for caching." - name: Android instrumented tests on an emulator uses: reactivecircus/android-emulator-runner@v2 with: @@ -164,10 +233,21 @@ jobs: target: aosp_atd arch: x86_64 profile: pixel_6 + force-avd-creation: false disable-animations: true - emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + # -no-snapshot-save: boot from the cached snapshot but don't rewrite it on exit. + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -no-snapshot-save -camera-back none # Installs and runs the androidDeviceTest instrumentation (an ART smoke test) on the emulator. script: ./gradlew :kuri:connectedAndroidDeviceTest --stacktrace + # Persist the AVD snapshot for later runs — only from main, and only on a non-exact restore. + - name: Save AVD snapshot + if: github.ref == 'refs/heads/main' && steps.avd-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-30-aosp_atd-x86_64-pixel6-v1 # Aggregate gate: a single check to require in branch protection. Green only when every # job above succeeded; fails if any was skipped, cancelled or failed. diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..ad8baf2 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,83 @@ +name: CodeQL + +# CodeQL SAST (static application security testing) for the JVM (Java + Kotlin) surface of kuri, +# plus CodeQL's reliability/maintainability queries — the query suite is set to security-and-quality +# in .github/codeql/codeql-config.yml. CodeQL only extracts JVM-bytecode-producing compilation; in +# this KMP project all production code is common + jvm Kotlin (the whole parsing engine lives in +# commonMain, and the reflective binder in kuri-bind's jvmMain), which the JVM target compiles, so a +# single traced JVM build covers commonMain + jvmMain — the entire security-relevant surface. Only +# platform-specific `actual` bodies (in jsMain/nativeMain/wasmJsMain, if any) fall outside this JVM +# extraction; CodeQL can't extract those targets, and they are covered by the CI test matrix instead. + +on: + push: + branches: [ main ] + pull_request: + schedule: + # Weekly re-scan (Mondays 03:19 UTC) so newly published CodeQL queries flag issues even on a + # week with no code change. Off-the-hour to avoid the top-of-hour scheduling congestion. + - cron: '19 3 * * 1' + +# A newer push to the same PR ref cancels an in-flight scan instead of stacking concurrent analyses; +# main runs are never cancelled, so every default-branch commit keeps its own recorded CodeQL result. +concurrency: + group: codeql-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +# Least privilege by default; the analyze job widens to what code-scanning upload needs. +permissions: + contents: read + +jobs: + analyze: + name: Analyze (Java/Kotlin) + runs-on: ubuntu-latest + # A wedged extractor or build should fail fast rather than burn the 6-hour default. + timeout-minutes: 30 + permissions: + # Upload the SARIF results to the repository's code-scanning alerts. + security-events: write + # Read workflow run metadata (required by CodeQL on private repos; harmless here). + actions: read + contents: read + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + # Match the CI jobs: Gradle runs on Corretto 21 (the module's jvmToolchain(21)). + distribution: corretto + java-version: '21' + - uses: gradle/actions/setup-gradle@v4 + + # Initialise the CodeQL tracer BEFORE the build so the Kotlin/Java compilation is extracted. + # 'java' is CodeQL's identifier for the Java/Kotlin extractor (it analyses Kotlin too). + # Pinned to the codeql-action's current major (@v4 → latest 4.x), matching how every other + # action here is pinned by major tag. The action version and the CodeQL CLI *bundle* version are + # separate schemes: @v4 selects the action, which ships a recent CLI bundle (2.26.x) on its own. + # (The previous @v2.26.0 pinned the long-deprecated v2 *action* — not the 2.26.0 CLI bundle it + # was mistaken for.) + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: java + # v4's explicit mode for a compiled language whose database is built by manual commands + # between init and analyze (the `compileKotlinJvm` step below), never by autobuild — which + # would build the whole KMP project. Omitting it works too (the tracer path is identical for + # Java), but declaring it self-documents that autobuild is deliberately avoided. + build-mode: manual + # security-and-quality query suite + generated-code exclusions. + config-file: ./.github/codeql/codeql-config.yml + + # Manual traced build instead of autobuild: compile only the JVM target of every module + # (compileKotlinJvm runs in :kuri and :kuri-bind). Autobuild would run the whole KMP build, + # including the native/JS/Wasm targets CodeQL can't extract. --no-build-cache forces a real + # compile (the project has the Gradle build cache on, which would otherwise serve cached + # classes and leave the tracer nothing to see); --no-daemon keeps compilation in the traced + # build process rather than a pre-existing untraced daemon. + - name: Compile JVM sources for CodeQL + run: ./gradlew compileKotlinJvm --no-daemon --no-build-cache --stacktrace + + - name: Perform CodeQL analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:java" diff --git a/gradle.properties b/gradle.properties index ae8b356..559e99d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,6 +3,10 @@ org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8 org.gradle.caching=true org.gradle.configuration-cache=true kotlin.mpp.stability.nowarn=true +# Native tasks for targets that can't run on the current CI host (e.g. iosSimulator on Linux) are +# disabled by Kotlin and emit a warning each; this silences that wall of warnings without changing +# what builds. Cross-compiled klib/*TestBinaries build breaks are still caught by the native jobs. +kotlin.native.ignoreDisabledTargets=true android.useAndroidX=true # Dokka 2.x runs in V1 (deprecated) mode unless the V2 plugin is opted into; V2 provides the diff --git a/kuri/api/kuri.klib.api b/kuri/api/kuri.klib.api new file mode 100644 index 0000000..792d805 --- /dev/null +++ b/kuri/api/kuri.klib.api @@ -0,0 +1,555 @@ +// Klib ABI Dump +// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, linuxArm64, linuxX64, macosArm64, mingwX64, tvosArm64, tvosSimulatorArm64, wasmJs, watchosArm64, watchosSimulatorArm64] +// Rendering settings: +// - Signature version: 2 +// - Show manifest properties: true +// - Show declarations: true + +// Library unique name: +final enum class org.dexpace.kuri.error/HostError : kotlin/Enum { // org.dexpace.kuri.error/HostError|null[0] + enum entry EmptyLabel // org.dexpace.kuri.error/HostError.EmptyLabel|null[0] + enum entry HostTooLong // org.dexpace.kuri.error/HostError.HostTooLong|null[0] + enum entry IdnaFailed // org.dexpace.kuri.error/HostError.IdnaFailed|null[0] + enum entry Ipv4NonNumeric // org.dexpace.kuri.error/HostError.Ipv4NonNumeric|null[0] + enum entry Ipv4Overflow // org.dexpace.kuri.error/HostError.Ipv4Overflow|null[0] + enum entry Ipv6Malformed // org.dexpace.kuri.error/HostError.Ipv6Malformed|null[0] + enum entry LabelTooLong // org.dexpace.kuri.error/HostError.LabelTooLong|null[0] + enum entry ZoneIdRejected // org.dexpace.kuri.error/HostError.ZoneIdRejected|null[0] + + final val entries // org.dexpace.kuri.error/HostError.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // org.dexpace.kuri.error/HostError.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): org.dexpace.kuri.error/HostError // org.dexpace.kuri.error/HostError.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // org.dexpace.kuri.error/HostError.values|values#static(){}[0] +} + +final enum class org.dexpace.kuri.error/ValidationError : kotlin/Enum { // org.dexpace.kuri.error/ValidationError|null[0] + enum entry BACKSLASH_AS_SOLIDUS // org.dexpace.kuri.error/ValidationError.BACKSLASH_AS_SOLIDUS|null[0] + enum entry INVALID_URL_UNIT // org.dexpace.kuri.error/ValidationError.INVALID_URL_UNIT|null[0] + enum entry LEADING_OR_TRAILING_C0_CONTROL_OR_SPACE // org.dexpace.kuri.error/ValidationError.LEADING_OR_TRAILING_C0_CONTROL_OR_SPACE|null[0] + enum entry MISSING_AUTHORITY_SLASHES // org.dexpace.kuri.error/ValidationError.MISSING_AUTHORITY_SLASHES|null[0] + enum entry TAB_OR_NEWLINE_REMOVED // org.dexpace.kuri.error/ValidationError.TAB_OR_NEWLINE_REMOVED|null[0] + + final val entries // org.dexpace.kuri.error/ValidationError.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // org.dexpace.kuri.error/ValidationError.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): org.dexpace.kuri.error/ValidationError // org.dexpace.kuri.error/ValidationError.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // org.dexpace.kuri.error/ValidationError.values|values#static(){}[0] +} + +sealed interface <#A: out kotlin/Any?> org.dexpace.kuri.error/ParseResult { // org.dexpace.kuri.error/ParseResult|null[0] + open fun getOrNull(): #A? // org.dexpace.kuri.error/ParseResult.getOrNull|getOrNull(){}[0] + open fun getOrThrow(): #A // org.dexpace.kuri.error/ParseResult.getOrThrow|getOrThrow(){}[0] + open fun isOk(): kotlin/Boolean // org.dexpace.kuri.error/ParseResult.isOk|isOk(){}[0] + + final class <#A1: out kotlin/Any?> Ok : org.dexpace.kuri.error/ParseResult<#A1> { // org.dexpace.kuri.error/ParseResult.Ok|null[0] + constructor (#A1) // org.dexpace.kuri.error/ParseResult.Ok.|(1:0){}[0] + + final val value // org.dexpace.kuri.error/ParseResult.Ok.value|{}value[0] + final fun (): #A1 // org.dexpace.kuri.error/ParseResult.Ok.value.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/ParseResult.Ok.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/ParseResult.Ok.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/ParseResult.Ok.toString|toString(){}[0] + } + + final class Err : org.dexpace.kuri.error/ParseResult { // org.dexpace.kuri.error/ParseResult.Err|null[0] + constructor (org.dexpace.kuri.error/UriParseError) // org.dexpace.kuri.error/ParseResult.Err.|(org.dexpace.kuri.error.UriParseError){}[0] + + final val error // org.dexpace.kuri.error/ParseResult.Err.error|{}error[0] + final fun (): org.dexpace.kuri.error/UriParseError // org.dexpace.kuri.error/ParseResult.Err.error.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/ParseResult.Err.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/ParseResult.Err.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/ParseResult.Err.toString|toString(){}[0] + } +} + +sealed interface org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError|null[0] + open val message // org.dexpace.kuri.error/UriParseError.message|{}message[0] + open fun (): kotlin/String // org.dexpace.kuri.error/UriParseError.message.|(){}[0] + + final class ForbiddenHostCodePoint : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint|null[0] + constructor (kotlin/Int, kotlin/Int) // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.|(kotlin.Int;kotlin.Int){}[0] + + final val at // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.at|{}at[0] + final fun (): kotlin/Int // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.at.|(){}[0] + final val codePoint // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.codePoint|{}codePoint[0] + final fun (): kotlin/Int // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.codePoint.|(){}[0] + + final fun component1(): kotlin/Int // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.component1|component1(){}[0] + final fun component2(): kotlin/Int // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.component2|component2(){}[0] + final fun copy(kotlin/Int = ..., kotlin/Int = ...): org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.copy|copy(kotlin.Int;kotlin.Int){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.ForbiddenHostCodePoint.toString|toString(){}[0] + } + + final class InputTooLong : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.InputTooLong|null[0] + constructor (kotlin/Int, kotlin/Int) // org.dexpace.kuri.error/UriParseError.InputTooLong.|(kotlin.Int;kotlin.Int){}[0] + + final val length // org.dexpace.kuri.error/UriParseError.InputTooLong.length|{}length[0] + final fun (): kotlin/Int // org.dexpace.kuri.error/UriParseError.InputTooLong.length.|(){}[0] + final val max // org.dexpace.kuri.error/UriParseError.InputTooLong.max|{}max[0] + final fun (): kotlin/Int // org.dexpace.kuri.error/UriParseError.InputTooLong.max.|(){}[0] + + final fun component1(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InputTooLong.component1|component1(){}[0] + final fun component2(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InputTooLong.component2|component2(){}[0] + final fun copy(kotlin/Int = ..., kotlin/Int = ...): org.dexpace.kuri.error/UriParseError.InputTooLong // org.dexpace.kuri.error/UriParseError.InputTooLong.copy|copy(kotlin.Int;kotlin.Int){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.InputTooLong.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InputTooLong.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.InputTooLong.toString|toString(){}[0] + } + + final class InvalidHost : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.InvalidHost|null[0] + constructor (kotlin/String, org.dexpace.kuri.error/HostError) // org.dexpace.kuri.error/UriParseError.InvalidHost.|(kotlin.String;org.dexpace.kuri.error.HostError){}[0] + + final val host // org.dexpace.kuri.error/UriParseError.InvalidHost.host|{}host[0] + final fun (): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidHost.host.|(){}[0] + final val reason // org.dexpace.kuri.error/UriParseError.InvalidHost.reason|{}reason[0] + final fun (): org.dexpace.kuri.error/HostError // org.dexpace.kuri.error/UriParseError.InvalidHost.reason.|(){}[0] + + final fun component1(): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidHost.component1|component1(){}[0] + final fun component2(): org.dexpace.kuri.error/HostError // org.dexpace.kuri.error/UriParseError.InvalidHost.component2|component2(){}[0] + final fun copy(kotlin/String = ..., org.dexpace.kuri.error/HostError = ...): org.dexpace.kuri.error/UriParseError.InvalidHost // org.dexpace.kuri.error/UriParseError.InvalidHost.copy|copy(kotlin.String;org.dexpace.kuri.error.HostError){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.InvalidHost.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidHost.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidHost.toString|toString(){}[0] + } + + final class InvalidPercentEncoding : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding|null[0] + constructor (kotlin/Int) // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.|(kotlin.Int){}[0] + + final val at // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.at|{}at[0] + final fun (): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.at.|(){}[0] + + final fun component1(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.component1|component1(){}[0] + final fun copy(kotlin/Int = ...): org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.copy|copy(kotlin.Int){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidPercentEncoding.toString|toString(){}[0] + } + + final class InvalidPort : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.InvalidPort|null[0] + constructor (kotlin/String) // org.dexpace.kuri.error/UriParseError.InvalidPort.|(kotlin.String){}[0] + + final val text // org.dexpace.kuri.error/UriParseError.InvalidPort.text|{}text[0] + final fun (): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidPort.text.|(){}[0] + + final fun component1(): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidPort.component1|component1(){}[0] + final fun copy(kotlin/String = ...): org.dexpace.kuri.error/UriParseError.InvalidPort // org.dexpace.kuri.error/UriParseError.InvalidPort.copy|copy(kotlin.String){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.InvalidPort.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidPort.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidPort.toString|toString(){}[0] + } + + final class InvalidScheme : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.InvalidScheme|null[0] + constructor (kotlin/Int, kotlin/String) // org.dexpace.kuri.error/UriParseError.InvalidScheme.|(kotlin.Int;kotlin.String){}[0] + + final val at // org.dexpace.kuri.error/UriParseError.InvalidScheme.at|{}at[0] + final fun (): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidScheme.at.|(){}[0] + final val detail // org.dexpace.kuri.error/UriParseError.InvalidScheme.detail|{}detail[0] + final fun (): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidScheme.detail.|(){}[0] + + final fun component1(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidScheme.component1|component1(){}[0] + final fun component2(): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidScheme.component2|component2(){}[0] + final fun copy(kotlin/Int = ..., kotlin/String = ...): org.dexpace.kuri.error/UriParseError.InvalidScheme // org.dexpace.kuri.error/UriParseError.InvalidScheme.copy|copy(kotlin.Int;kotlin.String){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.InvalidScheme.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.InvalidScheme.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.InvalidScheme.toString|toString(){}[0] + } + + final object EmptyHost : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.EmptyHost|null[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.EmptyHost.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.EmptyHost.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.EmptyHost.toString|toString(){}[0] + } + + final object MissingScheme : org.dexpace.kuri.error/UriParseError { // org.dexpace.kuri.error/UriParseError.MissingScheme|null[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.error/UriParseError.MissingScheme.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.error/UriParseError.MissingScheme.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.error/UriParseError.MissingScheme.toString|toString(){}[0] + } +} + +sealed interface org.dexpace.kuri.host/Host { // org.dexpace.kuri.host/Host|null[0] + open fun asText(): kotlin/String // org.dexpace.kuri.host/Host.asText|asText(){}[0] + + final class IpFuture : org.dexpace.kuri.host/Host { // org.dexpace.kuri.host/Host.IpFuture|null[0] + constructor (kotlin/String) // org.dexpace.kuri.host/Host.IpFuture.|(kotlin.String){}[0] + + final val value // org.dexpace.kuri.host/Host.IpFuture.value|{}value[0] + final fun (): kotlin/String // org.dexpace.kuri.host/Host.IpFuture.value.|(){}[0] + + final fun component1(): kotlin/String // org.dexpace.kuri.host/Host.IpFuture.component1|component1(){}[0] + final fun copy(kotlin/String = ...): org.dexpace.kuri.host/Host.IpFuture // org.dexpace.kuri.host/Host.IpFuture.copy|copy(kotlin.String){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.host/Host.IpFuture.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.host/Host.IpFuture.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.host/Host.IpFuture.toString|toString(){}[0] + } + + final class Ipv4 : org.dexpace.kuri.host/Host { // org.dexpace.kuri.host/Host.Ipv4|null[0] + constructor (kotlin/Int) // org.dexpace.kuri.host/Host.Ipv4.|(kotlin.Int){}[0] + + final val value // org.dexpace.kuri.host/Host.Ipv4.value|{}value[0] + final fun (): kotlin/Int // org.dexpace.kuri.host/Host.Ipv4.value.|(){}[0] + + final fun component1(): kotlin/Int // org.dexpace.kuri.host/Host.Ipv4.component1|component1(){}[0] + final fun copy(kotlin/Int = ...): org.dexpace.kuri.host/Host.Ipv4 // org.dexpace.kuri.host/Host.Ipv4.copy|copy(kotlin.Int){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.host/Host.Ipv4.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.host/Host.Ipv4.hashCode|hashCode(){}[0] + final fun octets(): kotlin/IntArray // org.dexpace.kuri.host/Host.Ipv4.octets|octets(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.host/Host.Ipv4.toString|toString(){}[0] + } + + final class Ipv6 : org.dexpace.kuri.host/Host { // org.dexpace.kuri.host/Host.Ipv6|null[0] + constructor (kotlin.collections/List, kotlin/String? = ...) // org.dexpace.kuri.host/Host.Ipv6.|(kotlin.collections.List;kotlin.String?){}[0] + + final val pieces // org.dexpace.kuri.host/Host.Ipv6.pieces|{}pieces[0] + final fun (): kotlin.collections/List // org.dexpace.kuri.host/Host.Ipv6.pieces.|(){}[0] + final val zoneId // org.dexpace.kuri.host/Host.Ipv6.zoneId|{}zoneId[0] + final fun (): kotlin/String? // org.dexpace.kuri.host/Host.Ipv6.zoneId.|(){}[0] + + final fun component1(): kotlin.collections/List // org.dexpace.kuri.host/Host.Ipv6.component1|component1(){}[0] + final fun component2(): kotlin/String? // org.dexpace.kuri.host/Host.Ipv6.component2|component2(){}[0] + final fun copy(kotlin.collections/List = ..., kotlin/String? = ...): org.dexpace.kuri.host/Host.Ipv6 // org.dexpace.kuri.host/Host.Ipv6.copy|copy(kotlin.collections.List;kotlin.String?){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.host/Host.Ipv6.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.host/Host.Ipv6.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.host/Host.Ipv6.toString|toString(){}[0] + } + + final class Opaque : org.dexpace.kuri.host/Host { // org.dexpace.kuri.host/Host.Opaque|null[0] + constructor (kotlin/String) // org.dexpace.kuri.host/Host.Opaque.|(kotlin.String){}[0] + + final val value // org.dexpace.kuri.host/Host.Opaque.value|{}value[0] + final fun (): kotlin/String // org.dexpace.kuri.host/Host.Opaque.value.|(){}[0] + + final fun component1(): kotlin/String // org.dexpace.kuri.host/Host.Opaque.component1|component1(){}[0] + final fun copy(kotlin/String = ...): org.dexpace.kuri.host/Host.Opaque // org.dexpace.kuri.host/Host.Opaque.copy|copy(kotlin.String){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.host/Host.Opaque.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.host/Host.Opaque.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.host/Host.Opaque.toString|toString(){}[0] + } + + final class RegName : org.dexpace.kuri.host/Host { // org.dexpace.kuri.host/Host.RegName|null[0] + constructor (kotlin/String) // org.dexpace.kuri.host/Host.RegName.|(kotlin.String){}[0] + + final val value // org.dexpace.kuri.host/Host.RegName.value|{}value[0] + final fun (): kotlin/String // org.dexpace.kuri.host/Host.RegName.value.|(){}[0] + + final fun component1(): kotlin/String // org.dexpace.kuri.host/Host.RegName.component1|component1(){}[0] + final fun copy(kotlin/String = ...): org.dexpace.kuri.host/Host.RegName // org.dexpace.kuri.host/Host.RegName.copy|copy(kotlin.String){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.host/Host.RegName.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.host/Host.RegName.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.host/Host.RegName.toString|toString(){}[0] + } + + final object Empty : org.dexpace.kuri.host/Host { // org.dexpace.kuri.host/Host.Empty|null[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.host/Host.Empty.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.host/Host.Empty.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.host/Host.Empty.toString|toString(){}[0] + } +} + +final class org.dexpace.kuri.error/UriSyntaxException : kotlin/IllegalArgumentException { // org.dexpace.kuri.error/UriSyntaxException|null[0] + final val error // org.dexpace.kuri.error/UriSyntaxException.error|{}error[0] + final fun (): org.dexpace.kuri.error/UriParseError // org.dexpace.kuri.error/UriSyntaxException.error.|(){}[0] +} + +final class org.dexpace.kuri.query/QueryParameter { // org.dexpace.kuri.query/QueryParameter|null[0] + constructor (kotlin/String, kotlin/String?) // org.dexpace.kuri.query/QueryParameter.|(kotlin.String;kotlin.String?){}[0] + + final val name // org.dexpace.kuri.query/QueryParameter.name|{}name[0] + final fun (): kotlin/String // org.dexpace.kuri.query/QueryParameter.name.|(){}[0] + final val value // org.dexpace.kuri.query/QueryParameter.value|{}value[0] + final fun (): kotlin/String? // org.dexpace.kuri.query/QueryParameter.value.|(){}[0] + + final fun component1(): kotlin/String // org.dexpace.kuri.query/QueryParameter.component1|component1(){}[0] + final fun component2(): kotlin/String? // org.dexpace.kuri.query/QueryParameter.component2|component2(){}[0] + final fun copy(kotlin/String = ..., kotlin/String? = ...): org.dexpace.kuri.query/QueryParameter // org.dexpace.kuri.query/QueryParameter.copy|copy(kotlin.String;kotlin.String?){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.query/QueryParameter.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.query/QueryParameter.hashCode|hashCode(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.query/QueryParameter.toString|toString(){}[0] +} + +final class org.dexpace.kuri.query/QueryParameters : kotlin.collections/Iterable { // org.dexpace.kuri.query/QueryParameters|null[0] + final val size // org.dexpace.kuri.query/QueryParameters.size|{}size[0] + final fun (): kotlin/Int // org.dexpace.kuri.query/QueryParameters.size.|(){}[0] + + final fun contains(kotlin/String): kotlin/Boolean // org.dexpace.kuri.query/QueryParameters.contains|contains(kotlin.String){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri.query/QueryParameters.equals|equals(kotlin.Any?){}[0] + final fun get(kotlin/String): kotlin/String? // org.dexpace.kuri.query/QueryParameters.get|get(kotlin.String){}[0] + final fun getAll(kotlin/String): kotlin.collections/List // org.dexpace.kuri.query/QueryParameters.getAll|getAll(kotlin.String){}[0] + final fun has(kotlin/String): kotlin/Boolean // org.dexpace.kuri.query/QueryParameters.has|has(kotlin.String){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri.query/QueryParameters.hashCode|hashCode(){}[0] + final fun isEmpty(): kotlin/Boolean // org.dexpace.kuri.query/QueryParameters.isEmpty|isEmpty(){}[0] + final fun iterator(): kotlin.collections/Iterator // org.dexpace.kuri.query/QueryParameters.iterator|iterator(){}[0] + final fun nameAt(kotlin/Int): kotlin/String // org.dexpace.kuri.query/QueryParameters.nameAt|nameAt(kotlin.Int){}[0] + final fun names(): kotlin.collections/Set // org.dexpace.kuri.query/QueryParameters.names|names(){}[0] + final fun newBuilder(): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParameters.newBuilder|newBuilder(){}[0] + final fun split(kotlin/String, kotlin/Char): kotlin.collections/List // org.dexpace.kuri.query/QueryParameters.split|split(kotlin.String;kotlin.Char){}[0] + final fun toFormUrlEncoded(): kotlin/String // org.dexpace.kuri.query/QueryParameters.toFormUrlEncoded|toFormUrlEncoded(){}[0] + final fun toMap(): kotlin.collections/Map // org.dexpace.kuri.query/QueryParameters.toMap|toMap(){}[0] + final fun toQueryString(): kotlin/String // org.dexpace.kuri.query/QueryParameters.toQueryString|toQueryString(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri.query/QueryParameters.toString|toString(){}[0] + final fun valueAt(kotlin/Int): kotlin/String? // org.dexpace.kuri.query/QueryParameters.valueAt|valueAt(kotlin.Int){}[0] + + final object Companion { // org.dexpace.kuri.query/QueryParameters.Companion|null[0] + final fun of(kotlin.collections/Map): org.dexpace.kuri.query/QueryParameters // org.dexpace.kuri.query/QueryParameters.Companion.of|of(kotlin.collections.Map){}[0] + final fun of(kotlin/Array...): org.dexpace.kuri.query/QueryParameters // org.dexpace.kuri.query/QueryParameters.Companion.of|of(kotlin.Array...){}[0] + final fun parse(kotlin/String): org.dexpace.kuri.query/QueryParameters // org.dexpace.kuri.query/QueryParameters.Companion.parse|parse(kotlin.String){}[0] + final fun parseForm(kotlin/String): org.dexpace.kuri.query/QueryParameters // org.dexpace.kuri.query/QueryParameters.Companion.parseForm|parseForm(kotlin.String){}[0] + } +} + +final class org.dexpace.kuri.query/QueryParametersBuilder { // org.dexpace.kuri.query/QueryParametersBuilder|null[0] + constructor () // org.dexpace.kuri.query/QueryParametersBuilder.|(){}[0] + + final fun add(kotlin/String, kotlin/String?): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParametersBuilder.add|add(kotlin.String;kotlin.String?){}[0] + final fun add(org.dexpace.kuri.query/QueryParameter): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParametersBuilder.add|add(org.dexpace.kuri.query.QueryParameter){}[0] + final fun addAll(kotlin.collections/Map): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParametersBuilder.addAll|addAll(kotlin.collections.Map){}[0] + final fun build(): org.dexpace.kuri.query/QueryParameters // org.dexpace.kuri.query/QueryParametersBuilder.build|build(){}[0] + final fun removeAll(kotlin/String): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParametersBuilder.removeAll|removeAll(kotlin.String){}[0] + final fun set(kotlin/String, kotlin/String?): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParametersBuilder.set|set(kotlin.String;kotlin.String?){}[0] + final fun set(org.dexpace.kuri.query/QueryParameter): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParametersBuilder.set|set(org.dexpace.kuri.query.QueryParameter){}[0] + final fun sort(): org.dexpace.kuri.query/QueryParametersBuilder // org.dexpace.kuri.query/QueryParametersBuilder.sort|sort(){}[0] +} + +final class org.dexpace.kuri/ParseOptions { // org.dexpace.kuri/ParseOptions|null[0] + final val allowIpv6ZoneId // org.dexpace.kuri/ParseOptions.allowIpv6ZoneId|{}allowIpv6ZoneId[0] + final fun (): kotlin/Boolean // org.dexpace.kuri/ParseOptions.allowIpv6ZoneId.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri/ParseOptions.equals|equals(kotlin.Any?){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri/ParseOptions.hashCode|hashCode(){}[0] + final fun newBuilder(): org.dexpace.kuri/ParseOptions.Builder // org.dexpace.kuri/ParseOptions.newBuilder|newBuilder(){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri/ParseOptions.toString|toString(){}[0] + + final class Builder { // org.dexpace.kuri/ParseOptions.Builder|null[0] + constructor () // org.dexpace.kuri/ParseOptions.Builder.|(){}[0] + + final fun allowIpv6ZoneId(kotlin/Boolean): org.dexpace.kuri/ParseOptions.Builder // org.dexpace.kuri/ParseOptions.Builder.allowIpv6ZoneId|allowIpv6ZoneId(kotlin.Boolean){}[0] + final fun build(): org.dexpace.kuri/ParseOptions // org.dexpace.kuri/ParseOptions.Builder.build|build(){}[0] + } + + final object Companion { // org.dexpace.kuri/ParseOptions.Companion|null[0] + final val DEFAULT // org.dexpace.kuri/ParseOptions.Companion.DEFAULT|{}DEFAULT[0] + final fun (): org.dexpace.kuri/ParseOptions // org.dexpace.kuri/ParseOptions.Companion.DEFAULT.|(){}[0] + } +} + +final class org.dexpace.kuri/Uri { // org.dexpace.kuri/Uri|null[0] + final val authority // org.dexpace.kuri/Uri.authority|{}authority[0] + final fun (): kotlin/String? // org.dexpace.kuri/Uri.authority.|(){}[0] + final val encodedPath // org.dexpace.kuri/Uri.encodedPath|{}encodedPath[0] + final fun (): kotlin/String // org.dexpace.kuri/Uri.encodedPath.|(){}[0] + final val fragment // org.dexpace.kuri/Uri.fragment|{}fragment[0] + final fun (): kotlin/String? // org.dexpace.kuri/Uri.fragment.|(){}[0] + final val host // org.dexpace.kuri/Uri.host|{}host[0] + final fun (): org.dexpace.kuri.host/Host? // org.dexpace.kuri/Uri.host.|(){}[0] + final val hostName // org.dexpace.kuri/Uri.hostName|{}hostName[0] + final fun (): kotlin/String? // org.dexpace.kuri/Uri.hostName.|(){}[0] + final val path // org.dexpace.kuri/Uri.path|{}path[0] + final fun (): kotlin/String // org.dexpace.kuri/Uri.path.|(){}[0] + final val pathSegments // org.dexpace.kuri/Uri.pathSegments|{}pathSegments[0] + final fun (): kotlin.collections/List // org.dexpace.kuri/Uri.pathSegments.|(){}[0] + final val port // org.dexpace.kuri/Uri.port|{}port[0] + final fun (): kotlin/Int? // org.dexpace.kuri/Uri.port.|(){}[0] + final val query // org.dexpace.kuri/Uri.query|{}query[0] + final fun (): kotlin/String? // org.dexpace.kuri/Uri.query.|(){}[0] + final val scheme // org.dexpace.kuri/Uri.scheme|{}scheme[0] + final fun (): kotlin/String? // org.dexpace.kuri/Uri.scheme.|(){}[0] + final val uriString // org.dexpace.kuri/Uri.uriString|{}uriString[0] + final fun (): kotlin/String // org.dexpace.kuri/Uri.uriString.|(){}[0] + final val userInfo // org.dexpace.kuri/Uri.userInfo|{}userInfo[0] + final fun (): kotlin/String? // org.dexpace.kuri/Uri.userInfo.|(){}[0] + + final fun effectivePort(): kotlin/Int? // org.dexpace.kuri/Uri.effectivePort|effectivePort(){}[0] + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri/Uri.equals|equals(kotlin.Any?){}[0] + final fun fileExtension(): kotlin/String // org.dexpace.kuri/Uri.fileExtension|fileExtension(){}[0] + final fun fileName(): kotlin/String // org.dexpace.kuri/Uri.fileName|fileName(){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri/Uri.hashCode|hashCode(){}[0] + final fun isAbsolute(): kotlin/Boolean // org.dexpace.kuri/Uri.isAbsolute|isAbsolute(){}[0] + final fun isOpaquePath(): kotlin/Boolean // org.dexpace.kuri/Uri.isOpaquePath|isOpaquePath(){}[0] + final fun newBuilder(): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.newBuilder|newBuilder(){}[0] + final fun normalized(): org.dexpace.kuri/Uri // org.dexpace.kuri/Uri.normalized|normalized(){}[0] + final fun normalizedEquals(org.dexpace.kuri/Uri): kotlin/Boolean // org.dexpace.kuri/Uri.normalizedEquals|normalizedEquals(org.dexpace.kuri.Uri){}[0] + final fun queryParameters(): org.dexpace.kuri.query/QueryParameters // org.dexpace.kuri/Uri.queryParameters|queryParameters(){}[0] + final fun relativize(org.dexpace.kuri/Uri): org.dexpace.kuri/Uri? // org.dexpace.kuri/Uri.relativize|relativize(org.dexpace.kuri.Uri){}[0] + final fun resolve(kotlin/String, org.dexpace.kuri/ParseOptions = ...): org.dexpace.kuri.error/ParseResult // org.dexpace.kuri/Uri.resolve|resolve(kotlin.String;org.dexpace.kuri.ParseOptions){}[0] + final fun resolveOrNull(kotlin/String, org.dexpace.kuri/ParseOptions = ...): org.dexpace.kuri/Uri? // org.dexpace.kuri/Uri.resolveOrNull|resolveOrNull(kotlin.String;org.dexpace.kuri.ParseOptions){}[0] + final fun resolveOrThrow(kotlin/String, org.dexpace.kuri/ParseOptions = ...): org.dexpace.kuri/Uri // org.dexpace.kuri/Uri.resolveOrThrow|resolveOrThrow(kotlin.String;org.dexpace.kuri.ParseOptions){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri/Uri.toString|toString(){}[0] + final fun toUrl(): org.dexpace.kuri.error/ParseResult // org.dexpace.kuri/Uri.toUrl|toUrl(){}[0] + final fun toUrlOrNull(): org.dexpace.kuri/Url? // org.dexpace.kuri/Uri.toUrlOrNull|toUrlOrNull(){}[0] + final fun toUrlOrThrow(): org.dexpace.kuri/Url // org.dexpace.kuri/Uri.toUrlOrThrow|toUrlOrThrow(){}[0] + final fun withFragment(kotlin/String?): org.dexpace.kuri/Uri // org.dexpace.kuri/Uri.withFragment|withFragment(kotlin.String?){}[0] + final fun withPort(kotlin/Int?): org.dexpace.kuri/Uri // org.dexpace.kuri/Uri.withPort|withPort(kotlin.Int?){}[0] + final fun withoutFragment(): org.dexpace.kuri/Uri // org.dexpace.kuri/Uri.withoutFragment|withoutFragment(){}[0] + + final class Builder { // org.dexpace.kuri/Uri.Builder|null[0] + constructor () // org.dexpace.kuri/Uri.Builder.|(){}[0] + + final fun addEncodedPathSegment(kotlin/String): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.addEncodedPathSegment|addEncodedPathSegment(kotlin.String){}[0] + final fun addPathSegment(kotlin/String): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.addPathSegment|addPathSegment(kotlin.String){}[0] + final fun addPathSegments(kotlin/String): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.addPathSegments|addPathSegments(kotlin.String){}[0] + final fun addQueryParameter(kotlin/String, kotlin/String?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.addQueryParameter|addQueryParameter(kotlin.String;kotlin.String?){}[0] + final fun allowIpv6ZoneId(kotlin/Boolean): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.allowIpv6ZoneId|allowIpv6ZoneId(kotlin.Boolean){}[0] + final fun build(): org.dexpace.kuri/Uri // org.dexpace.kuri/Uri.Builder.build|build(){}[0] + final fun buildOrNull(): org.dexpace.kuri/Uri? // org.dexpace.kuri/Uri.Builder.buildOrNull|buildOrNull(){}[0] + final fun encodedPath(kotlin/String): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.encodedPath|encodedPath(kotlin.String){}[0] + final fun fragment(kotlin/String?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.fragment|fragment(kotlin.String?){}[0] + final fun host(kotlin/String?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.host|host(kotlin.String?){}[0] + final fun host(org.dexpace.kuri.host/Host): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.host|host(org.dexpace.kuri.host.Host){}[0] + final fun port(kotlin/Int?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.port|port(kotlin.Int?){}[0] + final fun query(kotlin/String?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.query|query(kotlin.String?){}[0] + final fun removeAllQueryParameters(kotlin/String): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.removeAllQueryParameters|removeAllQueryParameters(kotlin.String){}[0] + final fun removePathSegment(kotlin/Int): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.removePathSegment|removePathSegment(kotlin.Int){}[0] + final fun scheme(kotlin/String?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.scheme|scheme(kotlin.String?){}[0] + final fun setPathSegment(kotlin/Int, kotlin/String): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.setPathSegment|setPathSegment(kotlin.Int;kotlin.String){}[0] + final fun setQueryParameter(kotlin/String, kotlin/String?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.setQueryParameter|setQueryParameter(kotlin.String;kotlin.String?){}[0] + final fun userInfo(kotlin/String?): org.dexpace.kuri/Uri.Builder // org.dexpace.kuri/Uri.Builder.userInfo|userInfo(kotlin.String?){}[0] + } + + final object Companion { // org.dexpace.kuri/Uri.Companion|null[0] + final fun canParse(kotlin/String, org.dexpace.kuri/ParseOptions = ...): kotlin/Boolean // org.dexpace.kuri/Uri.Companion.canParse|canParse(kotlin.String;org.dexpace.kuri.ParseOptions){}[0] + final fun parse(kotlin/String, org.dexpace.kuri/ParseOptions = ...): org.dexpace.kuri.error/ParseResult // org.dexpace.kuri/Uri.Companion.parse|parse(kotlin.String;org.dexpace.kuri.ParseOptions){}[0] + final fun parseOrNull(kotlin/String, org.dexpace.kuri/ParseOptions = ...): org.dexpace.kuri/Uri? // org.dexpace.kuri/Uri.Companion.parseOrNull|parseOrNull(kotlin.String;org.dexpace.kuri.ParseOptions){}[0] + final fun parseOrThrow(kotlin/String, org.dexpace.kuri/ParseOptions = ...): org.dexpace.kuri/Uri // org.dexpace.kuri/Uri.Companion.parseOrThrow|parseOrThrow(kotlin.String;org.dexpace.kuri.ParseOptions){}[0] + } +} + +final class org.dexpace.kuri/Url { // org.dexpace.kuri/Url|null[0] + final val authority // org.dexpace.kuri/Url.authority|{}authority[0] + final fun (): kotlin/String? // org.dexpace.kuri/Url.authority.|(){}[0] + final val effectivePort // org.dexpace.kuri/Url.effectivePort|{}effectivePort[0] + final fun (): kotlin/Int // org.dexpace.kuri/Url.effectivePort.|(){}[0] + final val encodedFragment // org.dexpace.kuri/Url.encodedFragment|{}encodedFragment[0] + final fun (): kotlin/String? // org.dexpace.kuri/Url.encodedFragment.|(){}[0] + final val encodedPath // org.dexpace.kuri/Url.encodedPath|{}encodedPath[0] + final fun (): kotlin/String // org.dexpace.kuri/Url.encodedPath.|(){}[0] + final val fragment // org.dexpace.kuri/Url.fragment|{}fragment[0] + final fun (): kotlin/String? // org.dexpace.kuri/Url.fragment.|(){}[0] + final val host // org.dexpace.kuri/Url.host|{}host[0] + final fun (): org.dexpace.kuri.host/Host? // org.dexpace.kuri/Url.host.|(){}[0] + final val hostName // org.dexpace.kuri/Url.hostName|{}hostName[0] + final fun (): kotlin/String? // org.dexpace.kuri/Url.hostName.|(){}[0] + final val href // org.dexpace.kuri/Url.href|{}href[0] + final fun (): kotlin/String // org.dexpace.kuri/Url.href.|(){}[0] + final val origin // org.dexpace.kuri/Url.origin|{}origin[0] + final fun (): kotlin/String // org.dexpace.kuri/Url.origin.|(){}[0] + final val password // org.dexpace.kuri/Url.password|{}password[0] + final fun (): kotlin/String // org.dexpace.kuri/Url.password.|(){}[0] + final val pathSegments // org.dexpace.kuri/Url.pathSegments|{}pathSegments[0] + final fun (): kotlin.collections/List // org.dexpace.kuri/Url.pathSegments.|(){}[0] + final val port // org.dexpace.kuri/Url.port|{}port[0] + final fun (): kotlin/Int? // org.dexpace.kuri/Url.port.|(){}[0] + final val query // org.dexpace.kuri/Url.query|{}query[0] + final fun (): kotlin/String? // org.dexpace.kuri/Url.query.|(){}[0] + final val queryParameters // org.dexpace.kuri/Url.queryParameters|{}queryParameters[0] + final fun (): org.dexpace.kuri.query/QueryParameters // org.dexpace.kuri/Url.queryParameters.|(){}[0] + final val scheme // org.dexpace.kuri/Url.scheme|{}scheme[0] + final fun (): kotlin/String // org.dexpace.kuri/Url.scheme.|(){}[0] + final val username // org.dexpace.kuri/Url.username|{}username[0] + final fun (): kotlin/String // org.dexpace.kuri/Url.username.|(){}[0] + + final fun equals(kotlin/Any?): kotlin/Boolean // org.dexpace.kuri/Url.equals|equals(kotlin.Any?){}[0] + final fun fileExtension(): kotlin/String // org.dexpace.kuri/Url.fileExtension|fileExtension(){}[0] + final fun fileName(): kotlin/String // org.dexpace.kuri/Url.fileName|fileName(){}[0] + final fun hasOpaqueOrigin(): kotlin/Boolean // org.dexpace.kuri/Url.hasOpaqueOrigin|hasOpaqueOrigin(){}[0] + final fun hashCode(): kotlin/Int // org.dexpace.kuri/Url.hashCode|hashCode(){}[0] + final fun isSpecial(): kotlin/Boolean // org.dexpace.kuri/Url.isSpecial|isSpecial(){}[0] + final fun newBuilder(): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.newBuilder|newBuilder(){}[0] + final fun relativize(org.dexpace.kuri/Url): kotlin/String? // org.dexpace.kuri/Url.relativize|relativize(org.dexpace.kuri.Url){}[0] + final fun resolve(kotlin/String): org.dexpace.kuri.error/ParseResult // org.dexpace.kuri/Url.resolve|resolve(kotlin.String){}[0] + final fun resolveOrNull(kotlin/String): org.dexpace.kuri/Url? // org.dexpace.kuri/Url.resolveOrNull|resolveOrNull(kotlin.String){}[0] + final fun resolveOrThrow(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.resolveOrThrow|resolveOrThrow(kotlin.String){}[0] + final fun toString(): kotlin/String // org.dexpace.kuri/Url.toString|toString(){}[0] + final fun toUri(): org.dexpace.kuri/Uri // org.dexpace.kuri/Url.toUri|toUri(){}[0] + final fun validationErrors(): kotlin.collections/List // org.dexpace.kuri/Url.validationErrors|validationErrors(){}[0] + final fun withFragment(kotlin/String?): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withFragment|withFragment(kotlin.String?){}[0] + final fun withHash(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withHash|withHash(kotlin.String){}[0] + final fun withHost(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withHost|withHost(kotlin.String){}[0] + final fun withHostname(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withHostname|withHostname(kotlin.String){}[0] + final fun withPassword(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withPassword|withPassword(kotlin.String){}[0] + final fun withPathname(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withPathname|withPathname(kotlin.String){}[0] + final fun withPort(kotlin/Int?): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withPort|withPort(kotlin.Int?){}[0] + final fun withPort(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withPort|withPort(kotlin.String){}[0] + final fun withProtocol(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withProtocol|withProtocol(kotlin.String){}[0] + final fun withSearch(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withSearch|withSearch(kotlin.String){}[0] + final fun withUsername(kotlin/String): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withUsername|withUsername(kotlin.String){}[0] + final fun withoutFragment(): org.dexpace.kuri/Url // org.dexpace.kuri/Url.withoutFragment|withoutFragment(){}[0] + + final class Builder { // org.dexpace.kuri/Url.Builder|null[0] + constructor () // org.dexpace.kuri/Url.Builder.|(){}[0] + + final fun addEncodedPathSegment(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.addEncodedPathSegment|addEncodedPathSegment(kotlin.String){}[0] + final fun addPathSegment(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.addPathSegment|addPathSegment(kotlin.String){}[0] + final fun addPathSegments(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.addPathSegments|addPathSegments(kotlin.String){}[0] + final fun addQueryParameter(kotlin/String, kotlin/String?): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.addQueryParameter|addQueryParameter(kotlin.String;kotlin.String?){}[0] + final fun build(): org.dexpace.kuri/Url // org.dexpace.kuri/Url.Builder.build|build(){}[0] + final fun buildOrNull(): org.dexpace.kuri/Url? // org.dexpace.kuri/Url.Builder.buildOrNull|buildOrNull(){}[0] + final fun encodedPath(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.encodedPath|encodedPath(kotlin.String){}[0] + final fun fragment(kotlin/String?): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.fragment|fragment(kotlin.String?){}[0] + final fun host(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.host|host(kotlin.String){}[0] + final fun host(org.dexpace.kuri.host/Host): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.host|host(org.dexpace.kuri.host.Host){}[0] + final fun password(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.password|password(kotlin.String){}[0] + final fun port(kotlin/Int?): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.port|port(kotlin.Int?){}[0] + final fun query(kotlin/String?): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.query|query(kotlin.String?){}[0] + final fun removeAllQueryParameters(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.removeAllQueryParameters|removeAllQueryParameters(kotlin.String){}[0] + final fun removePathSegment(kotlin/Int): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.removePathSegment|removePathSegment(kotlin.Int){}[0] + final fun scheme(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.scheme|scheme(kotlin.String){}[0] + final fun setPathSegment(kotlin/Int, kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.setPathSegment|setPathSegment(kotlin.Int;kotlin.String){}[0] + final fun setQueryParameter(kotlin/String, kotlin/String?): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.setQueryParameter|setQueryParameter(kotlin.String;kotlin.String?){}[0] + final fun username(kotlin/String): org.dexpace.kuri/Url.Builder // org.dexpace.kuri/Url.Builder.username|username(kotlin.String){}[0] + } + + final object Companion { // org.dexpace.kuri/Url.Companion|null[0] + final fun canParse(kotlin/String, org.dexpace.kuri/Url? = ...): kotlin/Boolean // org.dexpace.kuri/Url.Companion.canParse|canParse(kotlin.String;org.dexpace.kuri.Url?){}[0] + final fun parse(kotlin/String, org.dexpace.kuri/Url? = ...): org.dexpace.kuri.error/ParseResult // org.dexpace.kuri/Url.Companion.parse|parse(kotlin.String;org.dexpace.kuri.Url?){}[0] + final fun parseOrNull(kotlin/String, org.dexpace.kuri/Url? = ...): org.dexpace.kuri/Url? // org.dexpace.kuri/Url.Companion.parseOrNull|parseOrNull(kotlin.String;org.dexpace.kuri.Url?){}[0] + final fun parseOrThrow(kotlin/String, org.dexpace.kuri/Url? = ...): org.dexpace.kuri/Url // org.dexpace.kuri/Url.Companion.parseOrThrow|parseOrThrow(kotlin.String;org.dexpace.kuri.Url?){}[0] + } +} + +final object org.dexpace.kuri.idna/Idn { // org.dexpace.kuri.idna/Idn|null[0] + final fun toAscii(kotlin/String): org.dexpace.kuri.error/ParseResult // org.dexpace.kuri.idna/Idn.toAscii|toAscii(kotlin.String){}[0] + final fun toUnicode(kotlin/String): kotlin/String // org.dexpace.kuri.idna/Idn.toUnicode|toUnicode(kotlin.String){}[0] +} + +final object org.dexpace.kuri.percent/Percent { // org.dexpace.kuri.percent/Percent|null[0] + final fun decode(kotlin/String): kotlin/String // org.dexpace.kuri.percent/Percent.decode|decode(kotlin.String){}[0] + final fun encode(kotlin/String, org.dexpace.kuri.percent/Percent.Component): kotlin/String // org.dexpace.kuri.percent/Percent.encode|encode(kotlin.String;org.dexpace.kuri.percent.Percent.Component){}[0] + + final enum class Component : kotlin/Enum { // org.dexpace.kuri.percent/Percent.Component|null[0] + enum entry COMPONENT // org.dexpace.kuri.percent/Percent.Component.COMPONENT|null[0] + enum entry FRAGMENT // org.dexpace.kuri.percent/Percent.Component.FRAGMENT|null[0] + enum entry PATH_SEGMENT // org.dexpace.kuri.percent/Percent.Component.PATH_SEGMENT|null[0] + enum entry QUERY // org.dexpace.kuri.percent/Percent.Component.QUERY|null[0] + enum entry USER_INFO // org.dexpace.kuri.percent/Percent.Component.USER_INFO|null[0] + + final val entries // org.dexpace.kuri.percent/Percent.Component.entries|#static{}entries[0] + final fun (): kotlin.enums/EnumEntries // org.dexpace.kuri.percent/Percent.Component.entries.|#static(){}[0] + + final fun valueOf(kotlin/String): org.dexpace.kuri.percent/Percent.Component // org.dexpace.kuri.percent/Percent.Component.valueOf|valueOf#static(kotlin.String){}[0] + final fun values(): kotlin/Array // org.dexpace.kuri.percent/Percent.Component.values|values#static(){}[0] + } +} + +final object org.dexpace.kuri.scheme/Schemes { // org.dexpace.kuri.scheme/Schemes|null[0] + final fun defaultPort(kotlin/String): kotlin/Int? // org.dexpace.kuri.scheme/Schemes.defaultPort|defaultPort(kotlin.String){}[0] + final fun isSpecial(kotlin/String): kotlin/Boolean // org.dexpace.kuri.scheme/Schemes.isSpecial|isSpecial(kotlin.String){}[0] + final fun isValid(kotlin/String): kotlin/Boolean // org.dexpace.kuri.scheme/Schemes.isValid|isValid(kotlin.String){}[0] +} + +final object org.dexpace.kuri/Iri { // org.dexpace.kuri/Iri|null[0] + final fun toUnicode(org.dexpace.kuri/Uri): kotlin/String // org.dexpace.kuri/Iri.toUnicode|toUnicode(org.dexpace.kuri.Uri){}[0] + final fun toUri(kotlin/String): org.dexpace.kuri.error/ParseResult // org.dexpace.kuri/Iri.toUri|toUri(kotlin.String){}[0] +} + +final object org.dexpace.kuri/Kuri { // org.dexpace.kuri/Kuri|null[0] + final const val VERSION // org.dexpace.kuri/Kuri.VERSION|{}VERSION[0] + final fun (): kotlin/String // org.dexpace.kuri/Kuri.VERSION.|(){}[0] +} + +final fun <#A: kotlin/Any?, #B: kotlin/Any?> (org.dexpace.kuri.error/ParseResult<#A>).org.dexpace.kuri.error/map(kotlin/Function1<#A, #B>): org.dexpace.kuri.error/ParseResult<#B> // org.dexpace.kuri.error/map|map@org.dexpace.kuri.error.ParseResult<0:0>(kotlin.Function1<0:0,0:1>){0§;1§}[0] +final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> (org.dexpace.kuri.error/ParseResult<#A>).org.dexpace.kuri.error/fold(kotlin/Function1<#A, #B>, kotlin/Function1): #B // org.dexpace.kuri.error/fold|fold@org.dexpace.kuri.error.ParseResult<0:0>(kotlin.Function1<0:0,0:1>;kotlin.Function1){0§;1§}[0] diff --git a/kuri/build.gradle.kts b/kuri/build.gradle.kts index a053e39..1d7e7b2 100644 --- a/kuri/build.gradle.kts +++ b/kuri/build.gradle.kts @@ -1,4 +1,7 @@ -@file:OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class) +@file:OptIn( + org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class, + kotlinx.validation.ExperimentalBCVApi::class, +) import com.vanniktech.maven.publish.JavadocJar import com.vanniktech.maven.publish.KotlinMultiplatform @@ -221,6 +224,17 @@ kover { } } +// Enforce the native (KLIB) public ABI, not only the JVM/Android one. binary-compatibility-validator's +// klib validation is experimental and off by default, so `apiCheck` was already compiling every native +// klib but then skipping the comparison — wasted work that guaranteed nothing. Enabling it makes +// `apiDump` emit the merged `api/kuri.klib.api` snapshot and `apiCheck` diff each native target's ABI +// against it, so a source-compatible but ABI-breaking change to the native surface fails the build. +apiValidation { + klib { + enabled = true + } +} + // Publish every Kotlin Multiplatform target (plus the root `kotlinMultiplatform` publication) to Maven // Central through the Central Portal. The vanniktech plugin wires the per-target publications, a // Dokka-generated Javadoc jar and GPG signing; coordinates derive from the module `group` and the