@adventurelabs/scout-core 2.0.8 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -35,6 +35,8 @@ barrel.
|
|
|
35
35
|
`ScoutRefreshProvider` accepts an existing browser Supabase client and otherwise
|
|
36
36
|
creates one stable client. Its automatic refresh uses a fresh IndexedDB cache
|
|
37
37
|
without another request; manual and reconnect refreshes still query the API.
|
|
38
|
+
Returning to a visible tab revalidates herd data and refreshes JWT mints that
|
|
39
|
+
are near expiry, covering browsers that suspend background timers.
|
|
38
40
|
Offline PWAs can pass a persisted `offlineUserId` to restore that user's herd
|
|
39
41
|
modules and JWT mints before online authentication is revalidated. Cached mints
|
|
40
42
|
remain available when expired; pass `false` as the fourth argument to
|
|
@@ -355,14 +355,25 @@ export function useScoutRefresh(options = {}, identityOptions = {}) {
|
|
|
355
355
|
useEffect(() => {
|
|
356
356
|
if (!autoRefresh || typeof window === "undefined")
|
|
357
357
|
return;
|
|
358
|
-
const
|
|
358
|
+
const revalidate = () => {
|
|
359
|
+
if (!navigator.onLine)
|
|
360
|
+
return;
|
|
359
361
|
const now = Date.now();
|
|
360
362
|
if (now - lastQueryAtRef.current >= onlineRefetchMinIntervalMs) {
|
|
361
363
|
void handleRefresh({ force: true });
|
|
362
364
|
}
|
|
363
365
|
};
|
|
364
|
-
|
|
365
|
-
|
|
366
|
+
const handleVisibilityChange = () => {
|
|
367
|
+
if (document.visibilityState === "visible") {
|
|
368
|
+
revalidate();
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
window.addEventListener("online", revalidate);
|
|
372
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
373
|
+
return () => {
|
|
374
|
+
window.removeEventListener("online", revalidate);
|
|
375
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
376
|
+
};
|
|
366
377
|
}, [autoRefresh, handleRefresh, onlineRefetchMinIntervalMs]);
|
|
367
378
|
const clearCache = useCallback(async () => {
|
|
368
379
|
try {
|
|
@@ -82,6 +82,7 @@ function useJwtMintLifecycle({ enabled, supabase, identity, cacheKey, ttlSec, re
|
|
|
82
82
|
const [mint, setMint] = useState(null);
|
|
83
83
|
const [inFlight, setInFlight] = useState(false);
|
|
84
84
|
const [error, setError] = useState(null);
|
|
85
|
+
const [offline, setOffline] = useState(isBrowserOffline);
|
|
85
86
|
const refreshIdRef = useRef(0);
|
|
86
87
|
const authUserIdRef = useRef(null);
|
|
87
88
|
const cacheHydrationIdRef = useRef(0);
|
|
@@ -101,7 +102,7 @@ function useJwtMintLifecycle({ enabled, supabase, identity, cacheKey, ttlSec, re
|
|
|
101
102
|
console.error("[ScoutRefreshProvider] User validation callback failed:", validationError);
|
|
102
103
|
}
|
|
103
104
|
}, [onUserValidated]);
|
|
104
|
-
const status = useMemo(() => derive_jwt_mint_status(enabled, mint, inFlight, error), [enabled, mint, inFlight, error]);
|
|
105
|
+
const status = useMemo(() => derive_jwt_mint_status(enabled, mint, inFlight, error, offline), [enabled, mint, inFlight, error, offline]);
|
|
105
106
|
const refreshMint = useCallback(async (force = true) => {
|
|
106
107
|
if (!enabled || isBrowserOffline())
|
|
107
108
|
return;
|
|
@@ -312,15 +313,36 @@ function useJwtMintLifecycle({ enabled, supabase, identity, cacheKey, ttlSec, re
|
|
|
312
313
|
}
|
|
313
314
|
});
|
|
314
315
|
const handleOnline = () => {
|
|
316
|
+
setOffline(false);
|
|
315
317
|
void refreshMint(false);
|
|
316
318
|
};
|
|
319
|
+
const handleOffline = () => {
|
|
320
|
+
setOffline(true);
|
|
321
|
+
};
|
|
322
|
+
const handleVisibilityChange = () => {
|
|
323
|
+
if (document.visibilityState !== "visible")
|
|
324
|
+
return;
|
|
325
|
+
const currentlyOffline = isBrowserOffline();
|
|
326
|
+
setOffline(currentlyOffline);
|
|
327
|
+
if (currentlyOffline)
|
|
328
|
+
return;
|
|
329
|
+
const currentMint = mintRef.current;
|
|
330
|
+
if (!currentMint ||
|
|
331
|
+
shouldRefreshMint(currentMint, ttlSec, refreshBeforeExpirySec)) {
|
|
332
|
+
void refreshMint(false);
|
|
333
|
+
}
|
|
334
|
+
};
|
|
317
335
|
window.addEventListener("online", handleOnline);
|
|
336
|
+
window.addEventListener("offline", handleOffline);
|
|
337
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
318
338
|
return () => {
|
|
319
339
|
cancelled = true;
|
|
320
340
|
cacheHydrationIdRef.current++;
|
|
321
341
|
refreshIdRef.current++;
|
|
322
342
|
unsubscribeAuth();
|
|
323
343
|
window.removeEventListener("online", handleOnline);
|
|
344
|
+
window.removeEventListener("offline", handleOffline);
|
|
345
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
324
346
|
};
|
|
325
347
|
}, [
|
|
326
348
|
enabled,
|
|
@@ -328,6 +350,8 @@ function useJwtMintLifecycle({ enabled, supabase, identity, cacheKey, ttlSec, re
|
|
|
328
350
|
offlineUserId,
|
|
329
351
|
validatedUserId,
|
|
330
352
|
cacheKey,
|
|
353
|
+
ttlSec,
|
|
354
|
+
refreshBeforeExpirySec,
|
|
331
355
|
refreshMint,
|
|
332
356
|
updateMint,
|
|
333
357
|
]);
|
package/dist/types/jwt_mint.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ export declare enum EnumJwtMintStatus {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function derive_jwt_mint_status(enabled: boolean, mint: {
|
|
9
9
|
token: string;
|
|
10
|
-
|
|
10
|
+
exp?: number;
|
|
11
|
+
} | null | undefined, inFlight: boolean, error: string | null, allowExpired?: boolean): EnumJwtMintStatus;
|
package/dist/types/jwt_mint.js
CHANGED
|
@@ -6,17 +6,18 @@ export var EnumJwtMintStatus;
|
|
|
6
6
|
EnumJwtMintStatus["READY"] = "ready";
|
|
7
7
|
EnumJwtMintStatus["ERROR"] = "error";
|
|
8
8
|
})(EnumJwtMintStatus || (EnumJwtMintStatus = {}));
|
|
9
|
-
export function derive_jwt_mint_status(enabled, mint, inFlight, error) {
|
|
9
|
+
export function derive_jwt_mint_status(enabled, mint, inFlight, error, allowExpired = false) {
|
|
10
10
|
if (!enabled) {
|
|
11
11
|
return EnumJwtMintStatus.IDLE;
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const expired = mint?.exp != null && mint.exp <= Math.floor(Date.now() / 1000);
|
|
14
|
+
const hasUsableMint = Boolean(mint?.token) && (allowExpired || !expired);
|
|
15
|
+
if (inFlight) {
|
|
16
|
+
return hasUsableMint
|
|
17
|
+
? EnumJwtMintStatus.REFRESHING
|
|
18
|
+
: EnumJwtMintStatus.LOADING;
|
|
15
19
|
}
|
|
16
|
-
if (
|
|
17
|
-
return EnumJwtMintStatus.REFRESHING;
|
|
18
|
-
}
|
|
19
|
-
if (mint?.token) {
|
|
20
|
+
if (hasUsableMint) {
|
|
20
21
|
return EnumJwtMintStatus.READY;
|
|
21
22
|
}
|
|
22
23
|
if (error) {
|