Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No way to proxy SSE data #48

Open
lsmenicucci opened this issue Jul 13, 2024 · 7 comments
Open

No way to proxy SSE data #48

lsmenicucci opened this issue Jul 13, 2024 · 7 comments
Labels
enhancement New feature or request

Comments

@lsmenicucci
Copy link

It would be interesting if there was a way to update the server side event's data before they got swapped into the elements.

The main reason for this is that SSE specification uses \n\n as an event terminator and the way to send multiline data is to base64 encode it before. However, there is no way to decode it on the frontend before the swap. At least not to my knowledge.

@Telroshan Telroshan added the enhancement New feature or request label Jul 13, 2024
@Telroshan
Copy link
Collaborator

Hey, doesn't the htmx:sseBeforeMessage match your usecase here? It should allow you to override event.data which is then passed to the swap method

// swap the response into the DOM and trigger a notification
if (!api.triggerEvent(elt, 'htmx:sseBeforeMessage', event)) {
return
}
swap(elt, event.data)
api.triggerEvent(elt, 'htmx:sseMessage', event)

Let me know!

@lsmenicucci
Copy link
Author

Thanks for the response @Telroshan.

I'm afraid event.data is read-only. It seems to be protected by a getter.

The shortest workaround I've found is to fork the library and dispatch a custom event with a closure like so:

var decodedData = null
const setDecodedData = function(data) {
    decodedData = data
}

const newEvent = new CustomEvent('htmx:sseBeforeSwap', {
    detail: { setDecodedData, data: event.data },
})


// swap the response into the DOM and trigger a notification
if (!api.triggerEvent(elt, 'htmx:sseBeforeSwap', newEvent)) {
    return
}

swap(elt, decodedData || event.data)

Which is no easier than just decoding directly in the extension side.

@lsmenicucci lsmenicucci closed this as not planned Won't fix, can't repro, duplicate, stale Jul 13, 2024
@lsmenicucci lsmenicucci reopened this Jul 13, 2024
@Telroshan
Copy link
Collaborator

Oh, indeed the properties are read-only...
Maybe we should use a copy of event in the extension to pass down to htmx:sseBeforeMessage? Like { ... event } ? I don't know if that's a good idea, I would expect it to just copy the values and get rid of the properties protections, so that we don't add an extra event when we don't need one, and since it'd be an object reference, we wouldn't change the code that much.
Or, we could add an additional property to the event data like a dataOverride, that if is set would take precedence over event.data

Just some thoughts out loud, if you feel like it, feel free to explore solutions and submit a PR!

@lsmenicucci
Copy link
Author

I would be happy to contribute.

Approaching this problem from another perspective, I think message encoding should be configured to a specific SSE connection/endpoint. I would go for an sse-encoding="base64" attribute, whereas sse-encoding="text" is the default. Such an example use case would read as:

<div hx-ext="sse" sse-connect="/api/events" sse-encoding="base64">
<!-- html fowarded to swaps is already decoded into text  -->
</div>

Then the proper encoding process would occur inside a callback registered inside registerSSE. What do you think @Telroshan?

@Telroshan
Copy link
Collaborator

This would solve your immediate usecase, but I'im thinking an event-based solution would be more modular and let people handle more specific usecases as needed.
With this approach, you could easily use a custom attribute if you want to and say, in a global htmx:sseBeforeMessage listener, call atob to decode your base 64 and override the message data if your event's target has a closest element with that attribute. So 1 if + 1 instruction in your handler.

I would suppose that the sseBeforeMessage event was designed with this goal in mind, unfortunately it seems it hadn't been tested until now, considering that read-only constraint. It would've worked similarly to say htmx:configRequest, that's also an event that lets you override whatever you want to override before htmx sends its requests.
It's a nice and easy way to cover any future specific needs people might have, because we give them the keys to do so, while implementing just an additional attribute for the encoding here, would require adding even more things to the extension code later on if people have other specific usecases not covered by this change

@hspaay
Copy link

hspaay commented Jul 24, 2024

Running into the same issues here. Both the encoding issue but also the lack of ability to modify the event data before it is swapped in.

The workaround sofar is to just use hx-trigger with sse and do a round trip to the server with hx-get to get the properly formatted data. This reduces the functionality of sse to mere triggers. Also, as the formatting is a client side concern, having to code this on the server for each case where it differs is not the most efficient way.
The extension client-side-templates is interesting but is a limited use-case. It also requires another extra library for template handling.

My latest workaround is to listen for the event htmx:sseBeforeMessage, cancel it with preventDefault, json decode the data field and use it to modify the event target directly in javascript.

@dionysiusmarquis
Copy link

Any news on that? Is it possible to transform the event data before swap? Can't seem to get it working, either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants