cover TODOs + cross-tab cache

This commit is contained in:
Igor Loskutov
2025-09-03 07:57:11 -04:00
parent 048ebbd654
commit cff662709d
7 changed files with 138 additions and 59 deletions

View File

@@ -1,16 +1,16 @@
"use client";
import { Flex, Spinner } from "@chakra-ui/react";
import useAuthReady from "../lib/useAuthReady";
import { useAuth } from "../lib/AuthProvider";
export default function AuthWrapper({
children,
}: {
children: React.ReactNode;
}) {
const { isLoading } = useAuthReady();
const auth = useAuth();
if (isLoading) {
if (auth.status === "loading") {
return (
<Flex
flexDir="column"

View File

@@ -4,23 +4,16 @@ import { $api } from "./apiClient";
import { useError } from "../(errors)/errorContext";
import { useQueryClient } from "@tanstack/react-query";
import type { components, paths } from "../reflector-api";
import useAuthReady from "./useAuthReady";
import { useAuth } from "./AuthProvider";
// FIXME: React Query caching issues with cross-tab synchronization
//
// The default React Query behavior caches data indefinitely until invalidated,
// which should work well in theory. However, we're experiencing two problems:
//
// 1. Navigation between pages doesn't refresh data as expected by users
// 2. Query invalidation doesn't work properly across browser tabs - changes
// made in one tab (like updating room settings or deleting transcripts)
// aren't reflected when navigating in another tab without a full page refresh
//
// As a temporary workaround, we're setting a short staleTime to force data
// reloading, similar to our previous implementation. This should be revisited
// once we can resolve the underlying invalidation and cross-tab sync issues.
// 500ms is arbitrary.
const STALE_TIME = 500;
const useAuthReady = () => {
const auth = useAuth();
return {
isAuthenticated: auth.status === "authenticated",
isLoading: auth.status === "loading",
};
};
export function useRoomsList(page: number = 1) {
const { isAuthenticated } = useAuthReady();
@@ -35,7 +28,6 @@ export function useRoomsList(page: number = 1) {
},
{
enabled: isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -69,7 +61,6 @@ export function useTranscriptsSearch(
},
{
enabled: isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -115,7 +106,6 @@ export function useTranscriptGet(transcriptId: string | null) {
},
{
enabled: !!transcriptId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -133,7 +123,6 @@ export function useRoomGet(roomId: string | null) {
},
{
enabled: !!roomId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -205,7 +194,6 @@ export function useZulipStreams() {
{},
{
enabled: isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -225,7 +213,6 @@ export function useZulipTopics(streamId: number | null) {
},
{
enabled,
staleTime: STALE_TIME,
},
);
}
@@ -302,7 +289,6 @@ export function useTranscriptWaveform(transcriptId: string | null) {
},
{
enabled: !!transcriptId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -320,7 +306,6 @@ export function useTranscriptMP3(transcriptId: string | null) {
},
{
enabled: !!transcriptId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -338,7 +323,6 @@ export function useTranscriptTopics(transcriptId: string | null) {
},
{
enabled: !!transcriptId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -356,7 +340,6 @@ export function useTranscriptTopicsWithWords(transcriptId: string | null) {
},
{
enabled: !!transcriptId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -380,7 +363,6 @@ export function useTranscriptTopicsWithWordsPerSpeaker(
},
{
enabled: !!transcriptId && !!topicId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}
@@ -398,7 +380,6 @@ export function useTranscriptParticipants(transcriptId: string | null) {
},
{
enabled: !!transcriptId && isAuthenticated,
staleTime: STALE_TIME,
},
);
}

View File

@@ -1,6 +1,7 @@
"use client";
import { QueryClient } from "@tanstack/react-query";
import { broadcastQueryClient } from "@tanstack/query-broadcast-client-experimental";
export const queryClient = new QueryClient({
defaultOptions: {
@@ -15,3 +16,8 @@ export const queryClient = new QueryClient({
},
},
});
broadcastQueryClient({
queryClient,
broadcastChannel: "reflector-query-client",
});

View File

@@ -18,7 +18,8 @@ export interface CustomSession extends Session {
};
}
// assumption that JWT is JWTWithAccessToken - not ideal, TODO find a reason we have to do that
// assumption that JWT is JWTWithAccessToken - we set it in jwt callback of auth; typing isn't strong around there
// but the assumption is crucial to auth working
export const assertExtendedToken = <T>(
t: T,
): T & {

View File

@@ -1,13 +0,0 @@
"use client";
import { useAuth } from "./AuthProvider";
// TODO
export default function useAuthReady() {
const auth = useAuth();
return {
isAuthenticated: auth.status === "authenticated",
isLoading: auth.status === "loading",
};
}

View File

@@ -17,7 +17,8 @@
"@fortawesome/free-solid-svg-icons": "^6.4.0",
"@fortawesome/react-fontawesome": "^0.2.0",
"@sentry/nextjs": "^7.77.0",
"@tanstack/react-query": "^5.85.5",
"@tanstack/query-broadcast-client-experimental": "^5.85.9",
"@tanstack/react-query": "^5.85.9",
"@vercel/edge-config": "^0.4.1",
"@whereby.com/browser-sdk": "^3.3.4",
"autoprefixer": "10.4.20",

129
www/pnpm-lock.yaml generated
View File

@@ -25,9 +25,12 @@ importers:
"@sentry/nextjs":
specifier: ^7.77.0
version: 7.120.4(next@14.2.31(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.90.0))(react@18.3.1)
"@tanstack/query-broadcast-client-experimental":
specifier: ^5.85.9
version: 5.85.9
"@tanstack/react-query":
specifier: ^5.85.5
version: 5.85.5(react@18.3.1)
specifier: ^5.85.9
version: 5.85.9(react@18.3.1)
"@vercel/edge-config":
specifier: ^0.4.1
version: 0.4.1
@@ -72,7 +75,7 @@ importers:
version: 0.14.0
openapi-react-query:
specifier: ^0.5.0
version: 0.5.0(@tanstack/react-query@5.85.5(react@18.3.1))(openapi-fetch@0.14.0)
version: 0.5.0(@tanstack/react-query@5.85.9(react@18.3.1))(openapi-fetch@0.14.0)
postcss:
specifier: 8.4.31
version: 8.4.31
@@ -196,6 +199,13 @@ packages:
engines: { node: ">=6.0.0" }
hasBin: true
"@babel/runtime@7.27.0":
resolution:
{
integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==,
}
engines: { node: ">=6.9.0" }
"@babel/runtime@7.28.2":
resolution:
{
@@ -1408,16 +1418,22 @@ packages:
integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==,
}
"@tanstack/query-core@5.85.5":
"@tanstack/query-broadcast-client-experimental@5.85.9":
resolution:
{
integrity: sha512-KO0WTob4JEApv69iYp1eGvfMSUkgw//IpMnq+//cORBzXf0smyRwPLrUvEe5qtAEGjwZTXrjxg+oJNP/C00t6w==,
integrity: sha512-8UOwzQ16BAJwoTo584ZciRcT2sOw5DPsCRwQVDvST3ri8stDCj2CRQ9BxL9BIjkwICMuyNFQDc6Xgh1Coh9uyw==,
}
"@tanstack/react-query@5.85.5":
"@tanstack/query-core@5.85.9":
resolution:
{
integrity: sha512-/X4EFNcnPiSs8wM2v+b6DqS5mmGeuJQvxBglmDxl6ZQb5V26ouD2SJYAcC3VjbNwqhY2zjxVD15rDA5nGbMn3A==,
integrity: sha512-5fxb9vwyftYE6KFLhhhDyLr8NO75+Wpu7pmTo+TkwKmMX2oxZDoLwcqGP8ItKSpUMwk3urWgQDZfyWr5Jm9LsQ==,
}
"@tanstack/react-query@5.85.9":
resolution:
{
integrity: sha512-2T5zgSpcOZXGkH/UObIbIkGmUPQqZqn7esVQFXLOze622h4spgWf5jmvrqAo9dnI13/hyMcNsF1jsoDcb59nJQ==,
}
peerDependencies:
react: ^18 || ^19
@@ -2820,6 +2836,12 @@ packages:
}
engines: { node: ">=8" }
broadcast-channel@7.1.0:
resolution:
{
integrity: sha512-InJljddsYWbEL8LBnopnCg+qMQp9KcowvYWOt4YWrjD5HmxzDYKdVbDS1w/ji5rFZdRD58V5UxJPtBdpEbEJYw==,
}
browserslist@4.25.2:
resolution:
{
@@ -3893,6 +3915,12 @@ packages:
}
engines: { node: ">=10.13.0" }
eventemitter3@4.0.7:
resolution:
{
integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==,
}
events-intercept@2.0.0:
resolution:
{
@@ -5669,6 +5697,13 @@ packages:
}
engines: { node: ">= 0.4" }
oblivious-set@1.4.0:
resolution:
{
integrity: sha512-szyd0ou0T8nsAqHtprRcP3WidfsN1TnAR5yWXf2mFCEr5ek3LEOkT6EZ/92Xfs74HIdyhG5WkGxIssMU0jBaeg==,
}
engines: { node: ">=16" }
oidc-token-hash@5.1.1:
resolution:
{
@@ -5752,6 +5787,13 @@ packages:
}
engines: { node: ">= 0.4" }
p-finally@1.0.0:
resolution:
{
integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==,
}
engines: { node: ">=4" }
p-finally@2.0.1:
resolution:
{
@@ -5773,6 +5815,20 @@ packages:
}
engines: { node: ">=10" }
p-queue@6.6.2:
resolution:
{
integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==,
}
engines: { node: ">=8" }
p-timeout@3.2.0:
resolution:
{
integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==,
}
engines: { node: ">=8" }
package-json-from-dist@1.0.1:
resolution:
{
@@ -6302,6 +6358,12 @@ packages:
}
engines: { node: ">= 0.4" }
regenerator-runtime@0.14.1:
resolution:
{
integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==,
}
regexp.prototype.flags@1.5.4:
resolution:
{
@@ -7215,6 +7277,12 @@ packages:
}
engines: { node: ">= 10.0.0" }
unload@2.4.1:
resolution:
{
integrity: sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw==,
}
unpipe@1.0.0:
resolution:
{
@@ -7668,6 +7736,10 @@ snapshots:
dependencies:
"@babel/types": 7.28.2
"@babel/runtime@7.27.0":
dependencies:
regenerator-runtime: 0.14.1
"@babel/runtime@7.28.2": {}
"@babel/template@7.27.2":
@@ -8473,11 +8545,16 @@ snapshots:
"@swc/counter": 0.1.3
tslib: 2.8.1
"@tanstack/query-core@5.85.5": {}
"@tanstack/react-query@5.85.5(react@18.3.1)":
"@tanstack/query-broadcast-client-experimental@5.85.9":
dependencies:
"@tanstack/query-core": 5.85.5
"@tanstack/query-core": 5.85.9
broadcast-channel: 7.1.0
"@tanstack/query-core@5.85.9": {}
"@tanstack/react-query@5.85.9(react@18.3.1)":
dependencies:
"@tanstack/query-core": 5.85.9
react: 18.3.1
"@tootallnate/once@2.0.0": {}
@@ -9677,6 +9754,13 @@ snapshots:
dependencies:
fill-range: 7.1.1
broadcast-channel@7.1.0:
dependencies:
"@babel/runtime": 7.27.0
oblivious-set: 1.4.0
p-queue: 6.6.2
unload: 2.4.1
browserslist@4.25.2:
dependencies:
caniuse-lite: 1.0.30001734
@@ -10402,6 +10486,8 @@ snapshots:
event-target-shim@6.0.2: {}
eventemitter3@4.0.7: {}
events-intercept@2.0.0: {}
events@3.3.0: {}
@@ -11570,6 +11656,8 @@ snapshots:
define-properties: 1.2.1
es-object-atoms: 1.1.1
oblivious-set@1.4.0: {}
oidc-token-hash@5.1.1: {}
once@1.3.3:
@@ -11588,9 +11676,9 @@ snapshots:
dependencies:
openapi-typescript-helpers: 0.0.15
openapi-react-query@0.5.0(@tanstack/react-query@5.85.5(react@18.3.1))(openapi-fetch@0.14.0):
openapi-react-query@0.5.0(@tanstack/react-query@5.85.9(react@18.3.1))(openapi-fetch@0.14.0):
dependencies:
"@tanstack/react-query": 5.85.5(react@18.3.1)
"@tanstack/react-query": 5.85.9(react@18.3.1)
openapi-fetch: 0.14.0
openapi-typescript-helpers: 0.0.15
@@ -11630,6 +11718,8 @@ snapshots:
object-keys: 1.1.1
safe-push-apply: 1.0.0
p-finally@1.0.0: {}
p-finally@2.0.1: {}
p-limit@3.1.0:
@@ -11640,6 +11730,15 @@ snapshots:
dependencies:
p-limit: 3.1.0
p-queue@6.6.2:
dependencies:
eventemitter3: 4.0.7
p-timeout: 3.2.0
p-timeout@3.2.0:
dependencies:
p-finally: 1.0.0
package-json-from-dist@1.0.1: {}
parent-module@1.0.1:
@@ -11940,6 +12039,8 @@ snapshots:
get-proto: 1.0.1
which-builtin-type: 1.2.1
regenerator-runtime@0.14.1: {}
regexp.prototype.flags@1.5.4:
dependencies:
call-bind: 1.0.8
@@ -12576,6 +12677,8 @@ snapshots:
universalify@2.0.1: {}
unload@2.4.1: {}
unpipe@1.0.0: {}
unrs-resolver@1.11.1: