├── .gitattributes
├── .github
├── CODEOWNERS
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug-report.yaml
│ ├── config.yml
│ ├── feature-request.yaml
│ └── support-request.yaml
└── workflows
│ ├── build-docker-images.yml
│ ├── clojure-sdk.yml
│ ├── deploy-site.yml
│ ├── enforce-branch-policy.yml
│ ├── java-sdk-unit-tests.yml
│ ├── sdk-dotnet-nuget.yml
│ └── tests.yml
├── .gitignore
├── .vscode
├── extensions.json
├── launch.json
├── settings.json
└── tasks.json
├── BUILDING.md
├── CHANGELOG.md
├── CONTRIBUTING.md
├── DOCKER.md
├── Dockerfile
├── Dockerfile-dev
├── LICENSE
├── Makefile
├── README.md
├── Taskfile.yml
├── VERSION
├── biome.json
├── build
├── .gitignore
├── cmd
│ └── build
│ │ └── main.go
├── consts.go
├── consts_clojure.qtpl
├── consts_datastar_client.qtpl
├── consts_datastar_readme.qtpl
├── consts_fsharp.qtpl
├── consts_go.qtpl
├── consts_haskell.qtpl
├── consts_hello_world.qtpl
├── consts_java.qtpl
├── consts_php.qtpl
├── consts_python.qtpl
├── consts_ruby.qtpl
├── consts_rust.qtpl
├── consts_typescript.qtpl
├── consts_zig.qtpl
└── run.go
├── bundles
├── datastar-aliased.js
├── datastar-aliased.js.map
├── datastar-core.js
├── datastar-core.js.map
├── datastar.js
└── datastar.js.map
├── examples
├── clojure
│ └── hello-world
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── deps.edn
│ │ ├── resources
│ │ └── public
│ │ │ └── hello-world.html
│ │ └── src
│ │ ├── dev
│ │ └── user.clj
│ │ └── main
│ │ └── example
│ │ ├── core.clj
│ │ ├── main.clj
│ │ ├── server.clj
│ │ └── utils.clj
├── dotnet
│ ├── .gitignore
│ └── csharp
│ │ └── HelloWorld
│ │ ├── HelloWorld.csproj
│ │ ├── Program.cs
│ │ ├── Properties
│ │ └── launchSettings.json
│ │ ├── appsettings.Development.json
│ │ ├── appsettings.json
│ │ └── wwwroot
│ │ └── hello-world.html
├── go
│ └── hello-world
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── hello-world.html
│ │ └── main.go
├── haskell
│ └── hello-world
│ │ ├── Main.hs
│ │ └── hello-world.html
├── java
│ └── hello-world
│ │ ├── .gitignore
│ │ ├── pom.xml
│ │ └── src
│ │ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ │ └── example
│ │ │ │ ├── Main.java
│ │ │ │ └── servlets
│ │ │ │ ├── HelloWorldServlet.java
│ │ │ │ └── HtmlServlet.java
│ │ └── resources
│ │ │ └── hello-world.html
│ │ └── test
│ │ └── java
│ │ └── org
│ │ └── example
│ │ └── AppTest.java
├── php
│ └── hello-world
│ │ ├── composer.json
│ │ └── public
│ │ ├── hello-world.html
│ │ └── hello-world.php
├── python
│ ├── django
│ │ ├── README.md
│ │ ├── datastar
│ │ │ ├── __init__.py
│ │ │ ├── asgi.py
│ │ │ ├── settings.py
│ │ │ ├── urls.py
│ │ │ └── wsgi.py
│ │ ├── db.sqlite3
│ │ ├── ds
│ │ │ ├── __init__.py
│ │ │ ├── admin.py
│ │ │ ├── apps.py
│ │ │ ├── migrations
│ │ │ │ └── __init__.py
│ │ │ ├── models.py
│ │ │ ├── tests.py
│ │ │ └── views.py
│ │ ├── manage.py
│ │ └── pyproject.toml
│ ├── fastapi
│ │ └── app.py
│ ├── fasthtml
│ │ ├── advanced.py
│ │ └── simple.py
│ ├── litestar
│ │ └── app.py
│ ├── pyproject.toml
│ ├── quart
│ │ └── app.py
│ └── sanic
│ │ └── app.py
├── ruby
│ ├── hello-world
│ │ ├── Gemfile
│ │ ├── Gemfile.lock
│ │ ├── hello-world.html
│ │ └── hello-world.ru
│ └── threads
│ │ ├── Gemfile
│ │ ├── Gemfile.lock
│ │ └── threads.ru
├── rust
│ ├── axum
│ │ └── hello-world
│ │ │ ├── .gitignore
│ │ │ ├── Cargo.toml
│ │ │ ├── Makefile
│ │ │ ├── hello-world.html
│ │ │ └── src
│ │ │ └── main.rs
│ ├── makefile.defs
│ ├── rama
│ │ └── hello-world
│ │ │ ├── .gitignore
│ │ │ ├── Cargo.toml
│ │ │ ├── Makefile
│ │ │ ├── hello-world.html
│ │ │ └── src
│ │ │ └── main.rs
│ └── rocket
│ │ └── hello-world
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ ├── hello-world.html
│ │ └── src
│ │ └── main.rs
└── zig
│ ├── httpz
│ └── hello-world
│ │ ├── .gitignore
│ │ ├── build.zig
│ │ ├── build.zig.zon
│ │ └── src
│ │ ├── hello-world.html
│ │ └── main.zig
│ └── tokamak
│ └── hello-world
│ ├── .gitignore
│ ├── build.zig
│ ├── build.zig.zon
│ ├── hello-world.html
│ └── src
│ └── main.zig
├── fly.toml
├── go.mod
├── go.sum
├── library
├── .gitignore
├── README.md
├── package.json
├── pnpm-lock.yaml
├── src
│ ├── bundles
│ │ ├── datastar-aliased.ts
│ │ ├── datastar-core.ts
│ │ └── datastar.ts
│ ├── engine
│ │ ├── consts.ts
│ │ ├── engine.ts
│ │ ├── errors.ts
│ │ ├── index.ts
│ │ ├── signals.ts
│ │ └── types.ts
│ ├── index.ts
│ ├── plugins
│ │ ├── index.ts
│ │ └── official
│ │ │ ├── backend
│ │ │ ├── actions
│ │ │ │ ├── delete.ts
│ │ │ │ ├── get.ts
│ │ │ │ ├── patch.ts
│ │ │ │ ├── post.ts
│ │ │ │ ├── put.ts
│ │ │ │ └── sse.ts
│ │ │ ├── attributes
│ │ │ │ └── indicator.ts
│ │ │ ├── shared.ts
│ │ │ └── watchers
│ │ │ │ ├── executeScript.ts
│ │ │ │ ├── mergeFragments.ts
│ │ │ │ ├── mergeSignals.ts
│ │ │ │ ├── removeFragments.ts
│ │ │ │ └── removeSignals.ts
│ │ │ ├── browser
│ │ │ ├── actions
│ │ │ │ └── clipboard.ts
│ │ │ └── attributes
│ │ │ │ ├── customValidity.ts
│ │ │ │ ├── onIntersect.ts
│ │ │ │ ├── onInterval.ts
│ │ │ │ ├── onLoad.ts
│ │ │ │ ├── onRaf.ts
│ │ │ │ ├── onSignalChange.ts
│ │ │ │ ├── persist.ts
│ │ │ │ ├── replaceUrl.ts
│ │ │ │ ├── scrollIntoView.ts
│ │ │ │ └── viewTransition.ts
│ │ │ ├── core
│ │ │ └── attributes
│ │ │ │ ├── computed.ts
│ │ │ │ ├── signals.ts
│ │ │ │ └── star.ts
│ │ │ ├── dom
│ │ │ └── attributes
│ │ │ │ ├── attr.ts
│ │ │ │ ├── bind.ts
│ │ │ │ ├── class.ts
│ │ │ │ ├── on.ts
│ │ │ │ ├── ref.ts
│ │ │ │ ├── show.ts
│ │ │ │ └── text.ts
│ │ │ └── logic
│ │ │ └── actions
│ │ │ ├── fit.ts
│ │ │ ├── setAll.ts
│ │ │ └── toggleAll.ts
│ ├── utils
│ │ ├── dom.ts
│ │ ├── paths.ts
│ │ ├── tags.ts
│ │ ├── text.ts
│ │ ├── timing.ts
│ │ └── view-transtions.ts
│ └── vendored
│ │ ├── fetch-event-source.ts
│ │ ├── idiomorph.esm.d.ts
│ │ ├── idiomorph.esm.js
│ │ └── preact-core.ts
└── tsconfig.json
├── sdk
├── README.md
├── clojure
│ ├── .clj-kondo
│ │ ├── config.edn
│ │ └── hooks
│ │ │ └── test_hooks.clj
│ ├── .gitignore
│ ├── CHANGELOG.md
│ ├── README.md
│ ├── adapter-http-kit
│ │ ├── README.md
│ │ ├── build.clj
│ │ ├── deps.edn
│ │ └── src
│ │ │ └── main
│ │ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── clojure
│ │ │ └── adapter
│ │ │ ├── http_kit.clj
│ │ │ └── http_kit
│ │ │ └── impl.clj
│ ├── adapter-ring
│ │ ├── README.md
│ │ ├── build.clj
│ │ ├── deps.edn
│ │ └── src
│ │ │ └── main
│ │ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── clojure
│ │ │ └── adapter
│ │ │ ├── ring.clj
│ │ │ └── ring
│ │ │ └── impl.clj
│ ├── bb.edn
│ ├── deps.edn
│ ├── doc
│ │ ├── SSE-design-notes.md
│ │ ├── Write-profiles.md
│ │ ├── implementing-adapters.md
│ │ └── maintainers-guide.md
│ ├── malli-schemas
│ │ ├── README.md
│ │ ├── deps.edn
│ │ └── src
│ │ │ └── main
│ │ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── clojure
│ │ │ ├── adapter
│ │ │ ├── common_schemas.clj
│ │ │ ├── http_kit_schemas.clj
│ │ │ └── ring_schemas.clj
│ │ │ ├── api
│ │ │ ├── common_schemas.clj
│ │ │ ├── fragments_schemas.clj
│ │ │ ├── scripts_schemas.clj
│ │ │ ├── signals_schemas.clj
│ │ │ └── sse_schemas.clj
│ │ │ └── api_schemas.clj
│ ├── sdk-tests
│ │ ├── README.md
│ │ ├── deps.edn
│ │ └── src
│ │ │ ├── dev
│ │ │ └── user.clj
│ │ │ └── main
│ │ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── clojure
│ │ │ └── sdk_test
│ │ │ ├── core.clj
│ │ │ └── main.clj
│ ├── sdk
│ │ ├── README.md
│ │ ├── build.clj
│ │ ├── deps.edn
│ │ ├── resources
│ │ │ └── clj-kondo.exports
│ │ │ │ └── starfederation.datastar
│ │ │ │ └── clojure
│ │ │ │ └── config.edn
│ │ └── src
│ │ │ └── main
│ │ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── clojure
│ │ │ ├── adapter
│ │ │ ├── common.clj
│ │ │ └── test.clj
│ │ │ ├── api.clj
│ │ │ ├── api
│ │ │ ├── common.clj
│ │ │ ├── fragments.clj
│ │ │ ├── scripts.clj
│ │ │ ├── signals.clj
│ │ │ └── sse.clj
│ │ │ ├── consts.clj
│ │ │ ├── protocols.clj
│ │ │ └── utils.clj
│ └── src
│ │ ├── bb
│ │ └── tasks.clj
│ │ ├── dev
│ │ ├── examples
│ │ │ ├── animation_gzip.clj
│ │ │ ├── animation_gzip
│ │ │ │ ├── animation.clj
│ │ │ │ ├── brotli.clj
│ │ │ │ ├── handlers.clj
│ │ │ │ ├── rendering.clj
│ │ │ │ ├── state.clj
│ │ │ │ └── style.css
│ │ │ ├── broadcast_http_kit.clj
│ │ │ ├── broadcast_ring.clj
│ │ │ ├── common.clj
│ │ │ ├── data_dsl.clj
│ │ │ ├── faulty_event.clj
│ │ │ ├── form_behavior.clj
│ │ │ ├── http_kit_disconnect.clj
│ │ │ ├── jetty_disconnect.clj
│ │ │ ├── malli.clj
│ │ │ ├── multiple_fragments.clj
│ │ │ ├── redirect.clj
│ │ │ ├── remove_fragments.clj
│ │ │ ├── scripts.clj
│ │ │ ├── snippets.clj
│ │ │ ├── snippets
│ │ │ │ ├── load_more.clj
│ │ │ │ ├── polling1.clj
│ │ │ │ ├── polling2.clj
│ │ │ │ ├── redirect1.clj
│ │ │ │ ├── redirect2.clj
│ │ │ │ └── redirect3.clj
│ │ │ ├── tiny_gzip.clj
│ │ │ └── utils.clj
│ │ └── user.clj
│ │ └── test
│ │ ├── adapter-common
│ │ └── test
│ │ │ ├── common.clj
│ │ │ ├── examples
│ │ │ ├── common.clj
│ │ │ ├── counter.clj
│ │ │ └── form.clj
│ │ │ └── utils.clj
│ │ ├── adapter-http-kit
│ │ ├── starfederation
│ │ │ └── datastar
│ │ │ │ └── clojure
│ │ │ │ └── adapter
│ │ │ │ └── http_kit
│ │ │ │ └── impl_test.clj
│ │ └── test
│ │ │ ├── examples
│ │ │ └── http_kit_handler.clj
│ │ │ └── http_kit_test.clj
│ │ ├── adapter-ring-jetty
│ │ └── test
│ │ │ └── ring_jetty_test.clj
│ │ ├── adapter-ring
│ │ ├── starfederation
│ │ │ └── datastar
│ │ │ │ └── clojure
│ │ │ │ └── adapter
│ │ │ │ └── ring
│ │ │ │ └── impl_test.clj
│ │ └── test
│ │ │ └── examples
│ │ │ └── ring_handler.clj
│ │ ├── adapter-rj9a
│ │ └── test
│ │ │ └── rj9a_test.clj
│ │ ├── core-sdk
│ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── clojure
│ │ │ ├── adapter
│ │ │ └── common_test.clj
│ │ │ └── api_test.clj
│ │ └── malli-schemas
│ │ └── test
│ │ └── api_schemas_test.clj
├── dotnet
│ ├── .gitignore
│ ├── Build.ps1
│ ├── README.md
│ ├── assets
│ │ └── datastar_icon.png
│ └── fsharp
│ │ └── src
│ │ ├── .gitattributes
│ │ ├── Consts.fs
│ │ ├── Datastar.FSharp.fsproj
│ │ ├── DependencyInjection
│ │ ├── ServerSentEventScriptExtensions.fs
│ │ ├── Services.fs
│ │ └── ServicesProvider.fs
│ │ ├── HttpHandlers.fs
│ │ ├── ModelBinding
│ │ ├── FromSignalAttribute.fs
│ │ ├── MvcServiceProvider.fs
│ │ └── SignalsModelBinder.fs
│ │ ├── Scripts
│ │ ├── BrowserConsole.fs
│ │ └── Redirect.fs
│ │ ├── ServerSentEventGenerator.fs
│ │ ├── Types.fs
│ │ └── Utility.fs
├── go
│ ├── README.md
│ ├── datastar
│ │ ├── .gitattributes
│ │ ├── consts.go
│ │ ├── execute-script-sugar.go
│ │ ├── execute.go
│ │ ├── fragments-sugar.go
│ │ ├── fragments.go
│ │ ├── fragments_test.go
│ │ ├── signals-sugar.go
│ │ ├── signals.go
│ │ ├── sse-compression.go
│ │ ├── sse.go
│ │ └── types.go
│ └── examples
│ │ ├── basic
│ │ └── main.go
│ │ └── hotreload
│ │ └── main.go
├── haskell
│ ├── CHANGELOG.md
│ ├── LICENSE.md
│ ├── Makefile
│ ├── README.md
│ ├── cabal.project
│ ├── datastar.cabal
│ ├── run
│ └── src
│ │ ├── ServerSentEventGenerator.hs
│ │ ├── ServerSentEventGenerator
│ │ ├── Class.hs
│ │ ├── Constants.hs
│ │ ├── Internal.hs
│ │ ├── Server
│ │ │ └── Snap.hs
│ │ └── Types.hs
│ │ ├── demo
│ │ ├── Main.hs
│ │ └── www
│ │ │ ├── index.html
│ │ │ └── keats.txt
│ │ └── test
│ │ └── Main.hs
├── java
│ ├── README.md
│ ├── core
│ │ ├── pom.xml
│ │ └── src
│ │ │ ├── main
│ │ │ └── java
│ │ │ │ └── starfederation
│ │ │ │ └── datastar
│ │ │ │ ├── Consts.java
│ │ │ │ ├── adapters
│ │ │ │ ├── request
│ │ │ │ │ ├── AbstractRequestAdapter.java
│ │ │ │ │ └── RequestAdapter.java
│ │ │ │ └── response
│ │ │ │ │ ├── AbstractResponseAdapter.java
│ │ │ │ │ └── ResponseAdapter.java
│ │ │ │ ├── enums
│ │ │ │ ├── EventType.java
│ │ │ │ └── FragmentMergeMode.java
│ │ │ │ ├── events
│ │ │ │ ├── AbstractBuilder.java
│ │ │ │ ├── AbstractDatastarEvent.java
│ │ │ │ ├── CustomEvent.java
│ │ │ │ ├── DatastarEvent.java
│ │ │ │ ├── ExecuteScript.java
│ │ │ │ ├── MergeFragments.java
│ │ │ │ ├── MergeSignals.java
│ │ │ │ ├── RemoveFragments.java
│ │ │ │ └── RemoveSignals.java
│ │ │ │ └── utils
│ │ │ │ ├── DataStore.java
│ │ │ │ ├── ServerSentEventGenerator.java
│ │ │ │ └── SignalReader.java
│ │ │ └── test
│ │ │ └── java
│ │ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── unit
│ │ │ ├── DataStoreTest.java
│ │ │ ├── ExecuteScriptTest.java
│ │ │ ├── MergeFragmentsTest.java
│ │ │ ├── MergeSignalsTest.java
│ │ │ ├── RemoveFragmentsTest.java
│ │ │ ├── RemoveSignalsTest.java
│ │ │ ├── ServerSentEventGeneratorTest.java
│ │ │ └── SignalReaderTest.java
│ ├── datastar-java-sdk-jaxrs
│ │ ├── pom.xml
│ │ └── src
│ │ │ ├── main
│ │ │ └── java
│ │ │ │ └── starfederation
│ │ │ │ └── datastar
│ │ │ │ └── adapters
│ │ │ │ ├── request
│ │ │ │ ├── HttpServletRequestAdapter.java
│ │ │ │ └── JaxRsRequestAdapter.java
│ │ │ │ └── response
│ │ │ │ ├── HttpServletResponseAdapter.java
│ │ │ │ └── JaxRsResponseAdapter.java
│ │ │ └── test
│ │ │ └── java
│ │ │ └── starfederation
│ │ │ └── datastar
│ │ │ └── adapter
│ │ │ └── unit
│ │ │ └── JaxRsRequestAdapterTest.java
│ └── pom.xml
├── php
│ ├── LICENSE.md
│ ├── README.md
│ ├── composer.json
│ └── src
│ │ ├── .gitattributes
│ │ ├── Consts.php
│ │ ├── ServerSentEventData.php
│ │ ├── ServerSentEventGenerator.php
│ │ ├── enums
│ │ ├── EventType.php
│ │ └── FragmentMergeMode.php
│ │ └── events
│ │ ├── EventInterface.php
│ │ ├── EventTrait.php
│ │ ├── ExecuteScript.php
│ │ ├── MergeFragments.php
│ │ ├── MergeSignals.php
│ │ ├── RemoveFragments.php
│ │ └── RemoveSignals.php
├── python
│ ├── README.md
│ ├── pyproject.toml
│ └── src
│ │ └── datastar_py
│ │ ├── __init__.py
│ │ ├── attributes.py
│ │ ├── consts.py
│ │ ├── django.py
│ │ ├── fastapi.py
│ │ ├── fasthtml.py
│ │ ├── litestar.py
│ │ ├── py.typed
│ │ ├── quart.py
│ │ ├── sanic.py
│ │ ├── sse.py
│ │ └── starlette.py
├── ruby
│ ├── .gitignore
│ ├── .rspec
│ ├── Gemfile
│ ├── Gemfile.lock
│ ├── LICENSE.md
│ ├── README.md
│ ├── Rakefile
│ ├── bin
│ │ ├── console
│ │ └── setup
│ ├── datastar.gemspec
│ ├── examples
│ │ └── test.ru
│ ├── lib
│ │ ├── datastar.rb
│ │ └── datastar
│ │ │ ├── async_executor.rb
│ │ │ ├── configuration.rb
│ │ │ ├── consts.rb
│ │ │ ├── dispatcher.rb
│ │ │ ├── rails_async_executor.rb
│ │ │ ├── rails_thread_executor.rb
│ │ │ ├── railtie.rb
│ │ │ ├── server_sent_event_generator.rb
│ │ │ └── version.rb
│ ├── sig
│ │ └── datastar.rbs
│ └── spec
│ │ ├── dispatcher_spec.rb
│ │ ├── spec_helper.rb
│ │ └── support
│ │ └── dispatcher_examples.rb
├── rust
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── Makefile
│ ├── README.md
│ └── src
│ │ ├── axum.rs
│ │ ├── consts.rs
│ │ ├── execute_script.rs
│ │ ├── lib.rs
│ │ ├── merge_fragments.rs
│ │ ├── merge_signals.rs
│ │ ├── rama.rs
│ │ ├── remove_fragments.rs
│ │ ├── remove_signals.rs
│ │ ├── rocket.rs
│ │ └── testing.rs
├── test
│ ├── .gitignore
│ ├── README.md
│ ├── get-cases
│ │ ├── executeScriptWithAllOptions
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── executeScriptWithDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── executeScriptWithMultilineScript
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── executeScriptWithoutDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeFragmentsWithAllOptions
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeFragmentsWithDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeFragmentsWithMultilineFragments
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeFragmentsWithoutDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeSignalsWithAllOptions
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeSignalsWithDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeSignalsWithMultilineSignals
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── mergeSignalsWithoutDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── removeFragmentsWithAllOptions
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── removeFragmentsWithDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── removeFragmentsWithoutDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── removeSignalsWithAllOptions
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ ├── removeSignalsWithDefaults
│ │ │ ├── input.json
│ │ │ └── output.txt
│ │ └── sendTwoEvents
│ │ │ ├── input.json
│ │ │ └── output.txt
│ ├── normalize.sh
│ ├── post-cases
│ │ └── readSignalsFromBody
│ │ │ ├── input.json
│ │ │ └── output.txt
│ ├── test-all.sh
│ ├── test-get.sh
│ └── test-post.sh
├── typescript
│ ├── .gitignore
│ ├── README.md
│ ├── build.ts
│ ├── deno.json
│ ├── deno.lock
│ ├── examples
│ │ ├── deno.ts
│ │ └── node.js
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── src
│ │ ├── abstractServerSentEventGenerator.ts
│ │ ├── consts.ts
│ │ ├── node
│ │ │ ├── node.ts
│ │ │ └── serverSentEventGenerator.ts
│ │ ├── types.ts
│ │ └── web
│ │ │ ├── deno.ts
│ │ │ └── serverSentEventGenerator.ts
│ └── tsconfig.json
└── zig
│ ├── .github
│ └── PULL_REQUEST_TEMPLATE.md
│ ├── .gitignore
│ ├── README.md
│ ├── build.zig
│ ├── build.zig.zon
│ ├── src
│ ├── ServerSentEventGenerator.zig
│ ├── consts.zig
│ ├── httpz
│ │ ├── ServerSentEventGenerator.zig
│ │ └── root.zig
│ ├── root.zig
│ ├── testing.zig
│ └── tokamak
│ │ ├── ServerSentEventGenerator.zig
│ │ └── root.zig
│ └── test_runner.zig
├── site
├── .gitignore
├── cmd
│ ├── asciiconvertor
│ │ └── main.go
│ └── site
│ │ ├── .gitignore
│ │ └── main.go
├── postcss.config.js
├── router.go
├── routes_bundler.go
├── routes_bundler.qtpl
├── routes_bundler.templ
├── routes_errors.go
├── routes_errors.templ
├── routes_errors_init.templ
├── routes_errors_internal.templ
├── routes_errors_runtime.templ
├── routes_essays.go
├── routes_examples.go
├── routes_examples_active_search.go
├── routes_examples_active_search.templ
├── routes_examples_animations.go
├── routes_examples_animations.templ
├── routes_examples_bad_apple.go
├── routes_examples_bulk_update.go
├── routes_examples_bulk_update.templ
├── routes_examples_click_to_edit.go
├── routes_examples_click_to_edit.templ
├── routes_examples_click_to_load.go
├── routes_examples_click_to_load.templ
├── routes_examples_csrf.go
├── routes_examples_csrf.templ
├── routes_examples_custom_validity.go
├── routes_examples_dbmon.go
├── routes_examples_dbmon.templ
├── routes_examples_delete_row.go
├── routes_examples_delete_row.templ
├── routes_examples_dialogs_browser.go
├── routes_examples_dialogs_browser.templ
├── routes_examples_disable_button.go
├── routes_examples_dispatch_custom_event.go
├── routes_examples_edit_row.go
├── routes_examples_edit_row.templ
├── routes_examples_execute_script.go
├── routes_examples_file_upload.go
├── routes_examples_file_upload.templ
├── routes_examples_form_data.go
├── routes_examples_indicator.go
├── routes_examples_indicator.templ
├── routes_examples_infinite_scroll.go
├── routes_examples_infinite_scroll.templ
├── routes_examples_inline_validation.go
├── routes_examples_inline_validation.templ
├── routes_examples_lazy_load.go
├── routes_examples_lazy_load.templ
├── routes_examples_lazy_tabs.go
├── routes_examples_lazy_tabs.templ
├── routes_examples_merge_options.go
├── routes_examples_merge_options.templ
├── routes_examples_model_bindings.go
├── routes_examples_model_bindings.templ
├── routes_examples_offline_sync.go
├── routes_examples_on_load.go
├── routes_examples_on_load.templ
├── routes_examples_polling.go
├── routes_examples_prefetch.go
├── routes_examples_prefetch.templ
├── routes_examples_progress_bar.go
├── routes_examples_progress_bar.templ
├── routes_examples_quick_primer_go.go
├── routes_examples_quick_primer_go.templ
├── routes_examples_quiz.go
├── routes_examples_quiz_slow.go
├── routes_examples_redirects.go
├── routes_examples_redirects.templ
├── routes_examples_replace_url.go
├── routes_examples_scroll_into_view.go
├── routes_examples_scroll_into_view.templ
├── routes_examples_signals_changed.go
├── routes_examples_signals_ifmissing.go
├── routes_examples_templ_counter.go
├── routes_examples_templ_counter.templ
├── routes_examples_title_update_backend.go
├── routes_examples_toggle_visibility.go
├── routes_examples_toggle_visibility.templ
├── routes_examples_update_signals.go
├── routes_examples_value_select.go
├── routes_examples_value_select.templ
├── routes_examples_view_transition_api.go
├── routes_examples_view_transition_api.templ
├── routes_guide.go
├── routes_home.go
├── routes_home.templ
├── routes_how_tos.go
├── routes_how_tos_load_more.go
├── routes_how_tos_polling.go
├── routes_how_tos_redirect.go
├── routes_memes.go
├── routes_memes.templ
├── routes_reference.go
├── routes_tests.go
├── routes_tests_indicator.go
├── routes_tests_indicator_element_removed.go
├── routes_tests_merge_fragment.go
├── routes_tests_merge_fragment_input_value.go
├── routes_tests_merge_fragment_on_load.go
├── routes_tests_merge_fragment_outer_multiple_targets.go
├── routes_tests_merge_fragment_signals.go
├── routes_tests_merge_fragment_whitespace.go
├── routes_tests_on_load.go
├── routes_tests_remove_fragment.go
├── routes_tests_remove_initiating_fragment.go
├── routes_tests_sse_error_event.go
├── routes_tests_sse_events.go
├── routes_videos.go
├── routes_videos.templ
├── shared.templ
├── shared_partials.go
├── smoketests
│ ├── .gitignore
│ ├── active_search_test.go
│ ├── aliased_test.go
│ ├── animations_test.go
│ ├── attr_false_test.go
│ ├── attr_object_false_test.go
│ ├── bad_apple_test.go
│ ├── bind_keys_test.go
│ ├── bulk_update_test.go
│ ├── checkbox_array_test.go
│ ├── checkbox_boolean_checked_test.go
│ ├── checkbox_boolean_test.go
│ ├── checkbox_value_checked_test.go
│ ├── checkbox_value_test.go
│ ├── classes_test.go
│ ├── click_to_edit_test.go
│ ├── click_to_load_test.go
│ ├── cloak_test.go
│ ├── csrf_test.go
│ ├── custom_events_test.go
│ ├── custom_plugin_test.go
│ ├── dbmon_test.go
│ ├── delete_row_test.go
│ ├── dialogs_browser_test.go
│ ├── disable_button_test.go
│ ├── dispatch_custom_event_test.go
│ ├── edit_row_test.go
│ ├── execute_script_test.go
│ ├── file_upload_test.go
│ ├── helpers.go
│ ├── img_src_bind_test.go
│ ├── indicator_element_removed_test.go
│ ├── indicator_test.go
│ ├── infinite_scroll_test.go
│ ├── inline_validation_test.go
│ ├── input_array_test.go
│ ├── input_signal_test.go
│ ├── input_value_test.go
│ ├── key_casing_test.go
│ ├── lazy_load_test.go
│ ├── lazy_tabs_test.go
│ ├── local_signals_test.go
│ ├── merge_fragment_input_value_test.go
│ ├── merge_fragment_on_load_test.go
│ ├── merge_fragment_signals_test.go
│ ├── merge_fragment_test.go
│ ├── merge_fragment_whitespace_test.go
│ ├── merge_options_test.go
│ ├── model_binding_test.go
│ ├── multi_select_test.go
│ ├── multiline_expressions_test.go
│ ├── multiline_signals_test.go
│ ├── offline_sync_test.go
│ ├── on_load_delay_test.go
│ ├── on_load_test.go
│ ├── on_signal_change_path_once_test.go
│ ├── on_signal_change_path_test.go
│ ├── on_signal_change_path_wildcard_test.go
│ ├── on_signal_change_test.go
│ ├── persist_signals_path_test.go
│ ├── persist_signals_path_wildcard_test.go
│ ├── persist_signals_test.go
│ ├── persist_test.go
│ ├── plugin_name_prefix_test.go
│ ├── prefetch_test.go
│ ├── progress_bar_test.go
│ ├── radio_value_test.go
│ ├── raf_update_test.go
│ ├── redirects_test.go
│ ├── ref_test.go
│ ├── refs_test.go
│ ├── remove_fragment_test.go
│ ├── remove_initiating_fragment_test.go
│ ├── replace_url_from_backend_test.go
│ ├── replace_url_from_signals_test.go
│ ├── scroll_into_view_test.go
│ ├── select_multiple_test.go
│ ├── select_single_test.go
│ ├── session_storage_test.go
│ ├── set_all_path_test.go
│ ├── set_all_path_wildcard_test.go
│ ├── set_all_paths_test.go
│ ├── setup_test.go
│ ├── signals_ifmissing_test.go
│ ├── sortable_test.go
│ ├── sse_error_event_test.go
│ ├── sse_events_test.go
│ ├── templ_counter_test.go
│ ├── title_update_backend_test.go
│ ├── todos_test.go
│ ├── toggle_all_path_test.go
│ ├── toggle_visibility_test.go
│ ├── update_signals_test.go
│ ├── value_select_test.go
│ ├── view_transition_api_test.go
│ └── web_component_test.go
├── src
│ └── css
│ │ └── site.css
├── static
│ ├── code_snippets
│ │ ├── getting_started
│ │ │ ├── multiple_events.clojuresnippet
│ │ │ ├── multiple_events.csharpsnippet
│ │ │ ├── multiple_events.gosnippet
│ │ │ ├── multiple_events.haskellsnippet
│ │ │ ├── multiple_events.phpsnippet
│ │ │ ├── multiple_events.rubysnippet
│ │ │ ├── multiple_events.rustsnippet
│ │ │ ├── multiple_events.typescriptsnippet
│ │ │ ├── multiple_events.zigsnippet
│ │ │ ├── setup.clojuresnippet
│ │ │ ├── setup.csharpsnippet
│ │ │ ├── setup.gosnippet
│ │ │ ├── setup.haskellsnippet
│ │ │ ├── setup.phpsnippet
│ │ │ ├── setup.rubysnippet
│ │ │ ├── setup.rustsnippet
│ │ │ ├── setup.typescriptsnippet
│ │ │ └── setup.zigsnippet
│ │ ├── going_deeper
│ │ │ ├── multiple_events.clojuresnippet
│ │ │ ├── multiple_events.csharpsnippet
│ │ │ ├── multiple_events.gosnippet
│ │ │ ├── multiple_events.haskellsnippet
│ │ │ ├── multiple_events.phpsnippet
│ │ │ ├── multiple_events.rubysnippet
│ │ │ ├── multiple_events.rustsnippet
│ │ │ ├── multiple_events.typescriptsnippet
│ │ │ └── multiple_events.zigsnippet
│ │ └── how_tos
│ │ │ ├── load_more.clojuresnippet
│ │ │ ├── load_more.csharpsnippet
│ │ │ ├── load_more.gosnippet
│ │ │ ├── load_more.phpsnippet
│ │ │ ├── polling_1.clojuresnippet
│ │ │ ├── polling_1.csharpsnippet
│ │ │ ├── polling_1.gosnippet
│ │ │ ├── polling_1.haskellsnippet
│ │ │ ├── polling_1.phpsnippet
│ │ │ ├── polling_1.rubysnippet
│ │ │ ├── polling_1.rustsnippet
│ │ │ ├── polling_1.typescriptsnippet
│ │ │ ├── polling_1.zigsnippet
│ │ │ ├── polling_2.clojuresnippet
│ │ │ ├── polling_2.csharpsnippet
│ │ │ ├── polling_2.gosnippet
│ │ │ ├── polling_2.haskellsnippet
│ │ │ ├── polling_2.phpsnippet
│ │ │ ├── polling_2.rubysnippet
│ │ │ ├── polling_2.rustsnippet
│ │ │ ├── polling_2.typescriptsnippet
│ │ │ ├── polling_2.zigsnippet
│ │ │ ├── redirect_1.clojuresnippet
│ │ │ ├── redirect_1.csharpsnippet
│ │ │ ├── redirect_1.gosnippet
│ │ │ ├── redirect_1.haskellsnippet
│ │ │ ├── redirect_1.phpsnippet
│ │ │ ├── redirect_1.rubysnippet
│ │ │ ├── redirect_1.rustsnippet
│ │ │ ├── redirect_1.typescriptsnippet
│ │ │ ├── redirect_1.zigsnippet
│ │ │ ├── redirect_2.clojuresnippet
│ │ │ ├── redirect_2.csharpsnippet
│ │ │ ├── redirect_2.gosnippet
│ │ │ ├── redirect_2.haskellsnippet
│ │ │ ├── redirect_2.phpsnippet
│ │ │ ├── redirect_2.rubysnippet
│ │ │ ├── redirect_2.rustsnippet
│ │ │ ├── redirect_2.typescriptsnippet
│ │ │ ├── redirect_2.zigsnippet
│ │ │ ├── redirect_3.clojuresnippet
│ │ │ ├── redirect_3.csharpsnippet
│ │ │ ├── redirect_3.gosnippet
│ │ │ ├── redirect_3.phpsnippet
│ │ │ ├── redirect_3.rubysnippet
│ │ │ └── redirect_3.zigsnippet
│ ├── css
│ │ └── .gitignore
│ ├── favicon
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ └── site.webmanifest
│ ├── images
│ │ ├── badapple.zst
│ │ ├── datastar.svg
│ │ ├── datastar_icon.svg
│ │ ├── essays
│ │ │ ├── datastar_dependencies.png
│ │ │ └── fullstack.jpg
│ │ ├── examples
│ │ │ └── tokyo.png
│ │ ├── fujs.svg
│ │ ├── memes
│ │ │ ├── bender.png
│ │ │ ├── bigsky.png
│ │ │ ├── both.png
│ │ │ ├── club.png
│ │ │ ├── compile_time.png
│ │ │ ├── crap.png
│ │ │ ├── force_feed.png
│ │ │ ├── history.png
│ │ │ ├── hypermedia.png
│ │ │ ├── one.png
│ │ │ ├── only_clicks.png
│ │ │ ├── polling.png
│ │ │ ├── remember.png
│ │ │ ├── rule7b.png
│ │ │ ├── sse_vs_xhr.png
│ │ │ ├── target_id_not_found.png
│ │ │ └── use_datastar.png
│ │ ├── rocket-circle.png
│ │ ├── rocket-social-preview-white.png
│ │ ├── rocket-social-preview.png
│ │ ├── rocket.gif
│ │ ├── rocket.png
│ │ ├── rocket.svg
│ │ └── rocket.webp
│ ├── js
│ │ ├── .gitignore
│ │ ├── sortable.js
│ │ └── web_component.js
│ └── md
│ │ ├── essays
│ │ ├── another_dependency.md
│ │ ├── event_streams_all_the_way_down.md
│ │ ├── grugs_around_fire.md
│ │ ├── haikus.md
│ │ ├── htmx_sucks.md
│ │ ├── i_am_a_teapot.md
│ │ ├── the_road_to_v1.md
│ │ ├── why_another_framework.md
│ │ └── yes_you_want_a_build_step.md
│ │ ├── examples
│ │ ├── active_search.md
│ │ ├── animations.md
│ │ ├── bad_apple.md
│ │ ├── bind_keys.md
│ │ ├── bulk_update.md
│ │ ├── classes.md
│ │ ├── click_outside.md
│ │ ├── click_to_edit.md
│ │ ├── click_to_load.md
│ │ ├── cloak.md
│ │ ├── csrf.md
│ │ ├── custom_events.md
│ │ ├── custom_validity.md
│ │ ├── dbmon.md
│ │ ├── debounce_and_throttle.md
│ │ ├── delete_row.md
│ │ ├── dialogs_browser.md
│ │ ├── disable_button.md
│ │ ├── dispatch_custom_event.md
│ │ ├── edit_row.md
│ │ ├── execute_script.md
│ │ ├── file_upload.md
│ │ ├── form_data.md
│ │ ├── ignore_attributes.md
│ │ ├── img_src_bind.md
│ │ ├── indicator.md
│ │ ├── infinite_scroll.md
│ │ ├── inline_validation.md
│ │ ├── invalid_signals.md
│ │ ├── key_casing.md
│ │ ├── lazy_load.md
│ │ ├── lazy_tabs.md
│ │ ├── merge_options.md
│ │ ├── model_binding.md
│ │ ├── multi_select.md
│ │ ├── multiline_expressions.md
│ │ ├── multiline_signals.md
│ │ ├── offline_sync.md
│ │ ├── on_load.md
│ │ ├── persist.md
│ │ ├── plugin_order.md
│ │ ├── polling.md
│ │ ├── prefetch.md
│ │ ├── progress_bar.md
│ │ ├── quick_primer_go.md
│ │ ├── raf_update.md
│ │ ├── redirects.md
│ │ ├── refs.md
│ │ ├── regex.md
│ │ ├── replace_url_from_backend.md
│ │ ├── replace_url_from_signals.md
│ │ ├── scroll_into_view.md
│ │ ├── session_storage.md
│ │ ├── signals_change.md
│ │ ├── signals_ifmissing.md
│ │ ├── signals_ifmissing_onload.md
│ │ ├── sortable.md
│ │ ├── templ_counter.md
│ │ ├── timing.md
│ │ ├── title_update_backend.md
│ │ ├── toggle_visibility.md
│ │ ├── update_signals.md
│ │ ├── value_select.md
│ │ ├── view_transition_api.md
│ │ ├── view_transition_on_click.md
│ │ └── web_component.md
│ │ ├── guide
│ │ ├── datastar_expressions.md
│ │ ├── getting_started.md
│ │ ├── going_deeper.md
│ │ └── stop_overcomplicating_it.md
│ │ ├── how_tos
│ │ ├── how_to_bind_keydown_events_to_specific_keys.md
│ │ ├── how_to_load_more_list_items.md
│ │ ├── how_to_poll_the_backend_at_regular_intervals.md
│ │ ├── how_to_redirect_the_page_from_the_backend.md
│ │ └── how_to_stream_sse_events_with_a_user_defined_delay.md
│ │ ├── reference
│ │ ├── action_plugins.md
│ │ ├── attribute_plugins.md
│ │ ├── custom_builds.md
│ │ ├── overview.md
│ │ ├── sdks.md
│ │ ├── security.md
│ │ └── sse_events.md
│ │ └── tests
│ │ ├── aliased.md
│ │ ├── attr_false.md
│ │ ├── attr_object_false.md
│ │ ├── checkbox_array.md
│ │ ├── checkbox_boolean.md
│ │ ├── checkbox_boolean_checked.md
│ │ ├── checkbox_value.md
│ │ ├── checkbox_value_checked.md
│ │ ├── custom_plugin.md
│ │ ├── indicator.md
│ │ ├── indicator_element_removed.md
│ │ ├── input_array.md
│ │ ├── input_signal.md
│ │ ├── input_value.md
│ │ ├── key_casing.md
│ │ ├── local_signals.md
│ │ ├── merge_fragment.md
│ │ ├── merge_fragment_containing_on_event.md
│ │ ├── merge_fragment_input_value.md
│ │ ├── merge_fragment_on_load.md
│ │ ├── merge_fragment_outer_multiple_targets.md
│ │ ├── merge_fragment_signals.md
│ │ ├── merge_fragment_whitespace.md
│ │ ├── on_load.md
│ │ ├── on_load_delay.md
│ │ ├── on_signal_change.md
│ │ ├── on_signal_change_path.md
│ │ ├── on_signal_change_path_once.md
│ │ ├── on_signal_change_path_wildcard.md
│ │ ├── persist_signals.md
│ │ ├── persist_signals_path.md
│ │ ├── persist_signals_path_wildcard.md
│ │ ├── plugin_name_prefix.md
│ │ ├── radio_value.md
│ │ ├── ref.md
│ │ ├── remove_fragment.md
│ │ ├── remove_initiating_fragment.md
│ │ ├── select_multiple.md
│ │ ├── select_single.md
│ │ ├── set_all_path.md
│ │ ├── set_all_path_wildcard.md
│ │ ├── set_all_paths.md
│ │ ├── sse_error_event.md
│ │ ├── sse_events.md
│ │ └── toggle_all_path.md
└── tailwind.config.js
└── tools
├── intellij-plugin
├── .github
│ ├── dependabot.yml
│ └── workflows
│ │ ├── build.yml
│ │ ├── release.yml
│ │ └── run-ui-tests.yml
├── .gitignore
├── .run
│ ├── Run Plugin.run.xml
│ ├── Run Tests.run.xml
│ └── Run Verifications.run.xml
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── build.gradle.kts
├── gradle.properties
├── gradle
│ ├── libs.versions.toml
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── qodana.yml
├── resources
│ └── img
│ │ └── datastar-intellij-plugin.png
├── schema.json
├── settings.gradle.kts
├── src
│ └── main
│ │ └── resources
│ │ ├── META-INF
│ │ ├── plugin.xml
│ │ └── pluginIcon.svg
│ │ ├── datastar-attributes.web-types.json
│ │ ├── datastar-icon.png
│ │ └── messages
│ │ └── MyBundle.properties
├── test.css
└── test.html
└── vscode-extension
├── .gitignore
├── LICENSE.md
├── README.md
├── package-lock.json
├── package.json
└── src
├── data-attributes.json
└── icon.png
/.gitattributes:
--------------------------------------------------------------------------------
1 |
2 | bundles linguist-generated=true
3 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @delaneyj @bencroker
2 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: starfederation
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
--------------------------------------------------------------------------------
/.github/workflows/enforce-branch-policy.yml:
--------------------------------------------------------------------------------
1 | name: Enforce Branch Policy
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 | push:
8 | branches:
9 | - main
10 | workflow_dispatch:
11 | jobs:
12 | enforce-branch-policy:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Enforce main branch pull request policy
16 | if: github.event_name == 'pull_request' && github.ref == 'refs/heads/main'
17 | run: |
18 | echo "Pull requests to the main branch are not allowed."
19 | exit 1
20 | - name: Enforce main branch push policy
21 | run: |
22 | echo "Push events to the main branch are allowed."
23 | exit 0
--------------------------------------------------------------------------------
/.github/workflows/java-sdk-unit-tests.yml:
--------------------------------------------------------------------------------
1 | name: Java SDK Unit Tests
2 |
3 | on:
4 | pull_request:
5 | paths:
6 | - 'sdk/java/**'
7 |
8 | jobs:
9 | test-java:
10 | runs-on: ubuntu-latest
11 | defaults:
12 | run:
13 | working-directory: ./sdk/java
14 | steps:
15 | - name: Checkout repository
16 | uses: actions/checkout@v4
17 |
18 | - name: Set up Java 17
19 | uses: actions/setup-java@v4
20 | with:
21 | distribution: 'temurin'
22 | java-version: '17'
23 |
24 | - name: Build and run tests
25 |
26 | run: mvn --batch-mode verify
27 |
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | tailwindcli
2 | datastar_site
3 | data
4 | .task
5 | .idea
6 | .DS_Store
7 | node_modules
8 | datastar-website
9 | *_bin
10 | *.qtpl.go
11 | */java/*/target/
12 | *.pyc
13 | __pycache__
14 | __debug_bin*
15 |
16 | # search index
17 | /data-star.bleve
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "jdinabox.quicktemplate-vscode",
4 | "golang.go",
5 | "a-h.templ"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "go.testTimeout": "200s",
3 | "go.coverOnSingleTestFile": true,
4 | "go.coverOnSingleTest": true,
5 | "editor.foldingStrategy": "indentation",
6 | "makefile.configureOnOpen": false,
7 | "editor.formatOnSave": true,
8 | "[typescript]": {
9 | "editor.defaultFormatter": "biomejs.biome"
10 | },
11 | "[json]": {
12 | "editor.defaultFormatter": "biomejs.biome"
13 | },
14 | "[html]": {
15 | "editor.formatOnSave": false
16 | },
17 | "[markdown]": {
18 | "editor.formatOnSave": false
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "type": "shell",
6 | "label": "build datastar",
7 | "command": "task",
8 | "args": [
9 | "support"
10 | ]
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker.io/golang:1.24.2-alpine AS build
2 |
3 | RUN apk add --no-cache upx
4 | ENV PORT=8080
5 |
6 | WORKDIR /src
7 | COPY . .
8 | RUN go mod download
9 | COPY site ./site
10 | RUN --mount=type=cache,target=/root/.cache/go-build \
11 | go build -ldflags="-s" -o /out/site site/cmd/site/main.go
12 | RUN upx -9 -k /out/site
13 |
14 | FROM alpine
15 | RUN chmod a=rwx,u+t /tmp
16 | COPY --from=build /out/site /
17 | ENTRYPOINT ["/site"]
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 1.0.0-beta.11
--------------------------------------------------------------------------------
/build/.gitignore:
--------------------------------------------------------------------------------
1 | *_templ.go
2 | twcli
--------------------------------------------------------------------------------
/build/cmd/build/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "log"
5 | "time"
6 |
7 | build "github.com/starfederation/datastar/build"
8 | )
9 |
10 | func main() {
11 | start := time.Now()
12 | log.Print("Datastar built in TS compiler!")
13 | defer func() {
14 | log.Printf("Datastar built in %s", time.Since(start))
15 | }()
16 |
17 | if err := build.Build(); err != nil {
18 | log.Fatal(err)
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/examples/clojure/hello-world/.gitignore:
--------------------------------------------------------------------------------
1 | .nrepl-port
2 | .cpcache
3 |
--------------------------------------------------------------------------------
/examples/clojure/hello-world/README.md:
--------------------------------------------------------------------------------
1 | # Hello world example
2 |
3 | ## Running the example
4 |
5 | - repl:
6 |
7 | ```
8 | clojure -M:repl -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"
9 | ```
10 |
11 | - main:
12 |
13 | ```
14 | clojure -M -m example.main
15 | ```
16 |
--------------------------------------------------------------------------------
/examples/clojure/hello-world/src/dev/user.clj:
--------------------------------------------------------------------------------
1 | (ns user
2 | (:require
3 | [clj-reload.core :as reload]))
4 |
5 |
6 | (alter-var-root #'*warn-on-reflection* (constantly true))
7 |
8 |
9 | (reload/init
10 | {:no-reload ['user]})
11 |
12 |
13 | (defn reload! []
14 | (reload/reload))
15 |
16 |
17 | (comment
18 | (reload!)
19 | *e)
20 |
21 |
22 |
--------------------------------------------------------------------------------
/examples/clojure/hello-world/src/main/example/main.clj:
--------------------------------------------------------------------------------
1 | (ns example.main
2 | (:require
3 | [example.core :as c]
4 | [example.server :as server]))
5 |
6 |
7 | (defn -main [& _]
8 | (let [server (server/start! c/handler)]
9 | (.addShutdownHook (Runtime/getRuntime)
10 | (Thread. (fn []
11 | (server/stop! server)
12 | (shutdown-agents))))))
13 |
--------------------------------------------------------------------------------
/examples/clojure/hello-world/src/main/example/utils.clj:
--------------------------------------------------------------------------------
1 | (ns example.utils
2 | (:require
3 | [charred.api :as charred]
4 | [starfederation.datastar.clojure.api :as d*]))
5 |
6 |
7 | (def ^:private bufSize 1024)
8 | (def read-json (charred/parse-json-fn {:async? false :bufsize bufSize}))
9 |
10 | (defn get-signals [req]
11 | (-> req d*/get-signals read-json))
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/dotnet/csharp/HelloWorld/HelloWorld.csproj:
--------------------------------------------------------------------------------
1 |
6 | { templ.JSONString(info) } 7 |8 |
Internal errors should never occur. If you encounter this error, please open a new GitHub issue, providing and explanation of how it occurred and the details above.
14 | } 15 | } 16 | -------------------------------------------------------------------------------- /site/routes_examples_csrf.templ: -------------------------------------------------------------------------------- 1 | 2 | package site 3 | 4 | import "fmt" 5 | 6 | templ CSRFDemo(csrf string) { 7 |{ response }28 | } 29 | -------------------------------------------------------------------------------- /site/routes_examples_custom_validity.go: -------------------------------------------------------------------------------- 1 | package site 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-chi/chi/v5" 7 | "github.com/starfederation/datastar/sdk/go/datastar" 8 | ) 9 | 10 | func setupExamplesCustomValidity(examplesRouter chi.Router) error { 11 | examplesRouter.Get("/custom_validity/data", func(w http.ResponseWriter, r *http.Request) { 12 | sse := datastar.NewSSE(w, r) 13 | sse.ExecuteScript(`alert('Form submitted')`) 14 | }) 15 | 16 | return nil 17 | } 18 | -------------------------------------------------------------------------------- /site/routes_examples_indicator.go: -------------------------------------------------------------------------------- 1 | package site 2 | 3 | import ( 4 | "net/http" 5 | "time" 6 | 7 | "github.com/go-chi/chi/v5" 8 | "github.com/starfederation/datastar/sdk/go/datastar" 9 | ) 10 | 11 | func setupExamplesIndicator(examplesRouter chi.Router) error { 12 | 13 | examplesRouter.Get("/fetch_indicator/greet", func(w http.ResponseWriter, r *http.Request) { 14 | sse := datastar.NewSSE(w, r) 15 | sse.MergeFragmentTempl(indicatorEmpty()) 16 | time.Sleep(2 * time.Second) 17 | sse.MergeFragmentTempl(indicatorGreeting()) 18 | }) 19 | 20 | return nil 21 | } 22 | -------------------------------------------------------------------------------- /site/routes_examples_indicator.templ: -------------------------------------------------------------------------------- 1 | package site 2 | 3 | import "time" 4 | 5 | templ indicatorEmpty() { 6 |
1
`)
15 | })
16 |
17 | return nil
18 | }
19 |
--------------------------------------------------------------------------------
/site/routes_tests_merge_fragment_input_value.go:
--------------------------------------------------------------------------------
1 | package site
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/go-chi/chi/v5"
7 | "github.com/starfederation/datastar/sdk/go/datastar"
8 | )
9 |
10 | func setupTestsMergeFragmentInputValue(testsRouter chi.Router) error {
11 |
12 | testsRouter.Get("/merge_fragment_input_value/data", func(w http.ResponseWriter, r *http.Request) {
13 | sse := datastar.NewSSE(w, r)
14 | sse.MergeFragments(`foo 15 | bar`) 16 | }) 17 | 18 | return nil 19 | } 20 | -------------------------------------------------------------------------------- /site/routes_tests_on_load.go: -------------------------------------------------------------------------------- 1 | package site 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/go-chi/chi/v5" 7 | 8 | "github.com/starfederation/datastar/sdk/go/datastar" 9 | ) 10 | 11 | type OnLoadSignals struct { 12 | Fetching bool `json:"fetching"` 13 | } 14 | 15 | func setupTestsOnLoad(testsRouter chi.Router) error { 16 | 17 | testsRouter.Get("/on_load/data", func(w http.ResponseWriter, r *http.Request) { 18 | signals := &OnLoadSignals{} 19 | if err := datastar.ReadSignals(r, signals); err != nil { 20 | http.Error(w, err.Error(), http.StatusBadRequest) 21 | } 22 | 23 | sse := datastar.NewSSE(w, r) 24 | 25 | if signals.Fetching { 26 | sse.MergeFragments(`
1
`)
27 | }
28 | })
29 |
30 | return nil
31 | }
32 |
--------------------------------------------------------------------------------
/site/routes_tests_remove_fragment.go:
--------------------------------------------------------------------------------
1 | package site
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/go-chi/chi/v5"
7 | "github.com/starfederation/datastar/sdk/go/datastar"
8 | )
9 |
10 | func setupTestsRemoveFragment(testsRouter chi.Router) error {
11 |
12 | testsRouter.Delete("/remove_fragment/data", func(w http.ResponseWriter, r *http.Request) {
13 | sse := datastar.NewSSE(w, r)
14 | sse.RemoveFragments("#remove")
15 | })
16 |
17 | return nil
18 | }
19 |
--------------------------------------------------------------------------------
/site/routes_tests_remove_initiating_fragment.go:
--------------------------------------------------------------------------------
1 | package site
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/go-chi/chi/v5"
7 | "github.com/starfederation/datastar/sdk/go/datastar"
8 | )
9 |
10 | func setupTestsRemoveInitiatingFragment(testsRouter chi.Router) error {
11 |
12 | testsRouter.Delete("/remove_initiating_fragment/data", func(w http.ResponseWriter, r *http.Request) {
13 | sse := datastar.NewSSE(w, r)
14 | sse.RemoveFragments("#clickable")
15 | sse.MergeFragments(`1
`)
16 | })
17 |
18 | return nil
19 | }
20 |
--------------------------------------------------------------------------------
/site/routes_tests_sse_error_event.go:
--------------------------------------------------------------------------------
1 | package site
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/go-chi/chi/v5"
7 | )
8 |
9 | func setupTestsSseErrorEvent(testsRouter chi.Router) error {
10 |
11 | testsRouter.Get("/sse_error_event/data", func(w http.ResponseWriter, r *http.Request) {
12 | http.Error(w, "Service Unavailable", http.StatusServiceUnavailable)
13 | })
14 |
15 | return nil
16 | }
17 |
--------------------------------------------------------------------------------
/site/routes_tests_sse_events.go:
--------------------------------------------------------------------------------
1 | package site
2 |
3 | import (
4 | "net/http"
5 |
6 | "github.com/go-chi/chi/v5"
7 | "github.com/starfederation/datastar/sdk/go/datastar"
8 | )
9 |
10 | func setupTestsSseEvents(testsRouter chi.Router) error {
11 |
12 | testsRouter.Get("/sse_events/data", func(w http.ResponseWriter, r *http.Request) {
13 | datastar.NewSSE(w, r)
14 | })
15 |
16 | return nil
17 | }
18 |
--------------------------------------------------------------------------------
/site/smoketests/.gitignore:
--------------------------------------------------------------------------------
1 | *.png
2 |
--------------------------------------------------------------------------------
/site/smoketests/aliased_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitAliased(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/aliased")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/attr_false_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitAttrFalse(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/attr_false")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/attr_object_false_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitAttrObjectFalse(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/attr_object_false")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/checkbox_array_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitCheckboxArray(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/checkbox_array")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/checkbox_boolean_checked_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitCheckboxBooleanChecked(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/checkbox_boolean_checked")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/checkbox_boolean_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitCheckboxDefault(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/checkbox_boolean")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/checkbox_value_checked_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitCheckboxValueChecked(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/checkbox_value_checked")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/checkbox_value_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitCheckboxValue(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/checkbox_value")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/click_to_load_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleClickToLoad(t *testing.T) {
11 | setupPageTest(t, "examples/click_to_load", func(runner runnerFn) {
12 | runner("click to load", func(t *testing.T, page *rod.Page) {
13 | table := page.MustElement(".table")
14 |
15 | rows := table.MustElements("tr")
16 | assert.Len(t, rows, 11)
17 |
18 | btn := page.MustElement("#more_btn")
19 | btn.MustClick()
20 | page.MustWaitStable()
21 |
22 | updatedRows := table.MustElements("tr")
23 | assert.Len(t, updatedRows, 21)
24 | })
25 | })
26 | }
27 |
--------------------------------------------------------------------------------
/site/smoketests/cloak_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleCloak(t *testing.T) {
11 | setupPageTest(t, "examples/cloak", func(runner runnerFn) {
12 | runner("cloak", func(t *testing.T, page *rod.Page) {
13 | element := page.MustElement("#cloak")
14 | initial, err := element.Attribute("class")
15 | if err != nil {
16 | t.Fatal("failed to get initial class: %w", err)
17 | }
18 | assert.Nil(t, initial)
19 | })
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/site/smoketests/custom_plugin_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitCustomPlugin(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/custom_plugin")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/dispatch_custom_event_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleDispatchCustomEvent(t *testing.T) {
11 | setupPageTest(t, "examples/dispatch_custom_event", func(runner runnerFn) {
12 | runner("observe dispatched custom event", func(t *testing.T, page *rod.Page) {
13 | selector := "#container"
14 | el := page.MustElement(selector)
15 | initial := el.MustText()
16 |
17 | page.MustWait(`() => document.querySelector("` + selector + `").innerText !== ""`)
18 |
19 | result := el.MustText()
20 |
21 | assert.NotEqual(t, initial, result)
22 | })
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/site/smoketests/file_upload_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "path/filepath"
5 | "testing"
6 |
7 | "github.com/go-rod/rod"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestExampleFileUpload(t *testing.T) {
12 | setupPageTest(t, "examples/file_upload", func(runner runnerFn) {
13 | runner("upload a file", func(t *testing.T, page *rod.Page) {
14 | el := page.MustElement(`[type=file]`)
15 | el.MustSetFiles(
16 | filepath.FromSlash("site/smoketests/file_upload_test.go"),
17 | )
18 |
19 | list := el.MustEval("() => Array.from(this.files).map(f => f.name)").Arr()
20 | assert.Len(t, list, 1)
21 | assert.Equal(t, "file_upload_test.go", list[0].String())
22 | })
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/site/smoketests/indicator_element_removed_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitIndicatorElementRemoved(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/indicator_element_removed")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/indicator_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitIndicator(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/indicator")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/input_array_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitInputArray(t *testing.T) {
8 | setupPageTestOnPopulate(t, "tests/input_array", "bar")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/input_signal_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitInputSignal(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/input_signal")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/input_value_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitInputValue(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/input_value")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/key_casing_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitKeyCasing(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/key_casing")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/lazy_load_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func DisabledTestExampleLazyLoad(t *testing.T) {
11 | setupPageTest(t, "examples/lazy_load", func(runner runnerFn) {
12 | runner("observe lazy load", func(t *testing.T, page *rod.Page) {
13 | selector := "#lazy_load"
14 |
15 | initial := page.MustElement(selector).MustText()
16 | assert.Equal(t, "Loading...", initial)
17 |
18 | page.MustWait(`() => document.querySelector("` + selector + `").innerText === ""`)
19 |
20 | src := page.MustElement(selector).MustAttribute("src")
21 |
22 | assert.NotNil(t, src)
23 | })
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/site/smoketests/local_signals_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitLocalSignals(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/local_signals")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/merge_fragment_input_value_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitMergeFragmentInputValue(t *testing.T) {
8 | setupPageTestOnPopulateAndClick(t, "tests/merge_fragment_input_value", "foo")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/merge_fragment_on_load_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitMergeFragmentOnLoad(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/merge_fragment_on_load")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/merge_fragment_signals_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitMergeFragmentSignals(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/merge_fragment_signals")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/merge_fragment_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitMergeFragment(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/merge_fragment")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/merge_fragment_whitespace_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitMergeFragmentWhitespace(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/merge_fragment_whitespace")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/multiline_expressions_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleMultilineExpressions(t *testing.T) {
11 | setupPageTest(t, "examples/multiline_expressions", func(runner runnerFn) {
12 | runner("observe change", func(t *testing.T, page *rod.Page) {
13 | selector := "article > div"
14 | initial := page.MustElement(selector).MustText()
15 |
16 | page.MustWait(`() => document.querySelector("` + selector + `").innerText !== "` + initial + `"`)
17 | result := page.MustElement(selector).MustText()
18 |
19 | assert.NotEqual(t, initial, result)
20 | })
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/site/smoketests/on_load_delay_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitOnLoadDelay(t *testing.T) {
8 | setupPageTestOnDelay(t, "tests/on_load_delay")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/on_load_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitOnLoad(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/on_load")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/on_signal_change_path_once_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitOnSignalChangePathOnce(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/on_signal_change_path_once")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/on_signal_change_path_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitOnSignalChangePath(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/on_signal_change_path")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/on_signal_change_path_wildcard_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitOnSignalChangePathWildcard(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/on_signal_change_path_wildcard")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/on_signal_change_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitOnSignalChange(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/on_signal_change")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/persist_signals_path_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestPersistSignalsPathWildcard(t *testing.T) {
11 | setupPageTest(t, "tests/persist_signals_path", func(runner runnerFn) {
12 | runner("tests/persist_signals_path", func(t *testing.T, page *rod.Page) {
13 | page.MustWaitIdle()
14 | assert.Equal(t, "1", getLocalStoragePath(t, page, "foo"))
15 | assert.Equal(t, "1", getLocalStoragePath(t, page, "bar"))
16 | assert.Equal(t, "", getLocalStoragePath(t, page, "baz"))
17 | })
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/site/smoketests/persist_signals_path_wildcard_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestPersistSignalsPath(t *testing.T) {
11 | setupPageTest(t, "tests/persist_signals_path_wildcard", func(runner runnerFn) {
12 | runner("tests/persist_signals_path_wildcard", func(t *testing.T, page *rod.Page) {
13 | page.MustWaitIdle()
14 | assert.Equal(t, "{bar:{baz:1}", getLocalStoragePath(t, page, "foo"))
15 | })
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/site/smoketests/persist_signals_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestPersistSignals(t *testing.T) {
11 | setupPageTest(t, "tests/persist_signals", func(runner runnerFn) {
12 | runner("tests/persist_signals", func(t *testing.T, page *rod.Page) {
13 | page.MustWaitIdle()
14 | assert.Equal(t, "1", getLocalStoragePath(t, page, "foo"))
15 | assert.Equal(t, "1", getLocalStoragePath(t, page, "bar"))
16 | assert.Equal(t, "1", getLocalStoragePath(t, page, "baz"))
17 | })
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/site/smoketests/plugin_name_prefix_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitPluginNamePrefix(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/plugin_name_prefix")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/progress_bar_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleProgressBar(t *testing.T) {
11 | setupPageTest(t, "examples/progress_bar", func(runner runnerFn) {
12 | runner("observe progress bar", func(t *testing.T, page *rod.Page) {
13 | selector := "#progress_bar"
14 | svg := page.MustElement(selector)
15 |
16 | initial := svg.MustHTML()
17 |
18 | page.MustWaitStable()
19 |
20 | result := page.MustElement(selector).MustHTML()
21 |
22 | assert.NotEqual(t, initial, result)
23 | })
24 | })
25 | }
26 |
--------------------------------------------------------------------------------
/site/smoketests/radio_value_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitRadioValue(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/radio_value")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/raf_update_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleRafUpdate(t *testing.T) {
11 | setupPageTest(t, "examples/raf_update", func(runner runnerFn) {
12 | runner("observe raf", func(t *testing.T, page *rod.Page) {
13 | initial := page.MustElement("pre").MustText()
14 |
15 | page.MustWait("() => document.querySelector(`pre`).innerText !== `" + initial + "`")
16 |
17 | result := page.MustElement("pre").MustText()
18 |
19 | assert.NotEqual(t, initial, result)
20 | })
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/site/smoketests/redirects_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleRedirects(t *testing.T) {
11 | setupPageTest(t, "examples/redirects", func(runner runnerFn) {
12 | runner("redirection", func(t *testing.T, page *rod.Page) {
13 | btn := page.MustElementR("button", "Redirect")
14 | btn.MustClick()
15 |
16 | waitForURLToContain(page, "grugs_around_fire")
17 |
18 | url := page.MustInfo().URL
19 | assert.Contains(t, url, "grugs_around_fire")
20 | })
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/site/smoketests/ref_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitRef(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/ref")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/refs_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleRefs(t *testing.T) {
11 | setupPageTest(t, "examples/refs", func(runner runnerFn) {
12 | runner("observe ref", func(t *testing.T, page *rod.Page) {
13 | initial := page.MustElementR(".card-title", "I'm using content").MustText()
14 | assert.Contains(t, initial, "I'm a div that is getting referenced")
15 | })
16 | })
17 | }
18 |
--------------------------------------------------------------------------------
/site/smoketests/remove_fragment_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitRemoveFragment(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/remove_fragment")
9 | }
--------------------------------------------------------------------------------
/site/smoketests/remove_initiating_fragment_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitRemoveInitiatingFragment(t *testing.T) {
8 | setupPageTestOnClick(t, "tests/remove_initiating_fragment")
9 | }
--------------------------------------------------------------------------------
/site/smoketests/replace_url_from_backend_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleReplaceUrlFromBackend(t *testing.T) {
11 | setupPageTest(t, "examples/replace_url_from_backend", func(runner runnerFn) {
12 | runner("observe url replacement", func(t *testing.T, page *rod.Page) {
13 | initial := page.MustInfo().URL
14 |
15 | page.MustWait(`() => window.location.href !== "` + initial + `"`)
16 |
17 | result := page.MustInfo().URL
18 | assert.NotEqual(t, initial, result)
19 | })
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/site/smoketests/replace_url_from_signals_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleReplaceUrlFromSignals(t *testing.T) {
11 | setupPageTest(t, "examples/replace_url_from_signals", func(runner runnerFn) {
12 | runner("observe url replacement", func(t *testing.T, page *rod.Page) {
13 | initial := page.MustInfo().URL
14 |
15 | page.MustWait(`() => window.location.href !== "` + initial + `"`)
16 |
17 | result := page.MustInfo().URL
18 | assert.NotEqual(t, initial, result)
19 | })
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/site/smoketests/scroll_into_view_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleScrollIntoView(t *testing.T) {
11 | setupPageTest(t, "examples/scroll_into_view", func(runner runnerFn) {
12 | runner("smooth", func(t *testing.T, page *rod.Page) {
13 | pos := page.Mouse.Position()
14 | assert.InDelta(t, 0, pos.X, 5.0)
15 | assert.InDelta(t, 0, pos.Y, 5.0)
16 |
17 | btn := page.MustElement("#scrollIntoViewButton")
18 | btn.MustClick()
19 |
20 | page.MustWaitIdle()
21 |
22 | pos = page.Mouse.Position()
23 | assert.Greater(t, pos.X, 500.0)
24 | assert.Greater(t, pos.Y, 200.0)
25 | })
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/site/smoketests/select_multiple_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitSelectMultipe(t *testing.T) {
8 | setupPageTestOnSelect(t, "tests/select_multiple")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/select_single_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitSelectSingle(t *testing.T) {
8 | setupPageTestOnSelect(t, "tests/select_single")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/set_all_path_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitSetAllPath(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/set_all_path")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/set_all_path_wildcard_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitSetAllPathWildcard(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/set_all_path_wildcard")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/set_all_paths_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitSetAllPaths(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/set_all_paths")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/signals_ifmissing_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleSignalsIfmissing(t *testing.T) {
11 | setupPageTest(t, "examples/signals_ifmissing", func(runner runnerFn) {
12 | runner("check the signals", func(t *testing.T, page *rod.Page) {
13 |
14 | initial := page.MustElement("#placeholder").MustText()
15 | assert.Empty(t, initial)
16 |
17 | page.MustWait(`() => document.querySelector("#placeholder").innerText !== ""`)
18 |
19 | result := page.MustElement("#placeholder").MustText()
20 | assert.NotEqual(t, initial, result)
21 | assert.Equal(t, "1234", result)
22 | })
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/site/smoketests/sse_error_event_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitSseErrorEvent(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/sse_error_event")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/sse_events_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitSseEvents(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/sse_events")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/title_update_backend_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleTitleUpdateBackend(t *testing.T) {
11 | setupPageTest(t, "examples/title_update_backend", func(runner runnerFn) {
12 | runner("observe title change", func(t *testing.T, page *rod.Page) {
13 | initial := page.MustEval(`() => document.title`).Str()
14 |
15 | page.MustWait(`() => document.title !== "` + initial + `"`)
16 |
17 | result := page.MustEval(`() => document.title`).Str()
18 |
19 | assert.NotEqual(t, initial, result)
20 | })
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/site/smoketests/todos_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/go-rod/rod/lib/input"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestTodos(t *testing.T) {
12 | setupPageTest(t, "", func(runner runnerFn) {
13 | runner("add a todo", func(t *testing.T, page *rod.Page) {
14 | assert.NotNil(t, page)
15 | el := page.MustElementR("input", "What needs to be done?").MustInput("testing!")
16 | el.MustType(input.Enter)
17 | })
18 | })
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/site/smoketests/toggle_all_path_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestUnitToggleAllPath(t *testing.T) {
8 | setupPageTestOnLoad(t, "tests/toggle_all_path")
9 | }
10 |
--------------------------------------------------------------------------------
/site/smoketests/toggle_visibility_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/stretchr/testify/assert"
8 | )
9 |
10 | func TestExampleToggleVisibility(t *testing.T) {
11 | setupPageTest(t, "examples/toggle_visibility", func(runner runnerFn) {
12 | runner("toggle", func(t *testing.T, page *rod.Page) {
13 | initial := page.MustElement("#container > div").MustAttribute("style")
14 | assert.Equal(t, "display: none;", *initial)
15 |
16 | btn := page.MustElementR("button", "Toggle")
17 | btn.MustClick()
18 |
19 | result := page.MustElement("#container > div").MustAttribute("style")
20 | assert.Equal(t, "", *result)
21 | })
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/site/smoketests/web_component_test.go:
--------------------------------------------------------------------------------
1 | package smoketests
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/go-rod/rod"
7 | "github.com/go-rod/rod/lib/input"
8 | "github.com/stretchr/testify/assert"
9 | )
10 |
11 | func TestExampleWebComponent(t *testing.T) {
12 | setupPageTest(t, "examples/web_component", func(runner runnerFn) {
13 | runner("observe web component", func(t *testing.T, page *rod.Page) {
14 | page.MustElement("article > div > input").MustInput("tes")
15 | page.MustElement("article > div > input").MustType(input.KeyT)
16 |
17 | result := page.MustElement("div > span").MustText()
18 |
19 | assert.Equal(t, "tset", result)
20 | })
21 | })
22 | }
23 |
--------------------------------------------------------------------------------
/site/static/code_snippets/getting_started/multiple_events.clojuresnippet:
--------------------------------------------------------------------------------
1 | (d*/merge-fragment! sse "
8 | 1
10 |
10 | 1
12 |
10 | 1
12 |
15 | 1
17 |
11 | 1
13 |
11 | 1
13 |
11 | 1
13 |
11 | 1
13 | 0
20 | 1
22 |
11 | 1
13 |
10 | 1
12 |
13 | 1
15 |
10 | 1
12 |
10 | 1
12 |
8 | 1
10 |
8 | 1
10 | 0
10 | 1
12 | 0
11 | 1
13 |
11 | 1
13 |
13 | 1
15 |
11 | 1
13 |
11 | 1
13 | 0
9 | 1
11 |
8 | 1
10 |
8 | 1
10 |
8 | 1
10 |
8 | 1
10 |
8 | 1
10 | datastar: {"bar":1,"baz:1","foo":1}
8 | datastar: {"bar":1,"foo":1}
8 | datastar: {"foo":{"bar":{"baz":1}}}
8 | 0
8 | 1
10 |
12 | 1
14 | 0
8 | 1
10 | 0--1
10 | 1
12 | 0
10 | 1
12 |
11 | 1
13 |
10 | 1
12 |
8 | 1
10 |
8 | 1
10 |
8 | 1
10 |
11 | 1
13 |
10 | 1
12 |
8 | 1
10 |