Skip to content

Kotlin: provide & consume

The Kotlin API mirrors the JS one. Every entry point takes a BridgeKit instance, defaulting to the shared BridgeKit.default — so tests substitute instances and feature code uses the one it was handed.

Implement the generated interface, then register a lazy factory:

class AppHostProvider(private val deps: AppDeps) : AppHost {
override suspend fun isLoggedIn(): Boolean = deps.session.isLoggedIn()
override suspend fun saveFile(params: SaveFileParams): SaveFileResult = deps.files.save(params)
override fun showLogin() { deps.nav.toLogin() }
override fun notifications(): Flow<String> = deps.push.messages()
override val connectivity = MutableStateFlow(Connectivity(online = true))
}
val binding = bridgekit.provide(AppHostContract, Scope.global) { AppHostProvider(deps) }
// later:
binding.close()
  • The factory is lazy — invoked on first resolution unless eager = true.
  • One live binding per (contract, scope); a duplicate provide replaces with a dev warning.
  • binding.close() is handle-scoped and a no-op if already superseded.

consume returns a typed proxy. It suspends until (dispatcher connected AND contract provided), bounded by the readiness timeout:

val inbox = bridgekit.consume(InboxFeatureContract) // suspend, readiness-bounded
val count = inbox.getUnreadCount()
inbox.sessionStatus.collect { value -> /* BridgeValue<SessionStatus> */ }

Non-suspending and explicit alternatives:

val maybe = bridgekit.tryConsume(InboxFeatureContract) // null if not ready
if (bridgekit.isProvided(InboxFeatureContract)) { /* ... */ }
bridgekit.awaitProvided(InboxFeatureContract, timeout) // explicit wait

Consumed state carries availability:

inbox.sessionStatus.collect { v ->
when (v) {
is BridgeValue.Available -> render(v.value)
is BridgeValue.Initial -> render(v.value) // seeded initial, no provider yet
is BridgeValue.Unprovided -> showStale(v.lastKnown) // binding closed
}
}

Generated proxy factories and lifecycle extensions take bridgekit: BridgeKit = BridgeKit.default. Feature code uses the instance it received — BridgeKitModule.register passes one (see Auto-discovery) — and tests pass a BridgeKit(testTransport).

class InboxController(private val bridgekit: BridgeKit) {
suspend fun unread() = bridgekit.consume(InboxFeatureContract).getUnreadCount()
}