Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
226d3f6
build: cross-platform plumbing for Scala.js
sideeffffect Jun 10, 2026
e0c3fdb
feat: Scala.js client-side internal layer over the Dapr JS SDK
sideeffffect Jun 11, 2026
f69025b
feat: Scala.js serve() — express-based DaprAppServer twin
sideeffffect Jun 11, 2026
582c07b
feat: Scala.js workflow hosting — AsyncGenerator coroutine bridge
sideeffffect Jun 11, 2026
256b707
docs+ci: cross-platform documentation, test-js job, dual publish
sideeffffect Jun 11, 2026
5c544c9
fix: apply adversarial-review findings to the Scala.js layer
sideeffffect Jun 11, 2026
ec89910
refactor!: shared/jvm/js source layout, platform traits, scoped deps …
sideeffffect Jun 11, 2026
99e7b81
feat!: ScalablyTyped-generated facades replace the hand-written ones
sideeffffect Jun 11, 2026
ca8c62d
test: real Scala.js integration tests on Wasm+JSPI against a live sid…
sideeffffect Jun 12, 2026
cd60afd
ci+docs: platform matrix, review fixes, documentation for the rework
sideeffffect Jun 12, 2026
d39e343
refactor: self-contained _sjs1_3 artifact + JVM/JS coverage parity
sideeffffect Jun 12, 2026
899f708
fix(js): re-add ScalablyTyped facade jars to the package link classpath
sideeffffect Jun 12, 2026
e226231
fix(js): also add facade jars to the Wasm `test` link, not just `pack…
sideeffffect Jun 12, 2026
0ad84d0
test(it): unify Dapr component config into one shared set (JS side)
sideeffffect Jun 12, 2026
458ea7d
test(it): shared scenarios + redis for direct-call capabilities
sideeffffect Jun 12, 2026
0875bcd
test(it): unify invoke into shared scenarios + close the JS error-pat…
sideeffffect Jun 12, 2026
4e4b498
Merge remote-tracking branch 'origin/master' into feat/scala-js-cross…
sideeffffect Jun 12, 2026
3c23c86
test(it): redis everywhere — convert remaining server-delivery suites
sideeffffect Jun 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 91 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,54 +30,125 @@ jobs:
exit 1
fi

# One matrix leg per platform. Adding Scala Native one day should be a new include
# entry (platform: native, platform-flags: '--native', ...), not a new job.
#
# Platform-specific dependencies need no flags here: jvm-deps.scala /
# jvm-test-deps.test.scala / js-deps.scala scope their `using dep` directives via
# `//> using target.platform`, so `scala-cli ... --js .` simply never resolves the
# Dapr Java SDK or testcontainers, and JVM invocations never resolve the
# ScalablyTyped facades.
test:
strategy:
fail-fast: false
matrix:
include:
- platform: jvm
platform-flags: ''
# Integration suite: a real daprd sidecar (and Redis) per test via
# testcontainers-dapr; Docker is preinstalled on ubuntu-latest.
unit-test-args: ''
integration-command: scala-cli test . --test-only 'dapr4s.test.integration.*'
- platform: js
platform-flags: '--js'
# The Wasm-only integration suites use orphan js.await, which the plain-JS
# linker cannot handle (it wedges instead of erroring) — exclude them from
# the plain-backend unit-test leg; the integration command runs them on the
# Wasm backend instead.
unit-test-args: --exclude test/js/integration
# Brings up redis + placement + scheduler + daprd + the Wasm-packaged test
# server, runs the munit suites on Wasm+JSPI (Node 25), tears down.
integration-command: scripts/test-js-integration.sh
name: test (${{ matrix.platform }})
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: coursier/cache-action@v8
- uses: coursier/setup-action@v1
if: matrix.platform == 'js'
- uses: VirtusLab/scala-cli-setup@v1
with:
power: true
- name: Compile
run: scala-cli compile .
- name: Unit tests
run: scala-cli test . --test-only 'dapr4s.test.unit.*'

integration-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# JSPI is on by default from Node 25; the runner's default Node has no JSPI and
# scala-cli's runner passes no V8 flags, so the Wasm integration tests need this.
- name: Set up Node 25
if: matrix.platform == 'js'
uses: actions/setup-node@v4
with:
fetch-depth: 0
- uses: coursier/cache-action@v8
- uses: VirtusLab/scala-cli-setup@v1
node-version: 25
- name: Install npm dependencies (@dapr/dapr)
if: matrix.platform == 'js'
run: npm ci
# The ScalablyTyped-generated facades (js-deps.scala) live in ~/.ivy2/local; the
# generation script no-ops when the pinned digests are already there. Keep the
# cache key in sync with the converter version + flags in the script.
- name: Cache ScalablyTyped facades
if: matrix.platform == 'js'
uses: actions/cache@v4
with:
power: true
# The integration suite spins up a real daprd sidecar (and Redis) per test via
# testcontainers-dapr; Docker is preinstalled on ubuntu-latest. These are the
# round-trip publish/subscribe + service-invocation tests — the coverage that
# would have caught the JSON double-encoding regression that compile-only CI missed.
path: |
~/.ivy2/local/org.scalablytyped
~/.cache/scalablytyped
key: scalablytyped-${{ hashFiles('package-lock.json', 'scripts/generate-st-facades.sh') }}
- name: Generate ScalablyTyped facades
if: matrix.platform == 'js'
run: scripts/generate-st-facades.sh
- name: Compile
run: scala-cli compile ${{ matrix.platform-flags }} .
- name: Unit tests
run: scala-cli test ${{ matrix.platform-flags }} . ${{ matrix.unit-test-args }} --test-only 'dapr4s.test.unit.*'
- name: Integration tests
run: scala-cli test . --test-only 'dapr4s.test.integration.*'
run: ${{ matrix.integration-command }}

publish:
needs: [format, test, integration-test]
needs: [format, test]
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: coursier/cache-action@v8
- uses: coursier/setup-action@v1
- uses: VirtusLab/scala-cli-setup@v1
with:
power: true
- name: Publish
# The Scala.js publish compiles against the ScalablyTyped facade deps
# (compileOnly in js-deps.scala), so the artifacts must exist in ~/.ivy2/local
# here too — generation is a BUILD-time requirement only; consumers of the
# published artifact never need it (see the embed step below).
- name: Install npm dependencies (@dapr/dapr)
run: npm ci
- name: Cache ScalablyTyped facades
uses: actions/cache@v4
with:
path: |
~/.ivy2/local/org.scalablytyped
~/.cache/scalablytyped
key: scalablytyped-${{ hashFiles('package-lock.json', 'scripts/generate-st-facades.sh') }}
- name: Generate ScalablyTyped facades
run: scripts/generate-st-facades.sh
- name: Publish (JVM)
run: scala-cli publish .
env:
PUBLISH_USER: ${{ secrets.PUBLISH_USER }}
PUBLISH_PASSWORD: ${{ secrets.PUBLISH_PASSWORD }}
PUBLISH_SECRET_KEY: ${{ secrets.PUBLISH_SECRET_KEY }}
PUBLISH_SECRET_KEY_PASSWORD: ${{ secrets.PUBLISH_SECRET_KEY_PASSWORD }}
# Publishes a SELF-CONTAINED dapr4s_sjs1_3: the ScalablyTyped facade classes
# (renamed to the dapr4styped.* package) are embedded into the jar via
# --resource-dirs, and the facade deps are compileOnly so the POM references
# Maven-Central artifacts only — downstream Scala.js users resolve dapr4s like
# any ordinary dependency, no generation step; see js-deps.scala and
# scripts/embed-st-facades.sh.
- name: Stage ScalablyTyped facade classes for embedding
run: scripts/embed-st-facades.sh
- name: Publish (Scala.js)
run: scala-cli publish --js . --resource-dirs .scala-build/st-embed
env:
PUBLISH_USER: ${{ secrets.PUBLISH_USER }}
PUBLISH_PASSWORD: ${{ secrets.PUBLISH_PASSWORD }}
PUBLISH_SECRET_KEY: ${{ secrets.PUBLISH_SECRET_KEY }}
PUBLISH_SECRET_KEY_PASSWORD: ${{ secrets.PUBLISH_SECRET_KEY_PASSWORD }}
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
.claude

node_modules/
# Scratch tree of the ScalablyTyped converter (scripts/generate-st-facades.sh); the script
# removes it after every run, ignored here as a second line of defence — scala-cli would
# otherwise compile it as project sources.
out/
31 changes: 18 additions & 13 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@ trailingCommas = always
# Files using experimental capture-checking `^{...}` return-type annotations in a
# position scalafmt's parser cannot yet handle are excluded until scalafmt gains
# nightly-Scala CC syntax support. (Files that merely *use* `^{...}` but still parse
# — e.g. src/derivation/WorkflowEvents.scala, test/unit/CCTest.scala — stay checked.)
# — e.g. src/shared/derivation/WorkflowEvents.scala, test/shared/unit/CCTest.scala — stay checked.)
project.excludeFilters = [
"src/Capabilities\\.scala",
"src/DaprCapability\\.scala",
"src/Workflows\\.scala",
"src/derivation/Forwarders\\.scala",
"src/derivation/WorkflowActivityCalls\\.scala",
"src/internal/ConfigurationCapabilityImpl\\.scala",
"src/internal/DaprCapabilityImpl\\.scala",
"src/internal/WorkflowContextImpl\\.scala",
"test/integration/apps/WorkflowApp\\.scala",
"test/unit/CapabilityDerivationFixtures\\.scala",
"test/unit/WorkflowActivityDerivationFixtures\\.scala",
"test/unit/WorkflowEventsTest\\.scala"
"src/shared/Capabilities\\.scala",
"src/shared/DaprCapability\\.scala",
"src/shared/Workflows\\.scala",
"src/shared/derivation/Forwarders\\.scala",
"src/shared/derivation/WorkflowActivityCalls\\.scala",
"src/jvm/DaprCapabilityPlatform\\.scala",
"src/jvm/internal/ConfigurationCapabilityImpl\\.scala",
"src/jvm/internal/DaprCapabilityImpl\\.scala",
"src/jvm/internal/WorkflowContextImpl\\.scala",
"src/js/internal/ConfigurationCapabilityImpl\\.scala",
"src/js/internal/DaprAppServer\\.scala",
"src/js/internal/DaprCapabilityImpl\\.scala",
"src/js/internal/WorkflowContextImpl\\.scala",
"test/shared/apps/WorkflowApp\\.scala",
"test/shared/unit/CapabilityDerivationFixtures\\.scala",
"test/shared/unit/WorkflowActivityDerivationFixtures\\.scala",
"test/shared/unit/WorkflowEventsTest\\.scala"
]
Loading
Loading