diff --git a/.github/workflows/release-sdk.yml b/.github/workflows/release-sdk.yml index 0eb8f3b..af0844d 100644 --- a/.github/workflows/release-sdk.yml +++ b/.github/workflows/release-sdk.yml @@ -59,40 +59,54 @@ jobs: run: bb test:bb - name: Build jar artifacts - run: bb jar:all + run: bb install:all - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2 with: name: sdk.jar - path: sdk/target/*.jar + path: libraries/sdk/target/*.jar + if-no-files-found: error + compression-level: 0 + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2 + with: + name: brotli.jar + path: libraries/sdk-brotli/target/*.jar if-no-files-found: error compression-level: 0 - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2 with: name: adapter-http-kit.jar - path: sdk-adapter-http-kit/target/*.jar + path: libraries/sdk-http-kit/target/*.jar if-no-files-found: error compression-level: 0 - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2 with: - name: adapter-ring.jar - path: sdk-adapter-ring/target/*.jar + name: adapter-http-kit-malli-schemas.jar + path: libraries/sdk-http-kit-malli-schemas/target/*.jar if-no-files-found: error compression-level: 0 - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2 with: name: malli-schemas.jar - path: sdk-malli-schemas/target/*.jar + path: libraries/sdk-malli-schemas/target/*.jar if-no-files-found: error compression-level: 0 - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2 with: - name: brotli.jar - path: sdk-brotli/target/*.jar + name: adapter-ring.jar + path: libraries/sdk-ring/target/*.jar + if-no-files-found: error + compression-level: 0 + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # tag: v4.6.2 + with: + name: adapter-ring-malli-schemas.jar + path: libraries/sdk-ring-malli-schemas/target/*.jar if-no-files-found: error compression-level: 0 diff --git a/.gitignore b/.gitignore index 4824193..884a944 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ test-resources/test.config.edn /.nfnl.fnl /.nvim.fnl /.nvim.lua + +.cljdoc-preview +.lazy.fnl +.lazy.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e82851..c965645 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Release notes for the Clojure SDK +## 2025-09-14 - RC2 + +This release is mostly centered around documentation and cljdoc compatibility. + +### Changes + +- Several dependencies have been updated +- Libraries interdependencies are now explicit in their `deps.edn` +- Malli schemas are now split into 3 libraries. This comes from the need to be + cljdoc compatible + +### Added + +- New articles have been added to the `doc` directory +- Several docstrings have been added / updated +- There are new babashka tasks to help running a local cljdoc instance and + ingesting the docs locally +- The build process updates libraries interdependencies versions automatically +- A warning about which Http-kit version to use has been added in the proper + README + +### Fixed + +- cljdoc ingestion + ## 2025-06-22 ### Changed @@ -19,7 +44,7 @@ ### Fixed -- A superflous newline character was send when marking the end of a SSE event +- A superfluous newline character was send when marking the end of a SSE event - The clj-kondo config file for the SDK has been moved in a `clj-kondo.exports/starfederation.datastar.clojure/sdk` directory. This change allows for other projects to use diff --git a/README.md b/README.md index e8b56f1..162c97f 100644 --- a/README.md +++ b/README.md @@ -12,30 +12,30 @@ We provide several libraries for working with [Datastar](https://data-star.dev/) There currently are adapter implementations for: -- [ring](https://github.com/ring-clojure/ring) +- [ring compliant adapters](https://github.com/ring-clojure/ring) - [http-kit](https://github.com/http-kit/http-kit) If you want to roll your own adapter implementation, see [implementing-adapters](/doc/implementing-adapters.md). -## Installation +## Library coordinates -To your `deps.edn` file you can add the following coordinates: -| library | deps coordinate | -| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| library | deps coordinate | +| ------------- | ----------------------------------------------------| | SDK | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/sdk.svg)](https://clojars.org/dev.data-star.clojure/sdk) | | http-kit | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/http-kit.svg)](https://clojars.org/dev.data-star.clojure/http-kit) | | ring | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/ring.svg)](https://clojars.org/dev.data-star.clojure/ring) | | brotli | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/brotli.svg)](https://clojars.org/dev.data-star.clojure/brotli) | -| malli-schemas | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/malli-schemas.svg)](https://clojars.org/dev.data-star.clojure/malli-schemas) | +| Core SDK malli schemas | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/malli-schemas.svg)](https://clojars.org/dev.data-star.clojure/malli-schemas) | +| Http-kit malli schemas | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/http-kit-malli-schemas.svg)](https://clojars.org/dev.data-star.clojure/http-kit-malli-schemas) | +| Ring malli schemas | [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/ring-malli-schemas.svg)](https://clojars.org/dev.data-star.clojure/ring-malli-schemas) | -Notes: - -- You need the SDK and either the http-kit or the ring library to get started. +- To get started you'll need either the http-kit library or the ring one. +- Other libraries are optional - The ring library works with ring compliant adapters (adapter using the `ring.core.protocols/StreamableResponseBody`) -- Currently the brotli library works only with http-kit +- Currently the Brotli library works only with http-kit ## Usage @@ -96,9 +96,6 @@ it somewhere and use it later: ``` -Check the docstrings in the `starfederation.datastar.clojure.api` namespace for -more details. - ### Advanced features This SDK is essentially a tool to manage SSE connections with helpers to format @@ -118,40 +115,6 @@ You can find more information in several places: lists the conventions by which SDK adapters are implemented if the need to implement your own ever arises. -## Adapter behaviors: - -Ring adapters are not made equals. This leads to our SSE generators not having -the exact same behaviors in some cases. - -### SSE connection lifetime in ring when trying to store the sse-gen somewhere - -#### With ring sync - -| Adapter | | -| -------- | ---------------------------------------------------------------------- | -| ring | same as the thread creating the sse response | -| http-kit | alive until the client or the server explicitely closes the connection | - -You may keep the connection open in ring sync mode by somehow blocking the thread -handling the request. This is a valid strategy when using java's virtual threads. - -#### With ring async - -| Adapter | | -| ------------ | ---------------------------------------------------------------------- | -| all adapters | alive until the client or the server explicitely closes the connection | - -### Detecting a closed connection - -| Adapter | | -| -------- | ----------------------------------------------------------------------------------------------- | -| ring | Sending events on a closed connection will fail at some point and the sse-gen will close itself | -| http-kit | Http-kit detects closed connections by itself and closes the sse-gen | - -At this moment, when using the ring adapter and jetty, our SSE generators need -to send 2 small events or 1 big event to detect a closed connection. -There must be some buffering happening independent of our implementation. - ## TODO: - Streamlined release process (cutting releases and publish jar to a maven repo) diff --git a/bb.edn b/bb.edn index 018a466..205f3f1 100644 --- a/bb.edn +++ b/bb.edn @@ -1,16 +1,23 @@ {:paths ["src/bb" - "sdk/src/main" - "sdk-adapter-http-kit/src/main/" - "sdk-malli-schemas/src/main" + "libraries/sdk/src/main" + "libraries/sdk-http-kit/src/main/" + "libraries/sdk-http-kit-malli-schemas/src/main" + "libraries/sdk-malli-schemas/src/main" "./src/test/core-sdk" "./src/test/malli-schemas"] - :deps {io.github.noahtheduke/lazytest {:mvn/version "1.8.0"} - metosin/malli {:mvn/version "0.17.0"}} + :deps {borkdude/rewrite-edn {:mvn/version "0.4.9"} + io.github.noahtheduke/lazytest {:mvn/version "1.8.0"} + metosin/malli {:mvn/version "0.19.1"}} :tasks - {:requires ([tasks :as t]) + {:requires ([tasks :as t] + [tasks.build :as build] + [tasks.cljdoc :as cljdoc]) + ;; --------------------------------------------------------------------------- + ;; Dev tasks + ;; --------------------------------------------------------------------------- dev {:doc "Starts a dev repl. Additional deps aliases can be passed as arguments." :task (t/dev :http-kit :ring-jetty :malli-schemas)} @@ -22,11 +29,14 @@ dev:empty {:doc "Dev repl with no adapters." :task (t/dev :malli-schemas)} - + dev:bb {:doc "Start a babashka nrepl server. An addr like `localhost:1234` can be passed as argument." :task (t/dev-bb)} + ;; --------------------------------------------------------------------------- + ;; Test Tasks + ;; --------------------------------------------------------------------------- test:all {:doc "Run all tests once." :task (t/lazytest [:http-kit @@ -67,31 +77,37 @@ {:doc "Run core unit tests with babashka." :task (t/bb-lazytest [:test.paths/core-sdk :test.paths/malli-schemas])} - + test:sdk-common {:doc "Run the server used for the SDKs' common tests." :task (t/start-test-server)} + test:sdk-common-go + {:doc "Run the server used for the SDKs' common tests." + :task (t/run-go-tests)} + ;; --------------------------------------------------------------------------- + ;; Build tasks + ;; --------------------------------------------------------------------------- jar:sdk {:doc "Build jar for the common sdk" - :task (t/lib-jar! t/sdk-dir)} + :task (build/lib-jar! build/sdk-dir)} jar:sdk-adapter-ring {:doc "Build jar for the adapter-ring" - :task (t/lib-jar! t/sdk-adapter-ring-dir)} + :task (build/lib-jar! build/sdk-adapter-ring-dir)} jar:sdk-adapter-http-kit {:doc "Build jar for the adapter-http-kit" - :task (t/lib-jar! t/sdk-adapter-http-kit-dir)} + :task (build/lib-jar! build/sdk-adapter-http-kit-dir)} jar:sdk-brotli {:doc "Build jar for the Brotli library" - :task (t/lib-jar! t/sdk-brotli-dir)} + :task (build/lib-jar! build/sdk-brotli-dir)} jar:sdk-malli-schemas {:doc "Build jar for the malli-schemas" - :task (t/lib-jar! t/sdk-malli-schemas-dir)} + :task (build/lib-jar! build/sdk-malli-schemas-dir)} jar:all {:doc "Build the jar for all the libs" @@ -102,30 +118,54 @@ jar:sdk-brotli jar:sdk-malli-schemas]} + install:clean + {:doc "Deletes all datastar libs from the local maven repository." + :task (build/clean-maven-dir!)} + + install:all - {:doc "Install all libraries" + {:doc "Install all libraries locally." :depends [clean] - :task (doseq [dir t/sdk-lib-dirs] - (t/lib-install! dir))} + :task (doseq [dir build/sdk-lib-dirs] + (build/lib-install! dir))} clean - {:doc "Clean build artifacts" - :task (doseq [dir t/sdk-lib-dirs] + {:doc "Clean build artifacts in each library directory." + :task (doseq [dir build/sdk-lib-dirs] + (println "----------------") + (println "Cleaning: " dir) + (println "----------------") (clojure {:dir dir} "-T:build clean"))} set-version {:doc "Set the version in all libs" - :task (doseq [dir t/sdk-lib-dirs] - (t/lib-set-version! dir (first *command-line-args*)))} + :task (doseq [dir build/sdk-lib-dirs] + (build/lib-set-version! dir (first *command-line-args*)))} bump-version {:doc "Bump the version component in all libs. First argument must be one of: major, minor, patch" - :task (doseq [dir sdk-lib-dirs] + :task (doseq [dir build/sdk-lib-dirs] (let [component (first *command-line-args*)] - (t/lib-bump! dir component)))} + (build/lib-bump! dir component)))} publish:all {:doc "Publish the clojure sdk libs to clojars" :depends [jar:all] - :task (doseq [dir t/sdk-lib-dirs] - (t/lib-publish! dir))}}} + :task (doseq [dir build/sdk-lib-dirs] + (build/lib-publish! dir))} + + ;; --------------------------------------------------------------------------- + ;; Cljdoc tasks + ;; --------------------------------------------------------------------------- + cljdoc:clean + {:doc "Clean local cljdoc data." + :task (cljdoc/clean!)} + + cljdoc:server + {:doc "Start a local cljdoc server." + :task (cljdoc/start-server!)} + + cljdoc:ingest + {:doc "Tell local cljdoc server to ingest a library. Needs a argument (:sdk, :http-kit, :ring, ...)" + :task (cljdoc/ingest! (first *command-line-args*))}}} + diff --git a/deps.edn b/deps.edn index da7811d..da79592 100644 --- a/deps.edn +++ b/deps.edn @@ -1,31 +1,31 @@ {:paths [] - :deps {sdk/sdk {:local/root "./sdk"} - io.github.tonsky/clojure-plus {:mvn/version "1.6.1"} - io.github.paintparty/fireworks {:mvn/version "0.10.4"} + :deps {sdk/sdk {:local/root "./libraries/sdk/"} + io.github.tonsky/clojure-plus {:mvn/version "1.6.3"} + io.github.paintparty/fireworks {:mvn/version "0.12.6"} mvxcvi/puget {:mvn/version "1.3.4"} - com.taoensso/telemere {:mvn/version "1.0.0-RC3"} - io.github.clojure/tools.build {:git/tag "v0.10.9" - :git/sha "e405aac"}} + com.taoensso/telemere {:mvn/version "1.1.0"} + io.github.clojure/tools.build {:git/tag "v0.10.10" + :git/sha "deedd62"}} :aliases {:repl {:extra-paths ["src/dev"] - :extra-deps {org.clojure/clojure {:mvn/version "1.12.0"} - nrepl/nrepl {:mvn/version "1.3.0"} - cider/cider-nrepl {:mvn/version "0.50.2"} - io.github.tonsky/clj-reload {:mvn/version "0.7.1"} + :extra-deps {org.clojure/clojure {:mvn/version "1.12.2"} + nrepl/nrepl {:mvn/version "1.4.0"} + cider/cider-nrepl {:mvn/version "0.57.0"} + io.github.tonsky/clj-reload {:mvn/version "0.9.8"} dom-top/dom-top {:mvn/version "1.0.9"}}} :debug {:classpath-overrides {org.clojure/clojure nil} - :extra-deps {com.github.flow-storm/clojure {:mvn/version "1.12.0-4"} - com.github.flow-storm/flow-storm-dbg {:mvn/version "4.2.0"} - com.github.flow-storm/flow-storm-web-plugin {:mvn/version "1.0.0-beta"}} + :extra-deps {com.github.flow-storm/clojure {:mvn/version "1.12.2"} + com.github.flow-storm/flow-storm-dbg {:mvn/version "4.5.5"} + com.github.flow-storm/flow-storm-web-plugin {:mvn/version "1.0.2"}} :jvm-opts ["-Dclojure.storm.instrumentEnable=true" "-Dflowstorm.plugins.namespaces=flow-storm.plugins.web.all" "-Dclojure.storm.instrumentOnlyPrefixes=test.,reitit.,examples.,starfederation.,ring.adapter.jetty,org.httpkit.server"]} - + :test {:extra-paths ["test-resources/" :test.paths/core-sdk :test.paths/malli-schemas @@ -37,37 +37,52 @@ :test.paths/adapter-rj9a] - :extra-deps {io.github.noahtheduke/lazytest {:mvn/version "1.5.0"} - metosin/reitit {:mvn/version "0.7.2"} - etaoin/etaoin {:mvn/version "1.1.42"} - com.cnuernber/charred {:mvn/version "1.034"} - dev.onionpancakes/chassis {:mvn/version "1.0.365"}}} + :extra-deps {com.cnuernber/charred {:mvn/version "1.037"} + dev.onionpancakes/chassis {:mvn/version "1.0.365"} + etaoin/etaoin {:mvn/version "1.1.43"} + io.github.noahtheduke/lazytest {:mvn/version "1.8.0"} + metosin/reitit {:mvn/version "0.9.1"} + nubank/matcher-combinators {:mvn/version "3.9.2"}}} ;; Adapters aliases - :http-kit {:extra-deps {sdk/adapter-http-kit {:local/root "./sdk-adapter-http-kit"}}} + :http-kit {:extra-deps {sdk/adapter-http-kit {:local/root "./libraries/sdk-http-kit/" + :exclusions [dev.data-star.clojure/sdk]}}} - :ring-jetty {:extra-deps {sdk/adapter-ring {:local/root "./sdk-adapter-ring"} - ring/ring-jetty-adapter {:mvn/version "1.14.1"}}} - - :ring-rj9a {:extra-deps {sdk/adapter-ring {:local/root "./sdk-adapter-ring"} - info.sunng/ring-jetty9-adapter {:mvn/version "0.36.1"}}} + :ring-jetty {:extra-deps {sdk/adapter-ring {:local/root "./libraries/sdk-ring/" + :exclusions [dev.data-star.clojure/sdk]} + ring/ring-jetty-adapter {:mvn/version "1.15.0"}}} + + :ring-rj9a {:extra-deps {sdk/adapter-ring {:local/root "./libraries/sdk-ring/" + :exclusions [dev.data-star.clojure/sdk]} + info.sunng/ring-jetty9-adapter {:mvn/version "0.38.0"}}} ;; Optional libs aliases - :malli-schemas {:extra-deps {sdk/malli {:local/root "./sdk-malli-schemas"}}} + :malli-schemas {:extra-deps {sdk/malli {:local/root "./libraries/sdk-malli-schemas/" + :exclusions [dev.data-star.clojure/sdk]} + sdk/http-malli {:local/root "./libraries/sdk-http-kit-malli-schemas/" + :exclusions [dev.data-star.clojure/sdk + dev.data-star.clojure/http-kit + dev.data-star.clojure/malli-schemas]} + sdk/http-ring {:local/root "./libraries/sdk-ring-malli-schemas/" + :exclusions [dev.data-star.clojure/sdk + dev.data-star.clojure/ring + dev.data-star.clojure/malli-schemas]}}} + + :sdk-brotli {:extra-deps {sdk/brotli {:local/root "./libraries/sdk-brotli" + :exclusions [dev.data-star.clojure/sdk]} + com.aayushatharva.brotli4j/native-linux-x86_64 {:mvn/version "1.20.0"}}} - :sdk-brotli {:extra-deps {sdk/brotli {:local/root "./sdk-brotli"} - com.aayushatharva.brotli4j/native-linux-x86_64 {:mvn/version "1.18.0"}}} - - - :test.paths/core-sdk ["src/test/core-sdk"] - :test.paths/brotli ["src/test/brotli"] + + :test.paths/core-sdk ["./libraries/sdk/src/main/" "src/test/core-sdk"] + :test.paths/brotli ["./libraries/sdk-brotli/src/main/" "src/test/brotli"] :test.paths/malli-schemas ["src/test/malli-schemas"] :test.paths/adapter-common ["src/test/adapter-common"] - :test.paths/adapter-ring ["src/test/adapter-ring"] - :test.paths/adapter-ring-jetty ["src/test/adapter-ring-jetty"] - :test.paths/adapter-rj9a ["src/test/adapter-rj9a"] - :test.paths/adapter-http-kit ["src/test/adapter-http-kit"] + :test.paths/adapter-ring ["./libraries/sdk-ring/src/main/" "src/test/adapter-ring"] + :test.paths/adapter-ring-jetty ["./libraries/sdk-ring/src/main/" "src/test/adapter-ring-jetty"] + :test.paths/adapter-rj9a ["./libraries/sdk-ring/src/main/" "src/test/adapter-rj9a"] + :test.paths/adapter-http-kit ["./libraries/sdk-http-kit/src/main/" "src/test/adapter-http-kit"] + :neil {:project {:url "https://github.com/starfederation/datastar-clojure" :scm [:scm [:url "https://github.com/"] diff --git a/doc/Api.md b/doc/Api.md new file mode 100644 index 0000000..1719dac --- /dev/null +++ b/doc/Api.md @@ -0,0 +1,126 @@ +# A tour of the API + +## Core SDK + +The core SDK mainly provides tools for working with SSE-gens in a generic +manner. To do so all specific SSE-Gens are implementations of the +[starfederation.datastar.clojure.protocols/SSEGenerator](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.protocols#SSEGenerator) +protocol. This way +you use the same namespace regardless of the specific adapter you are using. + +### [starfederation.datastar.clojure.api](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api) + +This is the main entry point for using the SDK. + +#### SSE Generator utilities + +- [starfederation.datastar.clojure.api/close-sse!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#close-sse!) +- [starfederation.datastar.clojure.api/lock-sse!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#lock-sse!) +- [starfederation.datastar.clojure.api/with-open-sse](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#with-open-sse) + +#### Standard Datastar patching functions + +- [starfederation.datastar.clojure.api/patch-elements!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#patch-elements!) +- [starfederation.datastar.clojure.api/patch-elements-seq!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#patch-elements-seq!) +- [starfederation.datastar.clojure.api/remove-element!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#remove-element!) +- [starfederation.datastar.clojure.api/patch-signals!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#patch-signals!) + +#### Executing scripts + +Building on the patching functions we have convenience functions to send +JavaScript scripts to the browser to execute: + +- [starfederation.datastar.clojure.api/execute-script!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#execute-script!) +- [starfederation.datastar.clojure.api/console-log!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#console-log!) +- [starfederation.datastar.clojure.api/console-error!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#console-error!) +- [starfederation.datastar.clojure.api/redirect!](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#redirect!) + +#### Simple actions + +There are also some simple utilities for generation Datastar actions to put in +HTML: + +- [starfederation.datastar.clojure.api/sse-get](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#sse-get) +- [starfederation.datastar.clojure.api/sse-post](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#sse-post) +- [starfederation.datastar.clojure.api/sse-put](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#sse-put) +- [starfederation.datastar.clojure.api/sse-patch](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#sse-patch) +- [starfederation.datastar.clojure.api/sse-delete](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#sse-delete) + +#### Helpers + +- [starfederation.datastar.clojure.api/get-signals](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#get-signals) +- [starfederation.datastar.clojure.api/datastar-request?](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.api#datastar-request?) + +### [starfederation.datastar.clojure.adapter.common](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.adapter.common) + +This namespace contains code shared between specific adapters. This is a more +Advanced API needed mostly if you start +[writing custom adapters](/doc/implementing-adapters.md) or custom +[write profiles](/doc/Write-profiles.md). + +It contains: + +- definition for the keys used in the option maps of `->sse-response` functions +- utilities for working with output streams and building [write profiles](/doc/Write-profiles.md) +- default callbacks. + +### [starfederation.datastar.clojure.adapter.test](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/api/starfederation.datastar.clojure.adapter.test) + +This namespace contains a few mock SSEGenerator implementations. + +## Ring + +We try to provide a similar model for working with SSE in each adapter we +support by sticking as close as possible to the ring spec. + +### General model + +When using the SDK you will mainly use a `->sse-response` function. It returns a +ring response map that starts a SSE stream and is tailored to the adapter you +are using. + +The response map will contain a response status, the required SSE headers and +a body. + +> [!IMPORTANT] +> You can modify the response map except for the body and the SSE headers. + +For every adapter this function takes 2 arguments: + +- the ring request +- a map containing callbacks and options + +You get access to the SSE-Gen as an argument to the callbacks yo pass to +`->sse-response`. + +### SSE lifecycle + +The SSE connection is open and ready when the `on-open` callback is run. +If you don't plan on keeping it open you must close it yourself here. + +When the adapter detects the client disconnecting or when you close the +SSE-Gen yourself the `on-close` callback will be called. Note that when that +happens it is already no longer possible to send events. + +When sending events to the client, if an exception is thrown a `on-exception` +callback will be called. If you don't provide it a default one will be used. +The default behavior is to close the connection on `java.io.IOException` and +rethrow otherwise. + +### Differences between adapters + +We have tried to keep the differences between the adapters minimal. Still not +all ring adapters use the same mechanism to represent SSE streams and some +differences are unavoidable. + +These differences revolve mainly around disconnect detection and how the ring +synchronous and asynchronous APIs behave. + +Refer to the SDK adapter READMEs for more information. + +### Option keys & default write profiles aliases + +Besides the `->sse-reponse` function the `starfederation.datastar.clojure.adapter.XXX` +namespaces provides aliases to the commonly used code from the +[starfederation.datastar.clojure.adapter.common](https://cljdoc.org/d/dev.data-star.clojure/sdk/1.0.0-RC2/api/starfederation.datastar.clojure.adapter.common) +namespace. diff --git a/doc/Libraries.md b/doc/Libraries.md new file mode 100644 index 0000000..71b74fc --- /dev/null +++ b/doc/Libraries.md @@ -0,0 +1,25 @@ +# Libraries + +## [Core SDK](/libraries/sdk/README.md) + +Core SDK implementing the generic parts of the Datastar ADR. + +## [Http-kit adapter](/libraries/sdk-http-kit/README.md) + +SSE-gen implementation and ring API for Http-kit + +## [Ring](/libraries/sdk-ring/README.md) + +SSE-gen implementation and ring API for ring compliant adapters + +## [Brotli](/libraries/sdk-brotli/README.md) + +Write profiles for brotli + +## Malli Schemas + +We provide libraries containing Malli schemas for the different libraries + +- [Core SDK schemas](/libraries/sdk-malli-schemas/README.md) +- [Http-kit adapter schemas](/libraries/sdk-http-kit-malli-schemas/README.md) +- [Ring adapter schemas](/libraries/sdk-ring-malli-schemas/README.md) diff --git a/doc/SSE-design-notes.md b/doc/SSE-design-notes.md index bffc8a8..3e2dbed 100644 --- a/doc/SSE-design-notes.md +++ b/doc/SSE-design-notes.md @@ -58,17 +58,18 @@ Here are some solutions for buffering the writes: | 2 | churning through buffers for each event sent | | 3 | controlled allocations | -| solution | notes | -| -------- | ------------------------------------------------------------------------------- | -| 1 | we can control the size of the buffer | -| 2 | the jvm gc should be able _recycle_ short lived objects | +| solution | notes | +| -------- | --------------------------------------------------------- | +| 1 | we can control the size of the buffer | +| 2 | the jvm gc should be able _recycle_ short lived objects | | 3 | no direct support in the jvm, gc _recycling_ maybe be better, needs to be tuned | -> [!note] +> [!NOTE] > An `OutputStream` compression wrapper comes with an internal buffer and a > context window that will both allocate and retain memory. -> [!important] + +> [!IMPORTANT] > A `ByteArrayOutputStream` is also another buffer, it doesn't shrink in size > when reset is called (see [javadoc]()) diff --git a/doc/Using-datastar.md b/doc/Using-datastar.md new file mode 100644 index 0000000..60f3853 --- /dev/null +++ b/doc/Using-datastar.md @@ -0,0 +1,286 @@ +# Using Datastar + +Datastar allows you to control a web page from the backend. HTTP responses are +used to patch either the current dom or the signals present in the +page. + +There are 2 main ways to structure HTTP responses for Datastar: + +- Return `text/html` or `application/json` HTTP response to patch the DOM or + signals +- Start a Server Sent Events stream with a `text/event-stream` response and + send SSE events to patch the page. + +The Clojure SDK provides helpers when using the SSE option. It follows the +[Architecture Decision Record](https://github.com/starfederation/datastar/blob/develop/sdk/ADR.md) +shared by all official SDKs. This ADR describes a general mechanism to +manage SSE streams called a `ServerSentEventGenerator` and functions using this +SSE-Gen to send events formatted the way the Datastar expects them in the +browser. + +## Brief overview of the API + +When using the SDK you will invariably make use of 2 main namespaces, one for +sending Datastar event, the other to make SSE ring responses. + +### `starfederation.datastar.clojure.api` + +This is the main API of the core SDK. It provides several tools to work with +SSE-Gens such as: + +- the patching functions specified in the ADR +- helpers for managing the SSE-Gen + +### `starfederation.datastar.clojure.adapter.XXX` + +The ring API provided by the adapter implementation you are using. It's main +role is to provide a `->sse-response` function that builds a ring response +tailored to your adapter. + +In the following examples we'll be using +`starfederation.datastar.clojure.adapter.http-kit`. + +## Examples + +### Simple hello world + +Let's start with a Datastar hello world. We start by requiring the 2 namespaces +we'll need: + +```clojure +(require '[starfederation.datastar.clojure.api :as d*] ;; 1 + '[starfederation.datastar.clojure.adapter.http-kit :as hk-gen]);; 2 + +``` + +1. The core API +2. The specific API for a ring adapter, in this case Http-kit + +We can imagine a page with the following HTML: + +```HTML +
+ +

+
+``` + +Here we have a button that will call the `/'say-hello'` endpoint when clicked. +The handler for this endpoint would be: + +```clojure +(require '[some.hiccup.library :refer [html]]) + +(defn simple-hello [request] ;; 1 + (hk-gen/->sse-response request ;; 2 + {hk-gen/on-open ;; 3 + (fn [sse-gen] ;; 4 + (d*/patch-elements! sse-gen + (html [:p {:id "hello-field"} "Hello world!"])) ;; 5 + (d*/close-sse! sse-gen))})) ;; 6 + +``` + +1. We declare a standard ring handler which is a function of the HTTP request +2. The handler returns a SSE response +3. We setup a callback that will be called once the SSE stream is opened +4. The callback receives a `sse-gen` which is the SSE-gen for this response +5. Using `patch-elements` we send a HTML targeting the `"hello-field"` element +6. We close the connection + +In the browser, when Datastar gets the patch it will morph the DOM to be: + +```HTML +
+ +

Hello world!

+
+``` + +### Chunked hello world + +The previous example could have been accomplished without the use of the SDK +since we only sent one patch. However, using SSE we could just as well chunk the +response. Consider this handler: + +```clojure +(defn chunked-hello [request] + (hk-gen/->sse-response request + {hk-gen/on-open + (fn [sse-gen] + + (d*/patch-elements! sse-gen + (html [:p {:id "hello-field"} "Hello"])) + + (Thread/sleep 1000) + + (d*/patch-elements! sse-gen + (html [:p {:id "hello-field"} "Hello world!"])) + + (d*/close-sse! sse-gen))})) + +``` + +Here we send 2 events. The first will morph the DOM into: + +```HTML +
+ +

Hello

+
+``` + +The second: + +```HTML +
+ +

Hello world!

+
+``` + +The example on [the datastar homepage](https://data-star.dev/) is build +similarly to this. It helps illustrate the possibilities using SSE. We +can sent multiple patches, do work between patches and we can keep the +connection alive for however long we want. + +### Barebones broadcast + +Speaking of keeping the connection alive, a simple broadcast system can be +implemented with the following code: + +```clojure +(def !connections (atom #{})) ;; 1 + + +(defn subscribe-handler [request] + (hk-gen/->sse-response request + {hk-gen/on-open + (fn [sse-gen] + (swap! !connections conj sse-gen)) ;; 2 + + hk-gen/on-close + (fn [sse-gen status] + (swap! !connections disj sse-gen))})) ;; 3 + + +(defn broadcast-elements! [elements] ;; 4 + (doseq [c @!connections] + (d*/patch-elements! c elements))) + +``` + +1. We keep an atom that contains the open connections +2. When the handler is called the `sse-gen` is added to `!connections` +3. When the connection is closed we remove `sse-gen` from `!connections` +4. The broadcast function will send `elements` to all connected browsers + +In this example we do not automatically close the `sse-gen`. It will be kept +alive until either the client closes the SSE connection or your code does +it somewhere else. + +### Fat updates and compression + +Long lived connections open interesting possibilities up. A common pattern when +using Datastar is to keep one SSE stream opened and push updates when relevant +events occurred on the server. + +We can have a page setup this way: + +```HTML + +
+ Imagine a complex UI here +
+ +``` + +And code similar to our broadcast example: + +```clojure +;; Broadcasting logic +(def !connections (atom #{})) + + +(defn updates-handler [request] + (hk-gen/->sse-response request + {hk-gen/on-open + (fn [sse-gen] + (swap! !connections conj sse-gen)) + + hk-gen/on-close + (fn [sse-gen status] + (swap! !connections disj sse-gen))})) + + +(defn broadcast-frame! [frame] + (doseq [c @!connections] + (d*/patch-elements! c frame))) + + +;; Renders the whole main content of the page +(defn render-frame [state] + (html + [:div#main "Do something with the state here"]) + + +;; The state the rendering is based on +(def !state (atom {:some-complex "state"})) + + +(add-watch !state ::watch + (fn [_k _ref old new] + (when-not (identical? old new) + (let [frame (render-frame new)] + (broadcast-frame! frame)))))) + +``` + +When this page loads, the `/updates` endpoint is called setting up a long lived +SSE connection. When `!state` changes we broadcast a re-render of the whole +content of the page. + +Using fat updates instead of fine grained ones might seem wasteful at first. +It however has several advantages: + +- We don't need to keep track of which fine grained updates may not have gone + through risking a page only partially updated. Instead each update of the page + a client receives is internally consistent. +- SSE streams compresses really well, especially with algorithms like brotli + that keep a shared compression window between client and server opened for + the whole duration of the stream. + +To use compression in this example we just need to use an option of the +`->sse-response` function. Our `update-handler` would look like this: + +```clojure +(defn update-handler [request] + (hk-gen/->sse-response request + {hk-gen/on-open + (fn [sse-gen] + (swap! !connections conj sse-gen)) + + hk-gen/on-close + (fn [sse-gen status] + (swap! !connections disj sse-gen)) + + ;; We add a write profile here to enable gzip compression + hk-gen/write-profile hk-gen/gzip-profile})) + +``` + +For more about the compression option and this write profile concept, +checkout the [write profiles docs](/doc/Write-profiles.md). + +## Going further + +The examples presented here are contrived on purpose. For instance, you won't +keep you app state in an atom and use a watch to broadcast changes. However +these may help you get a feel for what is possible. + +You can now learn more about each specific library we provide using the rest of +the docs as well as the API docs. + +There are already several open source projects using Clojure and Datastar +that refine the patterns we presented here. I would encourage you to explore +these projects, use or take inspiration from them. diff --git a/doc/Write-profiles.md b/doc/Write-profiles.md index 51b8415..11fd04b 100644 --- a/doc/Write-profiles.md +++ b/doc/Write-profiles.md @@ -1,8 +1,8 @@ # Write profiles To manage several aspects of a SSE connection -(see the [SSE design notes](./SSE-design-notes.md)) the SDK provides a `write profile` -mechanism. It lets you control: +(see the [SSE design notes](/doc/SSE-design-notes.md)) the SDK provides a +`write profile` mechanism. It lets you control: - the buffering behavior of the SSE connection - whether you want to add compression to the SSE stream diff --git a/doc/cljdoc.edn b/doc/cljdoc.edn new file mode 100644 index 0000000..a478edc --- /dev/null +++ b/doc/cljdoc.edn @@ -0,0 +1,22 @@ +{:cljdoc/languages ["clj"] + :cljdoc.doc/tree + [["Readme" {:file "README.md"}] + ["Changelog" {:file "CHANGELOG.md"}] + + ["SDK docs" + ["Using Datastar" {:file "doc/Using-datastar.md"}] + ["A tour of the API" {:file "doc/Api.md"}] + ["SDK Libraries" {:file "doc/Libraries.md"} + ["Core SDK" {:file "libraries/sdk/README.md"}] + ["Http-kit adapter" {:file "libraries/sdk-http-kit/README.md"}] + ["Ring adapter" {:file "libraries/sdk-ring/README.md"}] + ["Core Malli Schemas" {:file "libraries/sdk-malli-schemas/README.md"}] + ["Http-kit Malli Schemas" {:file "libraries/sdk-http-kit-malli-schemas/README.md"}] + ["Ring Malli Schemas" {:file "libraries/sdk-ring-malli-schemas/README.md"}] + ["Brotli" {:file "libraries/sdk-brotli/README.md"}]] + ["Write profiles" {:file "doc/Write-profiles.md"}]] + + ["Internals and advanced topics" + ["SSE design notes" {:file "doc/SSE-design-notes.md"}] + ["Maintainer's guide" {:file "doc/maintainers-guide.md"}] + ["Adapter implemation guide" {:file "doc/implementing-adapters.md"}]]]} diff --git a/doc/maintainers-guide.md b/doc/maintainers-guide.md index 0d8f49c..4834de0 100644 --- a/doc/maintainers-guide.md +++ b/doc/maintainers-guide.md @@ -2,10 +2,11 @@ ## Directory structure -- `sdk`: the source folder for the main SDK -- `sdk-adapter-*`: source folders for adapter specific code -- `sdk-malli-schemas`: self explanatory... -- `sdk-brotli`: brotli write profiles +- `libraries/sdk`: the source folder for the main SDK +- `libraries/sdk-ring`: source folders for the ring adapter specific code +- `libraries/sdk-http-kit`: source folders for the http-kit adapter specific code +- `libraries/sdk-malli-schemas`: self explanatory... +- `libraries/sdk-brotli`: brotli write profiles - `src/bb`: tasks used run a repl, tests... - `src/bb-example`: bb examples - `src/dev`: dev utils, examples @@ -19,9 +20,10 @@ - `bb bump-version patch/minor/major`: to bump a version component across all libs - `bb set-version x.x.x`: to set the version component across all libs - `bb jar:all`: Build jars artifacts for all of the libs +- `bb clean`: Clean all build artifacts - `bb install:all`: Build jars artifacts for all of the libs and installs them locally +- `bb install:clean` will delete `~/.m2/repository/dev/data-star/clojure` - `bb jar:`: Build jars artifacts for one of the libs -- `bb clean`: Clean all build artifacts - `bb publish:all`: Publish the artifacts to clojars.org ### Development tasks `bb run dev` @@ -43,22 +45,54 @@ ring adapter using ring-jetty. - `bb run test:rj9a`: run all test for the SDK and the ring adapter using rj9a. - `bb run test:bb`: run unit tests for the SDK in Babashka. -- `bb run test:SDK-common`: start the server used to run the +- `bb run test:sdk-common`: start the server used to run the [SDKs' common tests](https://github.com/starfederation/datastar/tree/develop/sdk/tests). +- `bb run test:sdk-common`: run the common SDK test (go program) + +### Cljdoc tasks + +In order to test how [cljdoc](https://cljdoc.org/) will ingest our libraries +there are babashka to run a local instance. + +To do so you need to have either [docker](https://www.docker.com/) +or [podman](https://podman.io/) installed, the babashka tasks we provide will +work with either one. + +Next you need to run: + +```bash +docker pull cljdoc/cljdoc +``` + +Once that is done you can use the following bb tasks: + +- `bb run cljdoc:server` to start a cljdoc local instance on port `8000` +- `bb run install:all` to install locally the jars to ingest +- `bb run cljdoc:ingest ` to tell cljdoc to ingest a sdk library. + The possible values for `` are: + `:sdk :http-kit :ring :malli-schemas :brotli` +- `bb run cljdoc:clean` will delete `./.cljdoc-preview`, the directory + where the local cljdoc server stores its data. ## Release -- The library artifacts are published to Clojars (http://clojars.org) under the `dev.data-star.clojure` namespace. -- The Clojars account and deploy token are managed by Ben Croker, and added to this repo as GitHub action secrets: +- The library artifacts are published to [Clojars](http://clojars.org) under the + `dev.data-star.clojure` namespace. +- The Clojars account and deploy token are managed by Ben Croker, and added to + this repo as GitHub action secrets: - Secret name: `CLOJARS_USERNAME` Value: _the clojars account username_ - Secret name: `CLOJARS_PASSWORD` Value: _the clojars deploy token_ -- The libraries' versions are bumped in lockstep so that there is no confusion over which version of the common lib should be used with an adapter lib. +- The libraries' versions are bumped in lockstep so that there is no confusion + over which version of the common lib should be used with an adapter lib. -The Github Actions [CI workflow for clojure](../.github/workflows/release-sdk.yml) will always run the tests and produce jar artifacts. +The Github Actions [CI workflow for clojure](../.github/workflows/release-sdk.yml) +will always run the tests and produce jar artifacts. -Triggering a deployment to clojars is a manual process. A Datastar core contributor must trigger the `Release Clojure SDK` workflow with the `publish` input boolean set to `true`. +Triggering a deployment to clojars is a manual process. A Datastar core +contributor must trigger the `Release Clojure SDK` workflow with the `publish` +input boolean set to `true`. **Release process:** @@ -71,14 +105,23 @@ Triggering a deployment to clojars is a manual process. A Datastar core contribu ### Running tests - for the unit and smoke tests see the bb tasks. -- for the generic bash SDK tests: +- for the generic go SDK tests: 1. Start the test server with `bb run test:sdk-common` - 2. Run `go run github.com/starfederation/datastar/sdk/tests/cmd/datastar-sdk-tests@latest` + 2. Run `bb run test:sdk-common-go` ### webdriver config -Tests resources contains a test.config.edn file. It contains a map whose keys +You can modify the webdriver config when testing by creating a +`test-resources/test.config.edn` file. It contains a map whose keys are: -- `:drivers`: [etaoin](https://github.com/clj-commons/etaoin) webdriver types to run +- `:drivers`: [etaoin](https://github.com/clj-commons/etaoin) webdriver types + to run - `:webdriver-opts`: a map of webdriver type to webriver specific options + +For instance on my machine: + +```clojure +{:drivers [:firefox :chrome] + :webdriver-opts {:chrome {:path-driver "/snap/bin/chromium.chromedriver"}}} +``` diff --git a/examples/hello-httpkit/README.md b/examples/hello-httpkit/README.md index cb1cdb8..7c2d6a1 100644 --- a/examples/hello-httpkit/README.md +++ b/examples/hello-httpkit/README.md @@ -4,12 +4,12 @@ - repl: -``` +```bash clojure -M:repl -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]" ``` - main: -``` +```bash clojure -M -m hello-httpkit ``` diff --git a/examples/hello-httpkit/deps.edn b/examples/hello-httpkit/deps.edn index 04873e1..0a911e4 100644 --- a/examples/hello-httpkit/deps.edn +++ b/examples/hello-httpkit/deps.edn @@ -1,11 +1,12 @@ {:paths ["src" "resources"] - :deps {com.cnuernber/charred {:mvn/version "1.034"} - dev.data-star.clojure/http-kit {:local/root "../../sdk-adapter-http-kit"} - dev.data-star.clojure/sdk {:local/root "../../sdk"} - dev.onionpancakes/chassis {:mvn/version "1.0.365"} - http-kit/http-kit {:mvn/version "2.8.1"} - metosin/reitit {:mvn/version "0.7.2"}} + :deps {com.cnuernber/charred {:mvn/version "1.034"} + dev.data-star.clojure/http-kit {:local/root "../../libraries/sdk-http-kit" + :exclusions [dev.data-star.clojure/sdk]} + dev.data-star.clojure/sdk {:local/root "../../libraries/sdk"} + dev.onionpancakes/chassis {:mvn/version "1.0.365"} + http-kit/http-kit {:mvn/version "2.8.1"} + metosin/reitit {:mvn/version "0.7.2"}} :aliases - {:repl {:extra-deps {org.clojure/clojure {:mvn/version "1.12.0"} - nrepl/nrepl {:mvn/version "1.3.0"} - cider/cider-nrepl {:mvn/version "0.50.2"}}}}} + {:repl {:extra-deps {org.clojure/clojure {:mvn/version "1.12.0"} + nrepl/nrepl {:mvn/version "1.3.0"} + cider/cider-nrepl {:mvn/version "0.50.2"}}}}} diff --git a/examples/hello-world/README.md b/examples/hello-world/README.md index 686f0e3..7c38bdc 100644 --- a/examples/hello-world/README.md +++ b/examples/hello-world/README.md @@ -4,12 +4,12 @@ - repl: -``` +```bash clojure -M:repl -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]" ``` - main: -``` +```bash clojure -M -m example.main ``` diff --git a/examples/hello-world/deps.edn b/examples/hello-world/deps.edn index debe302..8a4d84c 100644 --- a/examples/hello-world/deps.edn +++ b/examples/hello-world/deps.edn @@ -1,8 +1,8 @@ {:paths ["src/main" "resources"] - :deps { - dev.data-star.clojure/sdk {:local/root "../../sdk"} - dev.data-star.clojure/ring {:local/root "../../sdk-adapter-ring"} + :deps {dev.data-star.clojure/sdk {:local/root "../../libraries/sdk/"} + dev.data-star.clojure/ring {:local/root "../../libraries/sdk-ring/" + :exclusions [dev.data-star.clojure/sdk]} ring/ring-jetty-adapter {:mvn/version "1.13.0"} metosin/reitit {:mvn/version "0.7.2"} dev.onionpancakes/chassis {:mvn/version "1.0.365"} diff --git a/build_stub.clj b/libraries/build_stub.clj similarity index 91% rename from build_stub.clj rename to libraries/build_stub.clj index 68ca770..197d044 100644 --- a/build_stub.clj +++ b/libraries/build_stub.clj @@ -3,7 +3,7 @@ '[clojure.tools.build.api :as b] '[clojure.edn :as edn]) -(def root-project (-> (edn/read-string (slurp "../deps.edn")) +(def root-project (-> (edn/read-string (slurp "../../deps.edn")) :aliases :neil :project)) (def repo-url-prefix (:url root-project)) (def scm (:scm root-project)) @@ -19,7 +19,7 @@ (assert description ":description must be set in deps.edn under the :neil alias") (def class-dir "target/classes") -(def basis (b/create-basis {:project "deps.edn"})) +(def basis (delay (b/create-basis {:project "deps.edn"}))) (def jar-file (format "target/%s-%s.jar" (name lib) version)) (defn clean [_] @@ -33,7 +33,7 @@ (b/write-pom {:class-dir class-dir :lib lib :version version - :basis basis + :basis @basis :src-dirs ["src/main" "resources"] :pom-data [[:description description] [:url (permalink cwd)] @@ -49,7 +49,7 @@ (defn install [_] (jar {}) - (b/install {:basis basis + (b/install {:basis @basis :lib lib :version version :jar-file jar-file diff --git a/sdk-brotli/README.md b/libraries/sdk-brotli/README.md similarity index 78% rename from sdk-brotli/README.md rename to libraries/sdk-brotli/README.md index cf75af5..1250a60 100644 --- a/sdk-brotli/README.md +++ b/libraries/sdk-brotli/README.md @@ -1,23 +1,23 @@ # Datastar Brotli write profile -This library contains some utilities to work with Brotli. - -Credits to [Anders](https://andersmurphy.com/) and his work on [Hyperlith](https://github.com/andersmurphy/hyperlith) -from which this library takes it's code. - ## Installation Install using clojars deps coordinates: [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/brotli.svg)](https://clojars.org/dev.data-star.clojure/brotli) +[![cljdoc badge](https://cljdoc.org/badge/dev.data-star.clojure/brotli)](https://cljdoc.org/d/dev.data-star.clojure/brotli/CURRENT) -## Supported ring adapters +This library contains some utilities to work with Brotli. + +Credits to [Anders](https://andersmurphy.com/) and his work on [Hyperlith](https://github.com/andersmurphy/hyperlith) +from which this library takes it's code. -At this moment only Http-kit is supported. +> [!IMPORTANT] +> At this moment only Http-kit is supported. -## Usage +## Overview -This library provides brotil write profiles you can use like this: +This library provides Brotli write profiles you can use like this: ```clojure (require diff --git a/sdk-adapter-http-kit/build.clj b/libraries/sdk-brotli/build.clj similarity index 100% rename from sdk-adapter-http-kit/build.clj rename to libraries/sdk-brotli/build.clj diff --git a/sdk-brotli/deps.edn b/libraries/sdk-brotli/deps.edn similarity index 73% rename from sdk-brotli/deps.edn rename to libraries/sdk-brotli/deps.edn index 68a46e0..8fc49de 100644 --- a/sdk-brotli/deps.edn +++ b/libraries/sdk-brotli/deps.edn @@ -1,10 +1,11 @@ {:paths ["src/main"] - :deps {com.aayushatharva.brotli4j/brotli4j {:mvn/version "1.18.0"} - io.netty/netty-buffer {:mvn/version "4.1.119.Final"}} - :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.9" - :git/sha "e405aac"} + :deps {com.aayushatharva.brotli4j/brotli4j {:mvn/version "1.20.0"} + dev.data-star.clojure/sdk {:mvn/version "1.0.0-RC2"} + io.netty/netty-buffer {:mvn/version "4.2.6.Final"}} + :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.10" + :git/sha "deedd62"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :neil {:project {:name dev.data-star.clojure/brotli :description "Brotli compression helpers for the Datastar SDK" - :version "1.0.0-RC1"}}}} + :version "1.0.0-RC2"}}}} diff --git a/sdk-brotli/src/main/starfederation/datastar/clojure/brotli.clj b/libraries/sdk-brotli/src/main/starfederation/datastar/clojure/brotli.clj similarity index 100% rename from sdk-brotli/src/main/starfederation/datastar/clojure/brotli.clj rename to libraries/sdk-brotli/src/main/starfederation/datastar/clojure/brotli.clj diff --git a/libraries/sdk-http-kit-malli-schemas/README.md b/libraries/sdk-http-kit-malli-schemas/README.md new file mode 100644 index 0000000..7f1cae6 --- /dev/null +++ b/libraries/sdk-http-kit-malli-schemas/README.md @@ -0,0 +1,23 @@ +# Malli schemas for the SDK + +## Installation + +Install using clojars deps coordinates: + +[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/http-kit-malli-schemas.svg)](https://clojars.org/dev.data-star.clojure/http-kit-malli-schemas) + +[![cljdoc badge](https://cljdoc.org/badge/dev.data-star.clojure/malli-schemas)](https://cljdoc.org/d/dev.data-star.clojure/malli-schemas/CURRENT) + +## Overview + +This library provides Malli schemas for Http-kit adapter APIs. + +Require the namespaces for which you want schema and/or instrumentation. Then +use malli's instrumentation facilities. + +Notable schema namespaces: + +- `starfederation.datastar.clojure.adapter.http-kit-schemas` for the + original http-kit adapter +- `starfederation.datastar.clojure.adapter.http-kit2-schemas` for the new + http-kit adapter API diff --git a/sdk-adapter-ring/build.clj b/libraries/sdk-http-kit-malli-schemas/build.clj similarity index 100% rename from sdk-adapter-ring/build.clj rename to libraries/sdk-http-kit-malli-schemas/build.clj diff --git a/libraries/sdk-http-kit-malli-schemas/deps.edn b/libraries/sdk-http-kit-malli-schemas/deps.edn new file mode 100644 index 0000000..3962628 --- /dev/null +++ b/libraries/sdk-http-kit-malli-schemas/deps.edn @@ -0,0 +1,12 @@ +{:paths ["src/main"] + :deps {dev.data-star.clojure/sdk {:mvn/version "1.0.0-RC2"} + dev.data-star.clojure/http-kit {:mvn/version "1.0.0-RC2"} + dev.data-star.clojure/malli-schemas {:mvn/version "1.0.0-RC2"} + metosin/malli {:mvn/version "0.17.0"}} + :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.9" + :git/sha "e405aac"} + slipset/deps-deploy {:mvn/version "0.2.2"}} + :ns-default build} + :neil {:project {:name dev.data-star.clojure/http-kit-malli-schemas + :version "1.0.0-RC2" + :description "Malli schemas for the Datastar SDK"}}}} diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit2_schemas.clj b/libraries/sdk-http-kit-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit2_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit2_schemas.clj rename to libraries/sdk-http-kit-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit2_schemas.clj diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit_schemas.clj b/libraries/sdk-http-kit-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit_schemas.clj rename to libraries/sdk-http-kit-malli-schemas/src/main/starfederation/datastar/clojure/adapter/http_kit_schemas.clj diff --git a/libraries/sdk-http-kit/README.md b/libraries/sdk-http-kit/README.md new file mode 100644 index 0000000..f6195a9 --- /dev/null +++ b/libraries/sdk-http-kit/README.md @@ -0,0 +1,59 @@ +# Datastar http-kit adapter + +## Installation + +Install using clojars deps coordinates: + +[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/http-kit.svg)](https://clojars.org/dev.data-star.clojure/http-kit) + +[![cljdoc badge](https://cljdoc.org/badge/dev.data-star.clojure/http-kit)](https://cljdoc.org/d/dev.data-star.clojure/http-kit/CURRENT) + +This library already depends on the core SDK lib. + +> [!IMPORTANT] +> This library adds (and needs) a dependency to Http-kit as recent as the current +> `v2.9.0-beta2`. We do not recommend using older versions (`v2.8.1` being the +> current stable) as they do not work properly with SSE. + +## Overview + +This library provides an implementation of the +`starfederation.datastar.clojure.protocols/SSEGenerator` for Http-kit. + +It provides 2 APIs to create ring SSE response tailored to Http-kit. + +### `starfederation.datastar.clojure.adapter.http-kit` + +This this the original API, it is mostly one function: `->sse-response`. + +Using this namespace is straightforward but it has a downside. +The way it works, the response's status and headers will be sent as soon has +your ring handler is done. It means that middleware that would modify the +response (or interceptors having a `:leave` function) will have no effect. + +### `starfederation.datastar.clojure.adapter.http-kit2` + +This is the latest API for using the SDK with Http-kit. It was designed to fix +the middleware (and interceptor) incompatibilities of the first. It is inspired +by the way [Pedestal](https://github.com/pedestal/pedestal) uses Http-kit. + +Using this API, `->sse-reponse` will not start the SSE stream. It returns a +response map that can be modified by middleware and interceptors after the +handler (and thus `->sse-reponse`) is done. + +The SSE stream is initiated either by the `wrap-start-responding` middleware or +the `start-responding-interceptor`. To be sure all other middleware you may use +work properly, `wrap-start-responding` should be the first in the chain and thus +the last to finish before handing the response to the adapter. + +## Specific behavior + +### Detecting a closed connection + +Http-kit detects closed connections by itself. When it dos the `on-close` +callback of `->sse-response` will be called. + +### SSE connection lifetime + +The connection stays alive until the client or your code explicitly closes it +server side regardless of the ring API (sync vs async) you are using. diff --git a/sdk-brotli/build.clj b/libraries/sdk-http-kit/build.clj similarity index 100% rename from sdk-brotli/build.clj rename to libraries/sdk-http-kit/build.clj diff --git a/sdk-adapter-http-kit/deps.edn b/libraries/sdk-http-kit/deps.edn similarity index 66% rename from sdk-adapter-http-kit/deps.edn rename to libraries/sdk-http-kit/deps.edn index e19497a..66f7e09 100644 --- a/sdk-adapter-http-kit/deps.edn +++ b/libraries/sdk-http-kit/deps.edn @@ -1,10 +1,10 @@ -;; NOTE: Track the next release of http-kit to switch to maven dep {:paths ["src/main"] - :deps {http-kit/http-kit {:mvn/version "2.9.0-alpha4"}} - :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.9" - :git/sha "e405aac"} + :deps {dev.data-star.clojure/sdk {:mvn/version "1.0.0-RC2"} + http-kit/http-kit {:mvn/version "2.9.0-beta2"}} + :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.10" + :git/sha "deedd62"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :neil {:project {:name dev.data-star.clojure/http-kit - :version "1.0.0-RC1" + :version "1.0.0-RC2" :description "http-kit adapter for the Datastar SDK"}}}} diff --git a/sdk-adapter-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit.clj b/libraries/sdk-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit.clj similarity index 100% rename from sdk-adapter-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit.clj rename to libraries/sdk-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit.clj diff --git a/sdk-adapter-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit/impl.cljc b/libraries/sdk-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit/impl.cljc similarity index 100% rename from sdk-adapter-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit/impl.cljc rename to libraries/sdk-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit/impl.cljc diff --git a/sdk-adapter-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit2.clj b/libraries/sdk-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit2.clj similarity index 100% rename from sdk-adapter-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit2.clj rename to libraries/sdk-http-kit/src/main/starfederation/datastar/clojure/adapter/http_kit2.clj diff --git a/sdk-malli-schemas/README.md b/libraries/sdk-malli-schemas/README.md similarity index 66% rename from sdk-malli-schemas/README.md rename to libraries/sdk-malli-schemas/README.md index 437906b..8fdc30d 100644 --- a/sdk-malli-schemas/README.md +++ b/libraries/sdk-malli-schemas/README.md @@ -6,7 +6,11 @@ Install using clojars deps coordinates: [![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/malli-schemas.svg)](https://clojars.org/dev.data-star.clojure/malli-schemas) -## Usage +[![cljdoc badge](https://cljdoc.org/badge/dev.data-star.clojure/malli-schemas)](https://cljdoc.org/d/dev.data-star.clojure/malli-schemas/CURRENT) + +## Overview + +This library provides Malli schemas for the core SDK. Require the namespaces for which you want schema and/or instrumentation. Then use malli's instrumentation facilities. @@ -14,8 +18,7 @@ use malli's instrumentation facilities. Notable schema namespaces: - `starfederation.datastar.clojure.api-schemas` for the general d\* API -- `starfederation.datastar.clojure.api.*-schemas` for more specific code underlying the main API -- `starfederation.datastar.clojure.adapter.common-schemas` for the common adapter machinery (write profiles) -- `starfederation.datastar.clojure.adapter.http-kit-schemas` for the http-kit adapter -- `starfederation.datastar.clojure.adapter.ring-schemas` for the ring adapter - +- `starfederation.datastar.clojure.api.*-schemas` for more specific code + underlying the main API +- `starfederation.datastar.clojure.adapter.common-schemas` for the common + adapter machinery (write profiles) diff --git a/sdk-malli-schemas/build.clj b/libraries/sdk-malli-schemas/build.clj similarity index 100% rename from sdk-malli-schemas/build.clj rename to libraries/sdk-malli-schemas/build.clj diff --git a/sdk-malli-schemas/deps.edn b/libraries/sdk-malli-schemas/deps.edn similarity index 67% rename from sdk-malli-schemas/deps.edn rename to libraries/sdk-malli-schemas/deps.edn index c5001ba..8e1bbcb 100644 --- a/sdk-malli-schemas/deps.edn +++ b/libraries/sdk-malli-schemas/deps.edn @@ -1,9 +1,10 @@ {:paths ["src/main"] - :deps {metosin/malli {:mvn/version "0.17.0"}} - :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.9" - :git/sha "e405aac"} + :deps {dev.data-star.clojure/sdk {:mvn/version "1.0.0-RC2"} + metosin/malli {:mvn/version "0.19.1"}} + :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.10" + :git/sha "deedd62"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :neil {:project {:name dev.data-star.clojure/malli-schemas - :version "1.0.0-RC1" + :version "1.0.0-RC2" :description "Malli schemas for the Datastar SDK"}}}} diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/common_schemas.clj b/libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/common_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/common_schemas.clj rename to libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/common_schemas.clj diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/common_schemas.clj b/libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/common_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/common_schemas.clj rename to libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/common_schemas.clj diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/elements_schemas.clj b/libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/elements_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/elements_schemas.clj rename to libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/elements_schemas.clj diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/scripts_schemas.clj b/libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/scripts_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/scripts_schemas.clj rename to libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/scripts_schemas.clj diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/signals_schemas.clj b/libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/signals_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/signals_schemas.clj rename to libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/signals_schemas.clj diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/sse_schemas.clj b/libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/sse_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/sse_schemas.clj rename to libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api/sse_schemas.clj diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api_schemas.clj b/libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/api_schemas.clj rename to libraries/sdk-malli-schemas/src/main/starfederation/datastar/clojure/api_schemas.clj diff --git a/libraries/sdk-ring-malli-schemas/README.md b/libraries/sdk-ring-malli-schemas/README.md new file mode 100644 index 0000000..bb1f96d --- /dev/null +++ b/libraries/sdk-ring-malli-schemas/README.md @@ -0,0 +1,17 @@ +# Malli schemas for the SDK + +## Installation + +Install using clojars deps coordinates: + +[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/ring-malli-schemas.svg)](https://clojars.org/dev.data-star.clojure/ring-malli-schemas) + +[![cljdoc badge](https://cljdoc.org/badge/dev.data-star.clojure/malli-schemas)](https://cljdoc.org/d/dev.data-star.clojure/malli-schemas/CURRENT) + +## Overview + +This library provides Malli schemas for the Ring adapter APIs. + +Notable schema namespaces: + +- `starfederation.datastar.clojure.adapter.ring-schemas` diff --git a/sdk/build.clj b/libraries/sdk-ring-malli-schemas/build.clj similarity index 100% rename from sdk/build.clj rename to libraries/sdk-ring-malli-schemas/build.clj diff --git a/libraries/sdk-ring-malli-schemas/deps.edn b/libraries/sdk-ring-malli-schemas/deps.edn new file mode 100644 index 0000000..968b9b6 --- /dev/null +++ b/libraries/sdk-ring-malli-schemas/deps.edn @@ -0,0 +1,12 @@ +{:paths ["src/main"] + :deps {metosin/malli {:mvn/version "0.17.0"} + dev.data-star.clojure/sdk {:mvn/version "1.0.0-RC2"} + dev.data-star.clojure/ring {:mvn/version "1.0.0-RC2"} + dev.data-star.clojure/malli-schemas {:mvn/version "1.0.0-RC2"}} + :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.9" + :git/sha "e405aac"} + slipset/deps-deploy {:mvn/version "0.2.2"}} + :ns-default build} + :neil {:project {:name dev.data-star.clojure/ring-malli-schemas + :version "1.0.0-RC2" + :description "Malli schemas for the Datastar SDK"}}}} diff --git a/sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/ring_schemas.clj b/libraries/sdk-ring-malli-schemas/src/main/starfederation/datastar/clojure/adapter/ring_schemas.clj similarity index 100% rename from sdk-malli-schemas/src/main/starfederation/datastar/clojure/adapter/ring_schemas.clj rename to libraries/sdk-ring-malli-schemas/src/main/starfederation/datastar/clojure/adapter/ring_schemas.clj diff --git a/libraries/sdk-ring/README.md b/libraries/sdk-ring/README.md new file mode 100644 index 0000000..1dbdf49 --- /dev/null +++ b/libraries/sdk-ring/README.md @@ -0,0 +1,50 @@ +# Datastar ring adapter + +## Installation + +Install using clojars deps coordinates: + +[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/ring.svg)](https://clojars.org/dev.data-star.clojure/ring) + +[![cljdoc badge](https://cljdoc.org/badge/dev.data-star.clojure/ring)](https://cljdoc.org/d/dev.data-star.clojure/ring/CURRENT) + +This library already depends on the core SDK lib. + +## Overview + +Datastar SDK adapter for [ring](https://github.com/ring-clojure/ring). It is currently +tested only with +[ring-jetty-adapter](https://github.com/ring-clojure/ring/tree/master/ring-jetty-adapter). + +This SDK adapter is based on the `ring.core.protocols/StreamableResponseBody` protocol. +Any ring adapter using this protocol should work with this library. + +## Specific behavior + +### Detecting a closed connection + +With the [ring-jetty-adapter](https://github.com/ring-clojure/ring/tree/master/ring-jetty-adapter), +sending events on a closed connection will fail at some point throwing an +`IOException`. By default the SSE-Gen will catch this exception, close itself +then call the `on-close` callback. + +> [!Note] +> At this moment, when using the ring adapter and Jetty, our SSE-Gen needs +> to send 2 small events or 1 big event to detect a closed connection. +> There must be some buffering happening independent of our implementation. + +### SSE connection lifetime + +|Api| connection lifetime| +|-|--| +|Ring sync| same as the thread carrying the initial response| +|Ring async| alive until the client or the server closes it| + +> [!IMPORTANT] +> This is standard behavior as specified in the Ring spec. It implies that you +> can't keep a SSE connection opened beyond the lifetime of the thread making +> the initial response when using the synchronous API. + +In other words, the [barebones broadcast example](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT/doc/sdk-docs/using-datastar#barebones-broadcast) +from the docs will work with the ring asynchronous API, not the synchronous one +when using this library. diff --git a/libraries/sdk-ring/build.clj b/libraries/sdk-ring/build.clj new file mode 100644 index 0000000..75ab750 --- /dev/null +++ b/libraries/sdk-ring/build.clj @@ -0,0 +1,2 @@ +(ns build) +(load-file "../build_stub.clj") diff --git a/sdk-adapter-ring/deps.edn b/libraries/sdk-ring/deps.edn similarity index 64% rename from sdk-adapter-ring/deps.edn rename to libraries/sdk-ring/deps.edn index 1cca75c..691eb36 100644 --- a/sdk-adapter-ring/deps.edn +++ b/libraries/sdk-ring/deps.edn @@ -1,9 +1,10 @@ {:paths ["src/main"] - :deps {org.ring-clojure/ring-core-protocols {:mvn/version "1.14.1"}} - :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.9" - :git/sha "e405aac"} + :deps {dev.data-star.clojure/sdk {:mvn/version "1.0.0-RC2"} + org.ring-clojure/ring-core-protocols {:mvn/version "1.15.0"}} + :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.10" + :git/sha "deedd62"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :neil {:project {:name dev.data-star.clojure/ring - :version "1.0.0-RC1" + :version "1.0.0-RC2" :description "Ring adapter for the Datastar SDK"}}}} diff --git a/sdk-adapter-ring/src/main/starfederation/datastar/clojure/adapter/ring.clj b/libraries/sdk-ring/src/main/starfederation/datastar/clojure/adapter/ring.clj similarity index 100% rename from sdk-adapter-ring/src/main/starfederation/datastar/clojure/adapter/ring.clj rename to libraries/sdk-ring/src/main/starfederation/datastar/clojure/adapter/ring.clj diff --git a/sdk-adapter-ring/src/main/starfederation/datastar/clojure/adapter/ring/impl.clj b/libraries/sdk-ring/src/main/starfederation/datastar/clojure/adapter/ring/impl.clj similarity index 100% rename from sdk-adapter-ring/src/main/starfederation/datastar/clojure/adapter/ring/impl.clj rename to libraries/sdk-ring/src/main/starfederation/datastar/clojure/adapter/ring/impl.clj diff --git a/libraries/sdk/README.md b/libraries/sdk/README.md new file mode 100644 index 0000000..65cb72f --- /dev/null +++ b/libraries/sdk/README.md @@ -0,0 +1,29 @@ +# Generic Clojure SDK for Datastar + +## Installation + +The SDK provided adapter libraries already depend on this library. However, +if you want to [develop your own SSEGenerator](/doc/implementing-adapters.md) +you'll need to depend on: + +[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/sdk.svg)](https://clojars.org/dev.data-star.clojure/sdk) +[![cljdoc badge](https://cljdoc.org/badge/dev.data-star.clojure/sdk)](https://cljdoc.org/d/dev.data-star.clojure/sdk/CURRENT) + +## Overview + +Datastar SDKs in each language follow an +[Architecture Decision Record](https://github.com/starfederation/datastar/blob/develop/sdk/ADR.md) +and the Clojure SDK is no exception. This ADR describes a general mechanism to +manage SSE streams called a ServerSentEventGenerator and functions using it to +send SSE event formatted the way the Datastar expect them in the browser. + +This library is a generic implementation of the ADR. It contains the code for: + +- building blocks to manage SSE streams +- a clojure protocol `starfederation.datastar.clojure.protocols/SSEGenerator` + allowing for the implementation of SSE generators for different Ring adapters. +- functions based on the protocol for working with SSE generators. +- helpers allowing to send Javascript scripts to run in the browser +- a generic mechanism called [write profiles](/doc/Write-profiles.md) to manage + the buffering behavior and compression of SSE streams +- several write profiles providing gzip compression diff --git a/libraries/sdk/build.clj b/libraries/sdk/build.clj new file mode 100644 index 0000000..75ab750 --- /dev/null +++ b/libraries/sdk/build.clj @@ -0,0 +1,2 @@ +(ns build) +(load-file "../build_stub.clj") diff --git a/sdk/deps.edn b/libraries/sdk/deps.edn similarity index 82% rename from sdk/deps.edn rename to libraries/sdk/deps.edn index 7eee1a6..6c7ffea 100644 --- a/sdk/deps.edn +++ b/libraries/sdk/deps.edn @@ -1,8 +1,8 @@ {:paths ["src/main" "resources"] - :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.9" - :git/sha "e405aac"} + :aliases {:build {:deps {io.github.clojure/tools.build {:git/tag "v0.10.10" + :git/sha "deedd62"} slipset/deps-deploy {:mvn/version "0.2.2"}} :ns-default build} :neil {:project {:name dev.data-star.clojure/sdk - :version "1.0.0-RC1" + :version "1.0.0-RC2" :description "Datastar SDK for Clojure"}}}} diff --git a/sdk/resources/clj-kondo.exports/starfederation.datastar.clojure/sdk/config.edn b/libraries/sdk/resources/clj-kondo.exports/starfederation.datastar.clojure/sdk/config.edn similarity index 100% rename from sdk/resources/clj-kondo.exports/starfederation.datastar.clojure/sdk/config.edn rename to libraries/sdk/resources/clj-kondo.exports/starfederation.datastar.clojure/sdk/config.edn diff --git a/sdk/src/main/starfederation/datastar/clojure/adapter/common.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/adapter/common.clj similarity index 98% rename from sdk/src/main/starfederation/datastar/clojure/adapter/common.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/adapter/common.clj index 5dfb01b..0fd6493 100644 --- a/sdk/src/main/starfederation/datastar/clojure/adapter/common.clj +++ b/libraries/sdk/src/main/starfederation/datastar/clojure/adapter/common.clj @@ -12,15 +12,15 @@ - [[write!]] - [[content-encoding]] - With this 3 keys we can control buffering aspects of our SSE connction and - and compression functionality. + With these 3 keys we can control buffering aspects of our SSE connection and + compression functionality. Here is an example profile which uses gzip and temporary buffers to concatenate SSE event text: ```clojure (def gzip-profile - {wrap-output-stream (fn[^OutputStream os] (-> os ->gzip-os ->os-writer)) + {wrap-output-stream (fn [^OutputStream os] (-> os ->gzip-os ->os-writer)) content-encoding gzip-content-encoding write! (->write-with-temp-buffer!)}) ``` @@ -107,7 +107,7 @@ A function that writes to a [[java.lang.Appendable]]. It should go in tandem with the way you wrap the [[OutputStream]]. - The SDK provide pre-made write function, see: + The SDK provide pre-made write functions, see: - [[->write-with-temp-buffer!]] - [[write-to-buffered-writer!]] " diff --git a/sdk/src/main/starfederation/datastar/clojure/adapter/test.cljc b/libraries/sdk/src/main/starfederation/datastar/clojure/adapter/test.cljc similarity index 73% rename from sdk/src/main/starfederation/datastar/clojure/adapter/test.cljc rename to libraries/sdk/src/main/starfederation/datastar/clojure/adapter/test.cljc index 078e594..cdc626a 100644 --- a/sdk/src/main/starfederation/datastar/clojure/adapter/test.cljc +++ b/libraries/sdk/src/main/starfederation/datastar/clojure/adapter/test.cljc @@ -1,4 +1,6 @@ (ns starfederation.datastar.clojure.adapter.test + "Utilities providing a test SSEGenerator and a mock `->sse-response` + function." (:require [starfederation.datastar.clojure.adapter.common :as ac] [starfederation.datastar.clojure.api.sse :as sse] @@ -25,7 +27,11 @@ -(defn ->sse-gen [& _] +(defn ->sse-gen + "Returns a SSEGenerator whose + [[starfederation.datastar.clojure.protocols/send-event!]] implementation + is a stub that returns the event string instead of sending it." + [& _] (->ReturnMsgGen)) @@ -54,9 +60,12 @@ (defn ->sse-response - "Fake a sse-response, the events sent with sse-gen during the - `on-open` callback are recorded in a vector stored in an atom returned as the - body of the response." + "Fake a sse-response, it returns the ring response map with + the `:status`, `:headers` and `:body` keys sent. + + The events sent with sse-gen during the `on-open` callback are recorded in a + vector stored in an atom. This atom is provided as the value for the + response's `:body`." [req {on-open ac/on-open :keys [status headers]}] (let [ diff --git a/sdk/src/main/starfederation/datastar/clojure/api.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/api.clj similarity index 94% rename from sdk/src/main/starfederation/datastar/clojure/api.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/api.clj index 73847c0..b56af4e 100644 --- a/sdk/src/main/starfederation/datastar/clojure/api.clj +++ b/libraries/sdk/src/main/starfederation/datastar/clojure/api.clj @@ -9,6 +9,7 @@ The main api consists several functions that operate on SSE generators, see: - [[patch-signals!]] - [[execute-script!]] + These function take options map whose keys are: - [[id]] - [[retry-duration]] @@ -21,8 +22,13 @@ These function take options map whose keys are: To help manage SSE generators's underlying connection there is: - [[close-sse!]] +- [[lock-sse!]] - [[with-open-sse]] +Helper to extract datastar specific data from ring requests: +- [[get-signals]] +- [[datastar-request?]] + Some common utilities for HTTP are also provided: - [[sse-get]] - [[sse-post]] @@ -324,13 +330,19 @@ Some scripts are provided: (defn get-signals - "Returns the signals json string from a ring request map. + "Extract datastar signals from a ring request map. - The Datastar signals are read from: - - the `:query-params` key of of the ring request map for HTTP get requests - - the body of the request for other HTTP methods + This function returns either a string or an InputStream depending on the + HTTP method of the request. - (Bring your own json parsing)" + - In the case of a GET request a string is returned (the signals are found in + the `:query-params` map of the request) + - For all other HTTP methods an `InputStream` is returned (the signals are the + `:body` of the request) + + We do not impose any json parsing library. This means that you need to bring + your own to parse the returned value into Clojure data. + " [ring-request] (signals/get-signals ring-request)) @@ -466,7 +478,8 @@ Some scripts are provided: ;; Misc ;; ----------------------------------------------------------------------------- (defn datastar-request? - "Test for the presence of the datastar header in a ring request." + "Test for the presence of the datastar header in a ring request. The presence + of the header means the request is issued from a datastar action." [request] (= "true" (get-in request [:headers "datastar-request"]))) diff --git a/sdk/src/main/starfederation/datastar/clojure/api/common.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/api/common.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/api/common.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/api/common.clj diff --git a/sdk/src/main/starfederation/datastar/clojure/api/elements.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/api/elements.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/api/elements.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/api/elements.clj diff --git a/sdk/src/main/starfederation/datastar/clojure/api/scripts.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/api/scripts.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/api/scripts.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/api/scripts.clj diff --git a/sdk/src/main/starfederation/datastar/clojure/api/signals.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/api/signals.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/api/signals.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/api/signals.clj diff --git a/sdk/src/main/starfederation/datastar/clojure/api/sse.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/api/sse.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/api/sse.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/api/sse.clj diff --git a/sdk/src/main/starfederation/datastar/clojure/consts.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/consts.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/consts.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/consts.clj diff --git a/sdk/src/main/starfederation/datastar/clojure/protocols.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/protocols.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/protocols.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/protocols.clj diff --git a/sdk/src/main/starfederation/datastar/clojure/utils.clj b/libraries/sdk/src/main/starfederation/datastar/clojure/utils.clj similarity index 100% rename from sdk/src/main/starfederation/datastar/clojure/utils.clj rename to libraries/sdk/src/main/starfederation/datastar/clojure/utils.clj diff --git a/sdk-adapter-http-kit/README.md b/sdk-adapter-http-kit/README.md deleted file mode 100644 index 090161b..0000000 --- a/sdk-adapter-http-kit/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Datastar http-kit adapter - -## Installation - -Install using clojars deps coordinates: - -[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/http-kit.svg)](https://clojars.org/dev.data-star.clojure/http-kit) - -Don't forget, you need the base SDK also: -[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/sdk.svg)](https://clojars.org/dev.data-star.clojure/sdk) diff --git a/sdk-adapter-ring/README.md b/sdk-adapter-ring/README.md deleted file mode 100644 index 85cc682..0000000 --- a/sdk-adapter-ring/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Datastar ring adapter - -Datastar SDK adapter for [ring](https://github.com/ring-clojure/ring). It is currently -tested with -[ring-jetty-adapter](https://github.com/ring-clojure/ring/tree/master/ring-jetty-adapter) - -This SDK adapter is based on the `ring.core.protocols/StreamableResponseBody` protocol. -Any ring adapter using this protocol should work with this library. - -## Installation - -Install using clojars deps coordinates: - -[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/ring.svg)](https://clojars.org/dev.data-star.clojure/ring) - -Don't forget, you need the base SDK also: -[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/sdk.svg)](https://clojars.org/dev.data-star.clojure/sdk) diff --git a/sdk-tests/README.md b/sdk-tests/README.md index a77e473..c6963c7 100644 --- a/sdk-tests/README.md +++ b/sdk-tests/README.md @@ -6,12 +6,21 @@ This is where the code for the [generic tests](/sdk/test) lives. - repl: -``` +```bash clojure -M:repl -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]" + ``` - main: -``` +```bash clojure -M -m starfederation.datastar.clojure.sdk-test.main ``` + +- start go binary running the tests + +```bash +go run github.com/starfederation/datastar/sdk/tests/cmd/datastar-sdk-tests@latest +``` + +More information here: [SDKs' common tests](https://github.com/starfederation/datastar/tree/develop/sdk/tests). diff --git a/sdk-tests/deps.edn b/sdk-tests/deps.edn index 251f2c1..852ba9b 100644 --- a/sdk-tests/deps.edn +++ b/sdk-tests/deps.edn @@ -1,7 +1,8 @@ {:paths ["src/main"] - :deps {datastar/sdk {:local/root "../sdk"} - datastar/ring {:local/root "../sdk-adapter-ring"} + :deps {datastar/sdk {:local/root "../libraries/sdk/"} + datastar/ring {:local/root "../libraries/sdk-ring/" + :exclusions [dev.data-star.clojure/sdk]} ring/ring-jetty-adapter {:mvn/version "1.13.0"} metosin/reitit {:mvn/version "0.7.2"} com.cnuernber/charred {:mvn/version "1.034"} diff --git a/sdk/README.md b/sdk/README.md deleted file mode 100644 index 3b3be11..0000000 --- a/sdk/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Generic Clojure SDK for Datastar - -This is where the code for the Generic SDK lives. - -## Installation - -Install using clojars deps coordinates: - -[![Clojars Project](https://img.shields.io/clojars/v/dev.data-star.clojure/sdk.svg)](https://clojars.org/dev.data-star.clojure/sdk) diff --git a/src/bb-example/bb.edn b/src/bb-example/bb.edn index 7a636b7..1d979f0 100644 --- a/src/bb-example/bb.edn +++ b/src/bb-example/bb.edn @@ -1,7 +1,8 @@ {:paths ["src/main" - "../../sdk/src/main" - "../../sdk-adapter-http-kit/src/main/" - "../../sdk-malli-schemas/src/main"] + "../../libraries/sdk/src/main" + "../../libraries/sdk-http-kit/src/main/" + "../../libraries/sdk-http-kit-malli-schemas/src/main/" + "../../libraries/sdk-malli-schemas/src/main"] :deps {metosin/malli {:mvn/version "0.17.0"} org.clojars.askonomm/ruuter {:mvn/version "1.3.5"} ring/ring-core {:mvn/version "1.14.2"}}} diff --git a/src/bb/tasks.clj b/src/bb/tasks.clj index 11552ad..fd5f057 100644 --- a/src/bb/tasks.clj +++ b/src/bb/tasks.clj @@ -4,6 +4,7 @@ [clojure.string :as string] [clojure.edn :as edn])) + ;; ----------------------------------------------------------------------------- ;; Clojure cli invocation helpers ;; ----------------------------------------------------------------------------- @@ -37,6 +38,15 @@ (defn clojure + "Invoke the clojure cli. + + Arg keys: + - `:dir`: directory in which to invoke the cli + - `:X`: clojure `-X` option (seq of deps keywords aliases) + - `:M`: clojure `-X` option (seq of deps keywords aliases) + - `:main-ns`: namespace of the main function + - `:args-str`: additional args for the cli + " {:arglists '([{:keys [X M main-ns args-str dir]}])} [{:as args}] (let [invocation (-> args @@ -49,6 +59,13 @@ (defn bb + "Invoke the babashka cli. + + Arg keys: + - `:dir`: directory in which to invoke the cli + - `:main-ns`: namespace of the main function + - `:args-str`: additional args for the cli + " {:arglists '([{:keys [main-ns args-str]}])} [{:as args}] (-> args @@ -69,13 +86,16 @@ :malli-schemas :sdk-brotli]) + (defn arg->kw [s] (if (string/starts-with? s ":") (keyword (subs s 1)) (keyword s))) -(defn dev [& aliases] +(defn dev + "Start a clojure repl with deps `aliases`." + [& aliases] (let [aliases (-> dev-aliases (into aliases) (into (map arg->kw *command-line-args*)))] @@ -83,13 +103,15 @@ :main-ns 'nrepl.cmdline :args-str " --middleware \"[cider.nrepl/cider-middleware]\""}))) -(defn dev-bb [& [addr]] + +(defn dev-bb + "Start a babashka repl." + [& [addr]] (let [addr (or addr (first *command-line-args*))] (bb {:args-str (str " nrepl-server" (when addr (str " " addr)))}))) - ;; ----------------------------------------------------------------------------- ;; Helpers tasks for tests ;; ----------------------------------------------------------------------------- @@ -114,7 +136,7 @@ :main-ns 'lazytest.main :args-str (string/join " " (conj (named-paths->dirs named-paths) - args))}) + (string/join " " args)))}) (defn lazytest [aliases paths-aliases & args] @@ -130,49 +152,11 @@ lazytest-invocation bb)) + (defn start-test-server [] (clojure {:dir "sdk-tests" :main-ns 'starfederation.datastar.clojure.sdk-test.main})) -;; ----------------------------------------------------------------------------- -;; Build tasks -;; ----------------------------------------------------------------------------- -(def sdk-dir "sdk") -(def sdk-adapter-http-kit-dir "sdk-adapter-http-kit") -(def sdk-adapter-ring-dir "sdk-adapter-ring") -(def sdk-brotli-dir "sdk-brotli") -(def sdk-malli-schemas-dir "sdk-malli-schemas") - -(def sdk-lib-dirs - [sdk-dir - sdk-adapter-ring-dir - sdk-adapter-http-kit-dir - sdk-brotli-dir - sdk-malli-schemas-dir]) - - -(defn lib-jar! [dir] - (t/clojure {:dir dir} "-T:build jar")) - - -(defn lib-install! [dir] - (t/clojure {:dir dir} "-T:build install")) - - -(defn lib-clean! [dir] - (t/clojure {:dir dir} "-T:build clean")) - - -(defn lib-bump! [dir component] - (when-not (contains? #{"major" "minor" "patch"} component) - (println (str "ERROR: First argument must be one of: major, minor, patch. Got: " (or component "nil"))) - (System/exit 1)) - (t/shell {:dir dir} (str "neil version " component " --no-tag"))) - - -(defn lib-set-version! [dir version] - (t/shell {:dir dir} (str "neil version set " version " --no-tag"))) - -(defn lib-publish! [dir] - (t/clojure {:dir dir} "-T:build deploy")) +(defn run-go-tests [] + (t/shell "go run github.com/starfederation/datastar/sdk/tests/cmd/datastar-sdk-tests@latest")) diff --git a/src/bb/tasks/build.clj b/src/bb/tasks/build.clj new file mode 100644 index 0000000..a6ec191 --- /dev/null +++ b/src/bb/tasks/build.clj @@ -0,0 +1,167 @@ +(ns tasks.build + (:require + [babashka.fs :as fs] + [babashka.tasks :as t] + [borkdude.rewrite-edn :as r] + [clojure.edn :as edn] + [clojure.set :as set])) + +;; ----------------------------------------------------------------------------- +;; Util +;; ----------------------------------------------------------------------------- +(def sdk-dir "libraries/sdk") +(def sdk-brotli-dir "libraries/sdk-brotli") +(def sdk-adapter-http-kit-dir "libraries/sdk-http-kit") +(def sdk-adapter-http-kit-malli-schemas-dir "libraries/sdk-http-kit-malli-schemas") +(def sdk-adapter-ring-dir "libraries/sdk-ring") +(def sdk-adapter-ring-malli-schemas-dir "libraries/sdk-ring-malli-schemas") +(def sdk-malli-schemas-dir "libraries/sdk-malli-schemas") + +;; Carrefull order matters because of interdepencies +(def sdk-lib-dirs + [sdk-dir + sdk-brotli-dir + sdk-adapter-http-kit-dir + sdk-adapter-ring-dir + + sdk-malli-schemas-dir + sdk-adapter-http-kit-malli-schemas-dir + sdk-adapter-ring-malli-schemas-dir]) + + +(def sdk-lib-maven-names + '#{dev.data-star.clojure/sdk + dev.data-star.clojure/brotli + dev.data-star.clojure/http-kit + dev.data-star.clojure/http-kit-malli-schemas + dev.data-star.clojure/malli-schemas + dev.data-star.clojure/ring + dev.data-star.clojure/ring-malli-schemas}) + +(def lib-dir->deps + {sdk-brotli-dir + ['dev.data-star.clojure/sdk] + + sdk-adapter-http-kit-dir + ['dev.data-star.clojure/sdk] + + sdk-adapter-http-kit-malli-schemas-dir + ['dev.data-star.clojure/sdk + 'dev.data-star.clojure/malli-schemas + 'dev.data-star.clojure/http-kit] + + sdk-adapter-ring-dir + ['dev.data-star.clojure/sdk] + + sdk-adapter-ring-malli-schemas-dir + ['dev.data-star.clojure/sdk + 'dev.data-star.clojure/malli-schemas + 'dev.data-star.clojure/http-kit] + + sdk-malli-schemas-dir + ['dev.data-star.clojure/sdk]}) + + +(def maven-dir + (str (fs/path (fs/home) ".m2" "repository" "dev" "data-star" "clojure"))) + + +(defn clean-maven-dir! + "Deletes `~/.m2/repository/dev/data-star/clojure`." + [] + (println "-------------") + (println "Deleting:" maven-dir) + (println "-------------") + (fs/delete-tree maven-dir)) + + +;; ----------------------------------------------------------------------------- +;; Tasks +;; ----------------------------------------------------------------------------- +(defn update-deps-version [deps-map lib-dir version] + (if-let [deps (lib-dir->deps lib-dir)] + (reduce (fn [deps-map dep] + (r/assoc-in deps-map [:deps dep] {:mvn/version version})) + deps-map + deps) + deps-map)) + + +(defn get-interdependencies [deps-map] + (-> deps-map + r/sexpr + (get :deps) + keys + set + (set/intersection sdk-lib-maven-names))) + + +(defn update-inter-deps-versions [deps-map version] + (reduce (fn [deps-map lib-maven-name] + (r/assoc-in deps-map [:deps lib-maven-name] {:mvn/version version})) + deps-map + (get-interdependencies deps-map))) + + +(defn ->deps-file [lib-dir] + (-> lib-dir + (fs/path "deps.edn") + str)) + + +(defn assoc-deps! + "Adds libraries interdependencies in deps.edn files" + [lib-dir version] + (let [deps-file (->deps-file lib-dir)] + (-> deps-file + slurp + r/parse-string + (update-inter-deps-versions version) + str + (->> (spit deps-file))))) + + +(defn current-version [] + (-> (t/shell {:dir sdk-dir :out :string} "neil" "version") + :out + edn/read-string + :project)) + + +(defn lib-bump! [dir component] + (when-not (contains? #{"major" "minor" "patch"} component) + (println (str "ERROR: First argument must be one of: major, minor, patch. Got: " (or component "nil"))) + (System/exit 1)) + + (t/shell {:dir dir} (str "neil version " component " --no-tag")) + + (assoc-deps! dir (current-version))) + + +(defn lib-set-version! [dir version] + (t/shell {:dir dir} (str "neil version set " version " --no-tag")) + + (assoc-deps! dir version)) + + +(defn lib-clean! [dir] + (t/clojure {:dir dir} "-T:build clean")) + + +(defn lib-jar! [dir] + (println "----------------") + (println "Building" dir) + (println "----------------") + (t/clojure {:dir dir} "-T:build jar")) + + +(defn lib-install! [dir] + (println "----------------") + (println "Installing" dir) + (println "----------------") + (t/clojure {:dir dir} "-T:build install")) + + +(defn lib-publish! [dir] + (t/clojure {:dir dir} "-T:build deploy")) + diff --git a/src/bb/tasks/cljdoc.clj b/src/bb/tasks/cljdoc.clj new file mode 100644 index 0000000..7e748d3 --- /dev/null +++ b/src/bb/tasks/cljdoc.clj @@ -0,0 +1,84 @@ +(ns tasks.cljdoc + (:require + [babashka.fs :as fs] + [babashka.tasks :as t] + [clojure.string :as string] + [tasks.build :as build])) + + +(def cljdoc-dir ".cljdoc-preview") + +(defn home-dir [] (str (fs/home))) +(defn cwd [] (str (fs/cwd))) + +(defn git-rev [] + (-> (t/shell {:out :string} "git" "rev-parse" "HEAD") + :out + string/trim)) + + +(defn try-docker-cmd [cmd] + (try + (t/shell {:out :string} cmd "--help") + cmd + (catch Exception _ nil))) + + +(def docker-cmd + (or (try-docker-cmd "docker") + (try-docker-cmd "podman"))) + + +(defn start-server! [] + (fs/create-dirs cljdoc-dir) + + (t/shell + docker-cmd "run" + "--rm" + "--publish" "8000:8000" + "--volume" (str (home-dir) "/.m2:/root/.m2") + "--volume" "./.cljdoc-preview:/app/data" + "--platform" "linux/amd64" + "cljdoc/cljdoc")) + + +(def libs + #{:sdk + :brotli + :http-kit + :http-kit-malli-schemas + :malli-schemas + :ring + :ring-malli-schemas}) + +(defn lib-arg->kw [lib] + (cond-> lib + (and (string? lib) (string/starts-with? lib ":")) + (subs 1) + + true + keyword)) + + +(defn ingest! [lib & {:keys [version] + :or {version (build/current-version)}}] + (let [lib (lib-arg->kw lib)] + (if (contains? libs lib) + (t/shell + docker-cmd "run" + "--rm" + "--volume" (str (home-dir) "/.m2:/root/.m2") + "--volume" (str (cwd) ":/repo-to-import") + "--volume" "./.cljdoc-preview:/app/data" + "--platform" "linux/amd64" + "--entrypoint" "clojure" + "cljdoc/cljdoc" "-Sforce" "-M:cli" "ingest" + "--project" (str "dev.data-star.clojure/" (name lib)) + "--version" (str version) + "--git" "/repo-to-import" + "--rev" (git-rev)) + (println "Can't ingest " lib ", unrecognized")))) + + +(defn clean! [] + (fs/delete-tree cljdoc-dir)) diff --git a/src/dev/examples/form_behavior/core.clj b/src/dev/examples/form_behavior/core.clj index 618f734..17bed11 100644 --- a/src/dev/examples/form_behavior/core.clj +++ b/src/dev/examples/form_behavior/core.clj @@ -13,7 +13,6 @@ ;; Trying out several way we might rightly and wrongly use html forms -;; TODO: still need to figure out some things (defn result-area [value] (hc/compile diff --git a/src/dev/examples/http_kit2/animation.clj b/src/dev/examples/http_kit2/animation.clj index c5684f3..de09c06 100644 --- a/src/dev/examples/http_kit2/animation.clj +++ b/src/dev/examples/http_kit2/animation.clj @@ -88,5 +88,3 @@ (u/reboot-hk-server! #'handler-http-kit) (u/reboot-jetty-server! #'handler-ring {:async? true})) - - diff --git a/src/dev/examples/http_kit2/form_behavior.clj b/src/dev/examples/http_kit2/form_behavior.clj index 6f708ed..39bdc0d 100644 --- a/src/dev/examples/http_kit2/form_behavior.clj +++ b/src/dev/examples/http_kit2/form_behavior.clj @@ -13,7 +13,6 @@ ;; Trying out several way we might rightly and wrongly use html forms -;; TODO: still need to figure out some things (defn result-area [value] (hc/compile diff --git a/src/test/core-sdk/starfederation/datastar/clojure/api_test.clj b/src/test/core-sdk/starfederation/datastar/clojure/api_test.clj index bbfd1be..8e357ec 100644 --- a/src/test/core-sdk/starfederation/datastar/clojure/api_test.clj +++ b/src/test/core-sdk/starfederation/datastar/clojure/api_test.clj @@ -72,9 +72,9 @@ (defdescribe test-common-sse-opts - (basic-test d*/patch-elements! "" patch-element-t []) - (basic-test d*/patch-elements-seq! [] patch-element-t []) - (basic-test d*/patch-signals! "" patch-signals-t [])) + (basic-test #'d*/patch-elements! "" patch-element-t []) + (basic-test #'d*/patch-elements-seq! [] patch-element-t []) + (basic-test #'d*/patch-signals! "" patch-signals-t [])) (comment