@adventurelabs/scout-core 2.0.10 → 2.0.12

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
@@ -44,6 +44,9 @@ remain available when expired; pass `false` as the fourth argument to
44
44
  not synthesize a Supabase `User` when no validated user is available.
45
45
  Use `createScoutBrowserClient()` when the application needs the same configured
46
46
  client outside the provider.
47
+ Provider descendants should call `useScoutRefreshActions()` for
48
+ `handleRefresh` and `clearCache` instead of creating another
49
+ `useScoutRefresh()` instance.
47
50
  Create Redux state explicitly with `configureScoutStore()` and keep that
48
51
  instance stable in the application provider.
49
52
 
@@ -1,4 +1,4 @@
1
- export { useScoutRefresh, type UseScoutRefreshOptions, } from "./useScoutRefresh";
1
+ export { useScoutRefresh, type ScoutRefreshRequest, type UseScoutRefreshOptions, } from "./useScoutRefresh";
2
2
  export { useScoutRealtimeBroadcast, type ScoutRealtimeBroadcastOptions, type ScoutRealtimeAuthErrorMode, } from "./useScoutRealtimeBroadcast";
3
3
  export { useScoutRealtimeConnectivity } from "./useScoutRealtimeConnectivity";
4
4
  export { useScoutRealtimeDevices } from "./useScoutRealtimeDevices";
@@ -62,6 +62,7 @@ export function useScoutRefresh(options = {}, identityOptions = {}) {
62
62
  const refreshIdRef = useRef(0);
63
63
  const refreshInProgressIdRef = useRef(null);
64
64
  const activeUserIdRef = useRef(null);
65
+ const signedOutRef = useRef(false);
65
66
  const validatedUserIdRef = useRef(null);
66
67
  const providedValidatedUserIdRef = useRef(validatedUserId);
67
68
  providedValidatedUserIdRef.current = validatedUserId;
@@ -334,6 +335,7 @@ export function useScoutRefresh(options = {}, identityOptions = {}) {
334
335
  useEffect(() => {
335
336
  return subscribeToSupabaseAuth(supabase, (event, session) => {
336
337
  if (event === "SIGNED_OUT") {
338
+ signedOutRef.current = true;
337
339
  const previousUserId = activeUserIdRef.current ?? scoutCache.getScopeUserId();
338
340
  refreshIdRef.current++;
339
341
  activeUserIdRef.current = null;
@@ -347,14 +349,22 @@ export function useScoutRefresh(options = {}, identityOptions = {}) {
347
349
  }
348
350
  const nextUserId = session?.user?.id;
349
351
  if (event === "SIGNED_IN" && nextUserId) {
352
+ const wasSignedOut = signedOutRef.current;
353
+ signedOutRef.current = false;
350
354
  validatedUserIdRef.current = nextUserId;
351
355
  notifyUserValidated(nextUserId);
352
- if (nextUserId === activeUserIdRef.current) {
356
+ const knownUserId = activeUserIdRef.current;
357
+ activeUserIdRef.current = nextUserId;
358
+ if (knownUserId === nextUserId) {
359
+ return;
360
+ }
361
+ if (knownUserId === null && !wasSignedOut) {
353
362
  return;
354
363
  }
355
364
  refreshIdRef.current++;
356
- activeUserIdRef.current = nextUserId;
357
- resetClientState();
365
+ if (knownUserId !== null) {
366
+ resetClientState();
367
+ }
358
368
  void handleRefresh({ force: true });
359
369
  }
360
370
  });
@@ -1,4 +1,4 @@
1
- import { type UseScoutRefreshOptions } from "../hooks/useScoutRefresh";
1
+ import { type ScoutRefreshRequest, type UseScoutRefreshOptions } from "../hooks/useScoutRefresh";
2
2
  import { type ReactNode } from "react";
3
3
  import { SupabaseClient } from "@supabase/supabase-js";
4
4
  import { Database } from "../types/supabase";
@@ -25,7 +25,12 @@ export interface PubsubTokenMintState {
25
25
  error: string | null;
26
26
  refreshMint: () => Promise<void>;
27
27
  }
28
+ export interface ScoutRefreshActions {
29
+ handleRefresh: (request?: ScoutRefreshRequest) => Promise<void>;
30
+ clearCache: () => Promise<void>;
31
+ }
28
32
  export declare function useSupabase(): SupabaseClient<Database>;
33
+ export declare function useScoutRefreshActions(): ScoutRefreshActions;
29
34
  export declare function useClientAbilitiesMint(): ClientAbilitiesMintState;
30
35
  export declare function useOptionalClientAbilitiesMint(): ClientAbilitiesMintState | null;
31
36
  export declare function usePubsubTokenMint(): PubsubTokenMintState;
@@ -37,6 +37,10 @@ function useScoutRefreshContext() {
37
37
  export function useSupabase() {
38
38
  return useScoutRefreshContext().supabase;
39
39
  }
40
+ export function useScoutRefreshActions() {
41
+ const { handleRefresh, clearCache } = useScoutRefreshContext();
42
+ return useMemo(() => ({ handleRefresh, clearCache }), [handleRefresh, clearCache]);
43
+ }
40
44
  export function useClientAbilitiesMint() {
41
45
  return useScoutRefreshContext().abilities;
42
46
  }
@@ -282,7 +286,12 @@ function useJwtMintLifecycle({ enabled, supabase, identity, cacheKey, ttlSec, re
282
286
  authUserIdRef.current !== userId) {
283
287
  return;
284
288
  }
285
- updateMint(cached.data);
289
+ if (cached.data && !cached.isStale) {
290
+ updateMint(cached.data);
291
+ }
292
+ else if (!mintRef.current) {
293
+ updateMint(cached.data);
294
+ }
286
295
  }
287
296
  catch (cacheError) {
288
297
  console.warn(`[ScoutRefreshProvider] ${cacheKey} cache load failed:`, cacheError);
@@ -481,9 +490,15 @@ export function ScoutRefreshProvider({ children, abilityParams, supabase: supaba
481
490
  }
482
491
  const abilitiesConfig = useMemo(() => resolveAbilityParams(abilityParams), [abilityParams]);
483
492
  const { identity, renderChildren } = useScoutIdentity(supabase, refreshOptions.offlineUserId);
484
- useScoutRefresh({ ...refreshOptions, supabase }, identity);
493
+ const { handleRefresh, clearCache } = useScoutRefresh({ ...refreshOptions, supabase }, identity);
485
494
  const abilities = useClientAbilitiesMintLifecycle(supabase, abilitiesConfig, identity);
486
495
  const pubsub = usePubsubTokenMintLifecycle(supabase, abilitiesConfig, identity);
487
- const value = useMemo(() => ({ supabase, abilities, pubsub }), [supabase, abilities, pubsub]);
496
+ const value = useMemo(() => ({
497
+ supabase,
498
+ abilities,
499
+ pubsub,
500
+ handleRefresh,
501
+ clearCache,
502
+ }), [supabase, abilities, pubsub, handleRefresh, clearCache]);
488
503
  return (_jsx(ScoutRefreshContext.Provider, { value: value, children: renderChildren ? children : null }));
489
504
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
4
4
  "description": "Core utilities and helpers for Adventure Labs Scout applications",
5
5
  "exports": {
6
6
  "./client": {