diff --git a/examples/README.md b/examples/README.md
index afb9bb9..070a90c 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -3,8 +3,9 @@
* [About the examples](#about-the-examples)
* [Running the examples](#running-the-examples)
* [Prerequisites](#prerequisites)
- * [Java HTTP Server](#java-http-server)
+ * [Spring](#spring)
* [Ktor](#ktor)
+ * [Java HTTP Server](#java-http-server)
## About the examples
@@ -20,21 +21,30 @@ All are a simple counter implemented using Datastar server-sent events.
To make the examples work as simply as possible, each back implementation is a JBang script.
-JBang is a tool that allows to run Kotlin scripts taking care of all the dependencies without the need to use more heavy weight tools like Maven or Gradle.
+JBang is a tool that allows to run Kotlin scripts taking care of all the dependencies without the need to use more heavyweight tools like Maven or Gradle.
You can find the installation instructions on the [official documentation](https://www.jbang.dev/documentation/jbang/latest/installation.html).
-### Java HTTP Server
+### Spring
-This example uses the plain Java `HttpServer` to serve the front end. ([code](java-httpserver/server.kt))
+This example uses `Spring` to serve the front end. ([code](spring/server.kt))
```shell
-cd ./java-httpserver ; jbang server.kt ; cd ..
+cd ./spring ; jbang server.kt ; cd ..
```
### Ktor
-This example uses the `Ktor` to serve the front end. ([code](ktor/server.kt))
+This example uses `Ktor` to serve the front end. ([code](ktor/server.kt))
```shell
cd ./ktor ; jbang server.kt ; cd ..
```
+
+### Java HTTP Server
+
+This example uses the plain Java `HttpServer` to serve the front end. ([code](java-httpserver/server.kt))
+
+```shell
+cd ./java-httpserver ; jbang server.kt ; cd ..
+```
+
diff --git a/examples/spring/server.kt b/examples/spring/server.kt
new file mode 100644
index 0000000..77e6f8c
--- /dev/null
+++ b/examples/spring/server.kt
@@ -0,0 +1,91 @@
+import dev.datastar.kotlin.sdk.Response
+import dev.datastar.kotlin.sdk.ServerSentEventGenerator
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.runBlocking
+import org.springframework.boot.SpringApplication
+import org.springframework.boot.SpringBootConfiguration
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration
+import org.springframework.context.annotation.Import
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PostMapping
+import org.springframework.web.bind.annotation.ResponseStatus
+import org.springframework.web.bind.annotation.RestController
+import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody
+import java.io.File
+import java.io.OutputStream
+import java.io.OutputStreamWriter
+
+///usr/bin/env jbang "$0" "$@" ; exit $?
+//JAVA 21
+//KOTLIN 2.2.0
+//DEPS dev.data-star.kotlin:kotlin-sdk:1.0.0-RC1
+//DEPS org.springframework.boot:spring-boot-starter-web:3.5.5
+//DEPS org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2
+
+fun main() {
+ SpringApplication.run(CounterApp::class.java)
+}
+
+@SpringBootConfiguration
+@EnableAutoConfiguration
+@Import(CounterController::class)
+open class CounterApp
+
+@RestController
+class CounterController {
+
+ private val counter = MutableStateFlow(0)
+
+ @GetMapping("/", produces = [MediaType.TEXT_HTML_VALUE])
+ @ResponseStatus(HttpStatus.OK)
+ fun index() = StreamingResponseBody { stream ->
+ File("../front/counter.html").inputStream().use { inputStream ->
+ inputStream.transferTo(stream)
+ }
+ }
+
+ @GetMapping("/counter", produces = [MediaType.TEXT_EVENT_STREAM_VALUE])
+ @ResponseStatus(HttpStatus.OK)
+ fun counter() = StreamingResponseBody { stream ->
+ runBlocking {
+ val response = adapterResponse(stream)
+ val generator = ServerSentEventGenerator(response)
+ counter.collect { event ->
+ generator.patchElements("""${event}""")
+
+ if (event == 3) {
+ generator.executeScript("""alert('Thanks for trying Datastar!')""")
+ }
+ }
+ }
+ }
+
+
+ @PostMapping("/increment")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ fun increment() {
+ counter.value++
+ }
+
+ @PostMapping("/decrement")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ fun decrement() {
+ counter.value--
+ }
+
+ private fun adapterResponse(stream: OutputStream): Response = object : Response {
+ private val writer = OutputStreamWriter(stream)
+
+ override fun sendConnectionHeaders(
+ status: Int,
+ headers: Map>
+ ) = Unit
+
+ override fun write(text: String) = writer.write(text)
+
+ override fun flush() = writer.flush()
+
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 96de832..c808008 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -2,6 +2,6 @@ plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}
-rootProject.name = "datastar-kotlin-sdk"
+rootProject.name = "datastar-kotlin"
include("sdk")