Go to file
2026-09-06 00:13:08 -04:00
api feat(api): bootstrap consumer plugins from Gradle configuration 2026-09-06 00:13:08 -04:00
gradle Initial commit 2026-06-16 11:24:56 -07:00
gradle-plugin feat(api): bootstrap consumer plugins from Gradle configuration 2026-09-06 00:13:08 -04:00
src/wasmWasiMain/kotlin/plugin feat(api): package Kotlin bindings for Gradle consumers 2026-09-05 20:47:08 -04:00
wit@1ad73fff1e feat(api): bootstrap consumer plugins from Gradle configuration 2026-09-06 00:13:08 -04:00
.gitignore feat(api): package Kotlin bindings for Gradle consumers 2026-09-05 20:47:08 -04:00
.gitmodules Initial commit 2026-06-16 11:24:56 -07:00
build.gradle.kts build: download prebuilt wasm-tools 2026-09-05 22:33:41 -04:00
gradle.properties Initial commit 2026-06-16 11:24:56 -07:00
gradlew Initial commit 2026-06-16 11:24:56 -07:00
gradlew.bat Initial commit 2026-06-16 11:24:56 -07:00
LICENSE-APACHE Relicense under MIT OR Apache-2.0 2026-08-15 10:54:40 -07:00
LICENSE-MIT Relicense under MIT OR Apache-2.0 2026-08-15 10:54:40 -07:00
plugin.wasm Initial commit 2026-06-16 11:24:56 -07:00
README.md feat(api): bootstrap consumer plugins from Gradle configuration 2026-09-06 00:13:08 -04:00
settings.gradle.kts feat(api): package Kotlin bindings for Gradle consumers 2026-09-05 20:47:08 -04:00
wasi_snapshot_preview1.reactor.wasm Initial commit 2026-06-16 11:24:56 -07:00

Pumpkin Plugin API for Kotlin

Build Kotlin plugins for Pumpkin as WebAssembly components.

The api module packages generated Kotlin bindings, the WIT export bridge, and the WIT snapshot and WASI adapter needed to build a component. The gradle-plugin module integrates that package into a plugin author's build. Plugin authors do not need Rust, wit-bindgen, or a WIT checkout.

Kotlin/Wasm component support is still experimental. The planned release destinations are Maven Central for the API and the Gradle Plugin Portal for the build plugin, though that is not certain yet.

Create a plugin

Create a Gradle project with a Gradle 9.x wrapper and JDK 17 or later. You do not need to clone this repository.

In settings.gradle.kts:

pluginManagement {
    repositories {
        gradlePluginPortal()
        mavenCentral()
    }
}

rootProject.name = "my-plugin"

In build.gradle.kts:

import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl

plugins {
    kotlin("multiplatform") version "2.4.0"
    id("io.github.pumpkin-mc.plugin") version "<plugin-version>"
}

repositories {
    mavenCentral()
}

kotlin {
    @OptIn(ExperimentalWasmDsl::class)
    wasmWasi {
        nodejs()
        binaries.executable()
    }
}

pumpkin {
    apiVersion.set("<api-version>")
    pluginClass.set("example.MyPlugin")
}

Important

Put your implementation in src/wasmWasiMain/kotlin/example/MyPlugin.kt. The wasmWasiMain source set is required; src/main/kotlin is not the source directory for this target.

package example

import plugin.PluginMetadata
import plugin.PumpkinPlugin
import pumpkin.Context
import pumpkin.Logging

class MyPlugin : PumpkinPlugin() {
    override fun metadata() = PluginMetadata(
        name = "my-plugin",
        version = "0.1.0",
        authors = listOf("Your name"),
        description = "My first Kotlin plugin",
        dependencies = emptyList(),
        permissions = emptyList(),
    )

    override fun onLoad(context: Context.Context): Result<Unit> {
        Logging.log(Logging.Level.INFO, "Hello from Kotlin!")
        return Result.success(Unit)
    }
}

The configured class must extend PumpkinPlugin and be constructible without arguments. Override the callbacks your plugin uses; most optional handler defaults throw if invoked without an implementation.

Build and load

From your plugin project:

./gradlew build

The Gradle plugin downloads a pinned prebuilt wasm-tools, compiles the Kotlin code, assembles the component, and validates it. The component is written to build/<project-name>.wasm (build/my-plugin.wasm above). Copy it into the Pumpkin server's plugins directory and start the server.

To assemble only the component, run ./gradlew assemblePluginRelease. Gradle skips tasks when their inputs are unchanged. The consumer's generated sources and downloaded tools live under build/, so ./gradlew clean removes them.

How the dependency and bootstrap work

The API publishes both a Kotlin/WASI KLIB and a generated-source archive. Currently, WIT exports must be compiled as part of the final plugin to be retained by the Kotlin/Wasm linker. The Gradle plugin therefore resolves the API's source archive through pumpkinApiSources, unpacks it, and adds it to wasmWasiMain. You do not add a separate implementation(...) dependency or run binding generation yourself.

generatePumpkinPluginBootstrap generates a factory from pumpkin.pluginClass:

package plugin

internal fun createPlugin(): PumpkinPlugin = example.MyPlugin()

This replaces the API's placeholder factory during consumer compilation. On the first exported callback, the API bridge constructs and caches your plugin instance. Later callbacks use the same instance. There is no need for main(), a top-level registration initializer, or a call to registerPlugin(...). The package also supplies the generator-specific PluginRootFunctionsExportsImpl and MetadataImpl bridges.

Server compatibility

Choose an API version compatible with your Pumpkin server. Errors such as no export ... found, type-checking export func ..., or missing imports indicate a possible mismatch between the plugin's packaged WIT and the server's contract. Update pumpkin.apiVersion to a compatible release and rebuild the component.

API development

Contributors building the API itself need JDK 17 or later and a host Rust toolchain. Gradle builds the pinned Kotlin-enabled wit-bindgen from source; no Rust WebAssembly target is required.

From this repository, generate the bindings and publish both development packages locally:

git submodule update --init --recursive
./gradlew :api:publishToMavenLocal :gradle-plugin:publishToMavenLocal

To test these local packages in a consumer, add mavenLocal() before the other repositories in both settings.gradle.kts's pluginManagement.repositories and build.gradle.kts's repositories. Set both version placeholders to 0.1.0-dev. After republishing changes under that version, run ./gradlew build --refresh-dependencies in the consumer.

The repository's legacy root template still uses the earlier main() registration approach. Use the separate consumer setup above for the bootstrap integration.

Updating the WIT

API maintainers should update the wit submodule to the revision compatible with the target Pumpkin server, then regenerate and republish the API. Commit the updated submodule revision with any required callback changes so builds use the same contract.

Attributions

This project was primarily derived from @jmrtsh's work on Kotlin/sample-wasi-http-kotlin, which is licensed under Apache-2.0.