SDKs · Kotlin / JVM

CAVS for the JVM.

Idiomatic Kotlin over the same Rust core the CLI uses, through the Java Foreign Function & Memory API (JEP 454). Typed @Serializable data classes, an AutoCloseable client, CompletableFuture async and progress lambdas. Published as io.github.orelvis15:cavs-sdk.

Coordinates

io.github.orelvis15:cavs-sdk:1.2.0

Gradle and Maven. The published jar bundles the native library per platform, with a SHA-256 sidecar the loader verifies.

Requires

Java 22+

The native bridge uses the FFM API finalized in Java 22. Run with --enable-native-access=ALL-UNNAMED.

Backend seam

NativeBridge

The FFM backend sits behind an interface, so an alternative bridge can slot in without touching CavsClient.

Install

Add the dependency.

Released builds bundle the platform library in the jar. For a source checkout, build cavs-ffi and point CAVS_SDK_LIBRARY at it.

// build.gradle.kts
dependencies {
    implementation("io.github.orelvis15:cavs-sdk:1.2.0")
}
<!-- pom.xml -->
<dependency>
  <groupId>io.github.orelvis15</groupId>
  <artifactId>cavs-sdk</artifactId>
  <version>1.2.0</version>
</dependency>
bash — local native library (source checkout) copy
$ cargo build --release -p cavs-ffi
$ export CAVS_SDK_LIBRARY="$PWD/target/release/libcavs_sdk.so"
Quickstart

Preview an update.

import com.cavs.sdk.CavsClient
import com.cavs.sdk.model.PreviewRequest

CavsClient.create().use { cavs ->
    val preview = cavs.preview(
        PreviewRequest(oldPath = "Build_v1", newPath = "Build_v2", policy = "balanced"),
    )
    println("Recommended route: ${preview.recommendedRoute}")
    preview.routes.forEach { println("  ${it.name}: ${it.networkBytes} bytes") }
}

Run with java --enable-native-access=ALL-UNNAMED ….

The API

Eight operations,
one client.

CavsClient is AutoCloseable. Every method takes a typed request and an optional (ProgressEvent) -> Unit lambda; previewAsync, createPlanAsync and applyPlanAsync return a CompletableFuture. Failures throw CavsException with a CavsErrorCode.

analyze(AnalyzeRequest)
Inspect an old→new transition: sizes, estimated update bytes, reuse ratios, worst files and layout findings with fixes.
packDirectory(PackDirectoryRequest)
Package a directory tree into a deduplicated .cavs container. Profile, compression, signing and .cavsignore globs.
preview(PreviewRequest)
Estimate the wire cost across routes and recommend the cheapest.
createPlan(CreatePlanRequest)
Build a portable, BLAKE3-sealed .cavsplan. Returns reuse and operation counts.
applyPlan(ApplyPlanRequest)
Apply a plan with verification — atomic for artifacts, staged + journaled for directories.
verifyInstall(VerifyRequest)
Check an install against a .cavssig or manifest; reports modified / missing / extra.
benchmark(BenchmarkRequest)
A repeatable route-comparison report with measured diff/apply timings.
estimateSavings(SavingsRequest)
Monthly egress cost of full downloads vs CAVS updates, and the savings.
Progress & async

Futures and
progress lambdas.

CavsClient.create().use { cavs ->
    // Async: returns a CompletableFuture.
    val future = cavs.createPlanAsync(
        CreatePlanRequest(oldPath = "Build_v1", newPath = "Build_v2", outputPlan = "update.cavsplan"),
    )

    // Sync with a progress lambda.
    val plan = cavs.createPlan(
        CreatePlanRequest(oldPath = "Build_v1", newPath = "Build_v2", outputPlan = "update.cavsplan"),
    ) { e -> println("[${e.type}] ${e.phase}") }

    try {
        cavs.analyze(AnalyzeRequest(oldPath = "missing", newPath = "Build_v2"))
    } catch (e: CavsException) {
        if (e.code == CavsErrorCode.PATH_NOT_FOUND) println("old build not found")
    }
}
CI/CD

Wire it into
your build service.

// Jenkins / Gradle — fail the build when the update is too large
pipeline {
  agent any
  stages {
    stage('CAVS Preview') {
      steps { sh './gradlew runCavsPreview' }
    }
  }
}

The reports are Kotlin data classes serialized with kotlinx.serialization — marshal them to JSON for dashboards, or assert on estimatedUpdateBytes to gate a release.