From d1906262f4f64e0ded94eceb555c3da58a88ad1b Mon Sep 17 00:00:00 2001 From: Karthik Kalyanaraman Date: Thu, 12 Mar 2026 18:51:50 -0700 Subject: [PATCH 1/2] fix stale closure --- .../lib/client/hooks/use-events-list-data.ts | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/web/app/lib/client/hooks/use-events-list-data.ts b/packages/web/app/lib/client/hooks/use-events-list-data.ts index 6a621e54f0..da90fea69c 100644 --- a/packages/web/app/lib/client/hooks/use-events-list-data.ts +++ b/packages/web/app/lib/client/hooks/use-events-list-data.ts @@ -36,6 +36,9 @@ export function useEventsListData( const [loadingMore, setLoadingMore] = useState(false); const isFetchingRef = useRef(false); + const encryptionKeyRef = useRef(encryptionKey); + encryptionKeyRef.current = encryptionKey; + const fetchInitial = useCallback(async () => { if (isFetchingRef.current) return; isFetchingRef.current = true; @@ -56,7 +59,16 @@ export function useEventsListData( if (fetchError) { setError(fetchError); } else { - setEvents(result.data.map(hydrateResourceIO)); + const hydrated = result.data.map(hydrateResourceIO); + const key = encryptionKeyRef.current; + if (key) { + const decrypted = await Promise.all( + hydrated.map((ev) => hydrateResourceIOWithKey(ev, key)) + ); + setEvents(decrypted); + } else { + setEvents(hydrated); + } setCursor(result.hasMore ? result.cursor : undefined); setHasMore(Boolean(result.hasMore)); } @@ -66,8 +78,6 @@ export function useEventsListData( setLoading(false); isFetchingRef.current = false; } - // encryptionKey intentionally excluded — the re-hydration effect below - // handles decrypting in-memory events when the key arrives. }, [env, runId, sortOrder]); useEffect(() => { @@ -106,9 +116,10 @@ export function useEventsListData( } else { if (result.data.length > 0) { const hydrated = result.data.map(hydrateResourceIO); - if (encryptionKey) { + const key = encryptionKeyRef.current; + if (key) { const decrypted = await Promise.all( - hydrated.map((ev) => hydrateResourceIOWithKey(ev, encryptionKey)) + hydrated.map((ev) => hydrateResourceIOWithKey(ev, key)) ); setEvents((prev) => [...prev, ...decrypted]); } else { @@ -123,7 +134,7 @@ export function useEventsListData( } finally { setLoadingMore(false); } - }, [env, runId, sortOrder, cursor, loadingMore, encryptionKey]); + }, [env, runId, sortOrder, cursor, loadingMore]); return { events, From 2d90a3eb62c7cce114374fa1ee82c9e1a96c9fd3 Mon Sep 17 00:00:00 2001 From: Karthik Kalyanaraman Date: Thu, 12 Mar 2026 18:53:53 -0700 Subject: [PATCH 2/2] add changeset --- .changeset/lovely-shoes-shop.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/lovely-shoes-shop.md diff --git a/.changeset/lovely-shoes-shop.md b/.changeset/lovely-shoes-shop.md new file mode 100644 index 0000000000..e6458f4b1e --- /dev/null +++ b/.changeset/lovely-shoes-shop.md @@ -0,0 +1,5 @@ +--- +"@workflow/web": patch +--- + +Fix stale encryptionKey closure in events list data hook in web