Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

sideeffffect/dapr4s

Open more actions menu

Repository files navigation

dapr4s

CI Release
Build Status Release Artifacts

A Scala 3 library that exposes every Dapr building block as a capture-checked capability. Dapr effects — state, pub/sub, service invocation, secrets, configuration, bindings, distributed locks, actors, workflows, cryptography, jobs, and conversation (LLM) — are modelled as scala.caps.Capability values that the compiler tracks. User code compiles under import language.experimental.safe, so the compiler statically guarantees that a Dapr resource can never escape the scope that owns it. The Dapr SDKs (Java SDK on the JVM, @dapr/dapr on Scala.js) are hidden entirely; users see only Scala types.

Requirements

  • Scala 3.10.0-RC1-…-NIGHTLY (capture checking / safe mode; exact version pinned in project.scala)
  • scala-cli >= 1.13.0 (older versions cannot build the Scala.js platform; >= 1.14 to run the Scala.js integration harness, scripts/test-js-integration.sh)
  • JVM 25 (for the JVM platform)
  • For Scala.js builds: npm ci + scripts/generate-st-facades.sh (once per machine — see below); Node 25+ to run capability-touching code
  • Docker (only for the integration tests, which exercise a real daprd sidecar + Redis)

Build & test

Sources live in src/{shared,jvm,js} and test/{shared,jvm,js} (platform-specific files also carry a per-file //> using target.platform directive). Platform-specific dependencies live in jvm-deps.scala / jvm-test-deps.test.scala / js-deps.scala, each scoped by its own target.platform directive — so plain --js invocations just work, with no --exclude flags for dependency scoping.

scala-cli compile .                                       # JVM
scala-cli test . --test-only 'dapr4s.test.unit.*'         # JVM unit tests
scala-cli test . --test-only 'dapr4s.test.integration.*'  # JVM integration tests (needs Docker)

scripts/generate-st-facades.sh                            # once per machine, before any --js build
scala-cli compile --js .                                  # Scala.js
scala-cli test --js . --exclude test/js/integration --test-only 'dapr4s.test.unit.*'   # Scala.js unit tests
PATH=<node25-bin>:$PATH scripts/test-js-integration.sh    # Scala.js integration tests (Docker + Node 25)

The one remaining --exclude (of test/js/integration) exists only because those Wasm-only suites use orphan js.await, which wedges the plain-JS linker; the integration script runs them on the Wasm backend instead, against a real daprd 1.17 + Redis environment.

Usage

//> using dep "com.github.sideeffffect::dapr4s::<version>"

(The :: before the version resolves the right platform artifact — dapr4s_3 on the JVM, dapr4s_sjs1_3 on Scala.js.)

import dapr4s.*

DaprCapability.state(StateStoreName("statestore")):   // StateCapability^{cap} in scope
  StateCapability.save(key, value)
// Using StateCapability here — outside the block — is a compile error.

Platforms

The public API is identical on the JVM and on Scala.js — synchronous, direct style on both. On the JVM, blocking calls park virtual threads; on Scala.js, the same calls suspend the WebAssembly stack via JSPI (JavaScript Promise Integration) while the Node event loop keeps running.

Scala.js supports the full capability matrix — state, pub/sub, invocation, bindings, secrets, configuration, locks, crypto, actors, workflows, and serve() with full app-channel parity (subscriptions, invoke routes, input bindings, job routes, actor hosting, workflow hosting) — except jobs and conversation, which the Dapr JS SDK has no API for. On Scala.js those two methods simply don't exist at compile time (they live on a JVM-only platform trait), so using them is a compile error, not a runtime exception — use the JVM platform for those.

JS consumers of capabilities must link with the experimental WebAssembly backend and run on Node 25+ (or Node 23/24 with --experimental-wasm-jspi); the pure parts of dapr4s (models, codecs, derivation) also link on the plain JS backend:

//> using platform "scala-js"
//> using jsEmitWasm true
//> using jsModuleKind "es"
//> using jsEsVersionStr "es2017"
//> using dep "com.github.sideeffffect::dapr4s::<version>"

Run npm install @dapr/dapr so the SDK is resolvable from the directory Node executes in, then enter js.async { ... } once at the program edge (or use the JS-only runAsync/serveAsync, which wrap it for you):

import dapr4s.*
import scala.scalajs.js

// one-shot request/response, with the single js.async entry at the program edge:
def main(args: Array[String]): Unit =
  js.async {
    Dapr().run:
      summon[DaprCapability].state(StateStoreName("statestore")).get(StateStoreKey("k"))
  }: Unit

Scala.js facades: embedded — consumers need only Maven Central

The dapr4s_sjs1_3 artifact is self-contained: the ScalablyTyped-generated facades of @dapr/dapr/express/Node that the JS interop layer is written against ship inside the dapr4s jar (under the dapr4s-specific dapr4styped.* package, so they can never collide with a typings.* generation of your own), and the POM references only Maven-Central artifacts. Using dapr4s from Scala.js is therefore an ordinary dependency — no converter, no local ivy repository, nothing beyond the using dep above plus npm install @dapr/dapr.

Building dapr4s itself (this repository) is different: the facades are compile-only dependencies resolved from ~/.ivy2/local, so run npm ci followed by scripts/generate-st-facades.sh once per machine before the first scala-cli compile --js .. The facade digests are deterministic in (package-lock.json, converter version, converter flags), the script is idempotent and skips instantly when the jars already exist, and at publish time scripts/embed-st-facades.sh packs the generated classes into the jar.

See DESIGN.md for the architecture, the two-layer (safe / @assumeSafe shell) model, and the Scala.js platform details, and dapr4s-examples for runnable examples.

Sponsors

This work has been sponsored by Chili Piper.

License

Apache-2.0

About

Scala 3 library exposing Dapr building blocks as capture-checked capabilities

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.