![]() also bump version to 0.1.3 and bump alpha version of rama |
||
---|---|---|
.. | ||
clojure | ||
dotnet | ||
go | ||
haskell | ||
java | ||
php | ||
python | ||
ruby | ||
rust | ||
test | ||
typescript | ||
zig | ||
README.md |
README.md
Architecture Decision Record: Datastar SDK
Summary
Datastar has had a few helper tools in the past for different languages. The SDK effort is to unify around the tooling needed for Hypermedia On Whatever your Like (HOWL) based UIs. Although Datastar the library can use any plugins, the default bundle includes robust Server Sent Event (SSE) base approach. Most current languages and backend don't have great tooling around the style of delivering content to the frontend.
Decision
Provide an SDK in a language agnostic way, to that end
- Keep SDK as minimal as possible
- Allow per language/framework extended features to live in an SDK sugar version
Details
Assumptions
The core mechanics of Datastar’s SSE support is
- Data gets sent to browser as SSE events.
- Data comes in via JSON from browser under a
datastar
namespace.
Library
[!WARNING] All naming conventions are shown using
Go
as the standard. Things may vary per language norms but please keep as close as possible.
ServerSentEventGenerator
There must be a ServerSentEventGenerator
namespace. In Go this is implemented as a struct, but could be a class or even namespace in languages such as C.
Construction / Initialization
- There must be a way to create a new instance of this object based on the incoming
HTTP
Request and Response objects. - The
ServerSentEventGenerator
must use a response controller that has the following response headers set by defaultCache-Control = nocache
Content-Type = text/event-stream
Connection = keep-alive
only if a HTTP/1.1 connection is used (see spec)
- Then the created response should
flush
immediately to avoid timeouts while 0-♾️ events are created - Multiple calls using
ServerSentEventGenerator
should be single threaded to guarantee order. The Go implementation uses a mutex to facilitate this behavior but might not be needed in a some environments
ServerSentEventGenerator.send
ServerSentEventGenerator.send(
eventType: EventType,
dataLines: string[],
options?: {
eventId?: string,
retryDuration?: durationInMilliseconds
}
)
All top level ServerSentEventGenerator
should use a unified sending function. This method should be private/protected
Args
EventType
An enum of Datastar supported events. Will be a string over the wire. Currently valid values are
Event | Description |
---|---|
datastar-merge-fragments | Merges HTML fragments into the DOM |
datastar-merge-signals | Merges signals into the signals |
datastar-remove-fragments | Removes HTML fragments from the DOM |
datastar-remove-signals | Removes signals from the signals |
datastar-execute-script | Executes JavaScript in the browser |
Options
eventId
(string) Each event may include aneventId
. This can be used by the backend to replay events. This is part of the SSE spec and is used to tell the browser how to handle the event. For more details see https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#idretryDuration
(duration) Each event may include aretryDuration
value. If one is not provided the SDK must default to1000
milliseconds. This is part of the SSE spec and is used to tell the browser how long to wait before reconnecting if the connection is lost. For more details see https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#retry
Logic
When called the function must write to the response buffer the following in specified order. If any part of this process fails you must return/throw an error depending on language norms.
- Must write
event: EVENT_TYPE\n
whereEVENT_TYPE
is EventType. - If a user defined event ID is provided, the function must write
id: EVENT_ID\n
whereEVENT_ID
is the event ID. - Must write
retry: RETRY_DURATION\n
whereRETRY_DURATION
is the provided retry duration, unless the value is the default of1000
milliseconds. - For each string in the provided
dataLines
, you must writedata: DATA\n
whereDATA
is the provided string. - Must write a
\n\n
to complete the event per the SSE spec. - Afterward the writer should immediately flush. This can be confounded by other middlewares such as compression layers.
ServerSentEventGenerator.MergeFragments
ServerSentEventGenerator.MergeFragments(
fragments: string,
options?: {
selector?: string,
mergeMode?: FragmentMergeMode,
useViewTransition?: boolean,
eventId?: string,
retryDuration?: durationInMilliseconds
}
)
Example Output
Minimal:
event: datastar-merge-fragments
data: fragments <div id="feed">
data: fragments <span>1</span>
data: fragments </div>
Maximal:
event: datastar-merge-fragments
id: 123
retry: 2000
data: selector #feed
data: useViewTransition true
data: fragments <div id="feed">
data: fragments <span>1</span>
data: fragments </div>
MergeFragments
is a helper function to send HTML fragments to the browser to be merged into the DOM.
Args
FragmentMergeMode
An enum of Datastar supported fragment merge modes. Will be a string over the wire Valid values should match the FragmentMergeMode and currently include
Mode | Description |
---|---|
morph | Use Idiomorph to merge the fragment into the DOM |
inner | Replace the innerHTML of the selector with the fragment |
outer | Replace the outerHTML of the selector with the fragment |
prepend | Prepend the fragment to the selector |
append | Append the fragment to the selector |
before | Insert the fragment before the selector |
after | Insert the fragment after the selector |
upsertAttributes | Update the attributes of the selector with the fragment |
Options
selector
(string) The CSS selector to use to insert the fragments. If not provided or empty, Datastar will default to using theid
attribute of the fragment.mergeMode
(FragmentMergeMode) The mode to use when merging the fragment into the DOM. If not provided the Datastar client side will default tomorph
.useViewTransition
Whether to use view transitions, if not provided the Datastar client side will default tofalse
.
Logic
When called the function must call ServerSentEventGenerator.send
with the datastar-merge-fragments
event type.
- If
selector
is provided, the function must include the selector in the event data in the formatselector SELECTOR\n
, unless the selector is empty. - If
mergeMode
is provided, the function must include the merge mode in the event data in the formatmerge MERGE_MODE\n
, unless the value is the default ofmorph
. - If
useViewTransition
is provided, the function must include the view transition in the event data in the formatuseViewTransition USE_VIEW_TRANSITION\n
, unless the value is the default offalse
.USE_VIEW_TRANSITION
should betrue
orfalse
(string), depending on the value of theuseViewTransition
option. - The function must include the fragments in the event data, with each line prefixed with
fragments
. This should be output after all other event data.
ServerSentEventGenerator.RemoveFragments
ServerSentEventGenerator.RemoveFragments(
selector: string,
options?: {
useViewTransition?: boolean,
eventId?: string,
retryDuration?: durationInMilliseconds
}
)
Example Output
Minimal:
event: datastar-remove-fragments
data: selector #target
Maximal:
event: datastar-remove-fragments
id: 123
retry: 2000
data: selector #target
data: useViewTransition true
RemoveFragments
is a helper function to send a selector to the browser to remove HTML fragments from the DOM.
Args
selector
is a CSS selector that represents the fragments to be removed from the DOM. The selector must be a valid CSS selector. The Datastar client side will use this selector to remove the fragment from the DOM.
Options
useViewTransition
Whether to use view transitions, if not provided the Datastar client side will default tofalse
.
Logic
- When called the function must call
ServerSentEventGenerator.send
with thedatastar-remove-fragments
event type. - The function must include the selector in the event data in the format
selector SELECTOR\n
. - If
useViewTransition
is provided, the function must include the view transition in the event data in the formatuseViewTransition USE_VIEW_TRANSITION\n
, unless the value is the default offalse
.USE_VIEW_TRANSITION
should betrue
orfalse
(string), depending on the value of theuseViewTransition
option.
ServerSentEventGenerator.MergeSignals
ServerSentEventGenerator.MergeSignals(
signals: string,
options ?: {
onlyIfMissing?: boolean,
eventId?: string,
retryDuration?: durationInMilliseconds
}
)
Example Output
Minimal:
event: datastar-merge-signals
data: signals {"output":"Patched Output Test","show":true,"input":"Test","user":{"name":"","email":""}}
Maximal:
event: datastar-merge-signals
id: 123
retry: 2000
data: onlyIfMissing true
data: signals {"output":"Patched Output Test","show":true,"input":"Test","user":{"name":"","email":""}}
MergeSignals
is a helper function to send one or more signals to the browser to be merged into the signals.
Args
Data is a JavaScript object or JSON string that will be sent to the browser to update signals in the signals. The data must evaluate to a valid JavaScript. It will be converted to signals by the Datastar client side.
Options
onlyIfMissing
(boolean) Whether to merge the signal only if it does not already exist. If not provided, the Datastar client side will default tofalse
, which will cause the data to be merged into the signals.
Logic
When called the function must call ServerSentEventGenerator.send
with the datastar-merge-signals
event type.
- If
onlyIfMissing
is provided, the function must include it in the event data in the formatonlyIfMissing ONLY_IF_MISSING\n
, unless the value is the default offalse
.ONLY_IF_MISSING
should betrue
orfalse
(string), depending on the value of theonlyIfMissing
option. - The function must include the signals in the event data, with each line prefixed with
signals
. This should be output after all other event data.
ServerSentEventGenerator.RemoveSignals
ServerSentEventGenerator.RemoveSignals(
paths: string[],
options?: {
eventId?: string,
retryDuration?: durationInMilliseconds
}
)
Example Output
Minimal:
event: datastar-remove-signals
data: paths user.name
data: paths user.email
Maximal:
event: datastar-remove-signals
id: 123
retry: 2000
data: paths user.name
data: paths user.email
RemoveSignals
is a helper function to send signals to the browser to be removed from the signals.
Args
paths
is a list of strings that represent the signal paths to be removed from the signals. The paths must be valid .
delimited paths to signals within the signals. The Datastar client side will use these paths to remove the data from the signals.
Logic
When called the function must call ServerSentEventGenerator.send
with the datastar-remove-signals
event type.
- The function must include the paths in the event data, with each line prefixed with
paths
. Space-separated paths such aspaths foo.bar baz.qux.hello world
should be allowed.
ServerSentEventGenerator.ExecuteScript
ServerSentEventGenerator.ExecuteScript(
script: string,
options?: {
autoRemove?: boolean,
attributes?: string,
eventId?: string,
retryDuration?: durationInMilliseconds
}
)
Example Output
Minimal:
event: datastar-execute-script
data: script window.location = "https://data-star.dev"
Maximal:
event: datastar-execute-script
id: 123
retry: 2000
data: autoRemove false
data: attributes type text/javascript
data: script window.location = "https://data-star.dev"
Args
script
is a string that represents the JavaScript to be executed by the browser.
Options
autoRemove
Whether to remove the script after execution, if not provided the Datastar client side will default totrue
.attributes
A line separated list of attributes to add to thescript
element, if not provided the Datastar client side will default totype module
. Each item in the array should be a string in the formatkey value
.
Logic
When called the function must call ServerSentEventGenerator.send
with the datastar-execute-script
event type.
- If
autoRemove
is provided, the function must include the auto remove script value in the event data in the formatautoRemove AUTO_REMOVE\n
, unless the value is the default oftrue
. - If
attributes
is provided, the function must include the attributes in the event data, with each line prefixed withattributes
, unless the attributes value is the default oftype module
. - The function must include the script in the event data, with each line prefixed with
script
. This should be output after all other event data.
ReadSignals(r *http.Request, signals any) error
ReadSignals
is a helper function to parse incoming data from the browser. It should take the incoming request and convert into an object that can be used by the backend.
Args
r
(http.Request) The incoming request object from the browser. This object must be a valid Request object per the language specifics.signals
(any) The signals object that the incoming data will be extracted into. The exact function signature will depend on the language specifics.
Logic
- The function must parse the incoming HTTP request
- If the incoming method is
GET
, the function must parse the query string'sdatastar
key and treat it as a URL encoded JSON string. - Otherwise, the function must parse the body of the request as a JSON encoded string.
- If the incoming data is not valid JSON, the function must return an error.
- If the incoming method is