Localized autorefresh

Hi everyone,

I’m really struggling with AutoRefresh — I realize I had a lot of misconceptions about how it actually works.
My main goal is to build a ChatGPT-like chat in my app using open-ihp.
According to the docs, “The package is designed to work well with IHP AutoRefresh and IHP DataSync”.
I built a POC that works with AutoRefresh, but then I realized that AutoRefresh monitors the entire table, re-executes the action for all connected users, and broadcasts the results to every client over WebSocket. That feels really unscalable — am I right about this?
Is there a way to refresh a view only when the specific user’s row changes?
On the UX side, I also want to have a skeleton loader before the interface renders. I managed to do this nicely with HTMX:

mainView =
[hsx|
<div
id=“chat-pane”
class=“h-full”
hx-get={pathTo (RefineChatPaneAction uuid)}
hx-trigger=“load once”
hx-swap=“innerHTML”
>
{skeleton}

|]
The issue is that whenever a token arrives in the DB from OpenAI, the skeleton keeps re-appearing.
I tried attaching AutoRefresh to RefineChatPaneAction, but then it doesn’t update at all. Does AutoRefresh not work with HTMX?
It seems like what I actually need is a localized AutoRefresh (as described here
), though I don’t necessarily care about SSE.
I also came across the DataSubscriptionApi . which does synchronize db to frontend for specific row, but only usable with react ? is there an equivalent with haskell views ?
(Ref: IHP Realtime SPAs Guide
)
For me, the main selling point of IHP was having a reactive stack from DB to frontend.
What I expected was something like:

RefineChatPaneAction uuid = autoRefresh do
row ← fetch uuid

mainView =
[hsx|
<div
id=“chat-pane”
class=“h-full”
hx-get={pathTo (RefineChatPaneAction uuid)}
hx-trigger=“load once”
hx-swap=“innerHTML”
>
{skeleton}

|]
…which would refresh the view automatically whenever the row with this uuid changes, without re-showing the skeleton each time.
Is there a way to achieve this behavior without React?

IMO you can make this work with AutoRefresh. You likely need to make changes to the ihp-auto-refresh.js file. It’s pretty simple

i managed to get htmx work with ihp. I could make a pr.
but there is still the problem of scalability.
I also did a poc with Datasync and htmx. seems more promising.

and this

async function setupCvSetupsSubscription(cvSetupId) {
console.log(“cv setup subscription called”, cvSetupId)

// Ensure previous subscription is closed before creating a new one
if (window._cvSetupsSubscription && typeof window._cvSetupsSubscription.close === ‘function’) {
try { window.cvSetupsSubscription.close(); } catch () {}
window._cvSetupsSubscription = null;
}

// Build the query using the IHP querybuilder
let qb = query(“cv_setups”);
if (typeof qb.where === ‘function’) {
qb = qb.where(‘id’, String(cvSetupId));
} else if (typeof qb.filterWhere === ‘function’) {
qb = qb.filterWhere(‘id’, String(cvSetupId));
}

// Use DataSubscription directly (ihp-querybuilder in this app
// does not expose a .subscribe method on QueryBuilder)
const subscription = new DataSubscription(qb.query);

// Keep current results locally and invoke the provided callback
// with the full list whenever something changes
let current = ;

subscription.onReady = (rows) => {
current = rows || ;
callback(current);
};
subscription.onCreate = (row) => {
current = […current, row];
callback(current);
};
subscription.onUpdate = (id, changeSet) => {
current = current.map((r) => (r.id === id ? { …r, …changeSet } : r));
console.log(“on update”)
callback(current);
};
subscription.onDelete = (id) => {
current = current.filter((r) => r.id !== id);
callback(current);
};

// Expose a teardown handle for later cleanup
window._cvSetupsSubscription = subscription;
return () => subscription.close();
}

window.setupCvSetupsSubscription = setupCvSetupsSubscription

should be factorizable, simplifiable