@adventurelabs/scout-core 1.4.75 → 1.4.78
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/dist/helpers/cache.d.ts +10 -0
- package/dist/helpers/cache.js +86 -2
- package/dist/helpers/client_abilities_token.d.ts +0 -1
- package/dist/helpers/client_abilities_token.js +0 -1
- package/dist/helpers/herd_modules_equal.d.ts +2 -0
- package/dist/helpers/herd_modules_equal.js +28 -0
- package/dist/helpers/pubsub_token.d.ts +3 -1
- package/dist/helpers/pubsub_token.js +41 -0
- package/dist/helpers/versions_software.d.ts +0 -1
- package/dist/helpers/versions_software.js +0 -14
- package/dist/helpers/versions_software_server.d.ts +0 -1
- package/dist/helpers/versions_software_server.js +0 -16
- package/dist/hooks/useScoutRefresh.js +13 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/providers/ScoutRefreshProvider.d.ts +12 -11
- package/dist/providers/ScoutRefreshProvider.js +85 -31
- package/dist/store/api.d.ts +722 -130
- package/dist/store/scout.d.ts +0 -106
- package/dist/store/scout.js +6 -2
- package/dist/types/client_abilities_token.d.ts +1 -6
- package/dist/types/client_abilities_token.js +5 -3
- package/dist/types/jwt_mint.d.ts +10 -0
- package/dist/types/jwt_mint.js +26 -0
- package/dist/types/pubsub_token.d.ts +5 -0
- package/dist/types/pubsub_token.js +1 -1
- package/package.json +3 -1
|
@@ -6,6 +6,10 @@ import { createBrowserClient } from "@supabase/ssr";
|
|
|
6
6
|
import { CLIENT_ABILITIES_TOKEN_TTL_SEC, } from "../types/client_abilities_token";
|
|
7
7
|
import { EnumWebResponse } from "../types/requests";
|
|
8
8
|
import { get_client_abilities_jwt_public_keys, mint_client_abilities_token, verify_client_abilities_token, } from "../helpers/client_abilities_token";
|
|
9
|
+
import { scoutCache } from "../helpers/cache";
|
|
10
|
+
import { get_pubsub_jwt_public_keys, mint_pubsub_token, verify_pubsub_token, } from "../helpers/pubsub_token";
|
|
11
|
+
import { PUBSUB_TOKEN_TTL_SEC } from "../types/pubsub_token";
|
|
12
|
+
import { derive_jwt_mint_status, } from "../types/jwt_mint";
|
|
9
13
|
const ScoutRefreshContext = createContext(null);
|
|
10
14
|
const DEFAULT_REFRESH_BEFORE_EXPIRY_SEC = 120;
|
|
11
15
|
const DEFAULT_PUBLIC_KEYS_CACHE_MS = 10 * 60 * 1000;
|
|
@@ -25,102 +29,123 @@ function useScoutRefreshContext() {
|
|
|
25
29
|
export function useSupabase() {
|
|
26
30
|
return useScoutRefreshContext().supabase;
|
|
27
31
|
}
|
|
28
|
-
/** Verified client abilities JWT (minted on a schedule by ScoutRefreshProvider). */
|
|
29
32
|
export function useClientAbilitiesMint() {
|
|
30
33
|
return useScoutRefreshContext().abilities;
|
|
31
34
|
}
|
|
35
|
+
export function usePubsubTokenMint() {
|
|
36
|
+
return useScoutRefreshContext().pubsub;
|
|
37
|
+
}
|
|
32
38
|
function resolveAbilityParams(abilityParams) {
|
|
33
39
|
return {
|
|
34
40
|
mintClientAbilitiesToken: abilityParams?.mintClientAbilitiesToken ?? true,
|
|
41
|
+
mintPubsubToken: abilityParams?.mintPubsubToken ?? false,
|
|
35
42
|
clientAbilitiesTokenTtlSec: abilityParams?.clientAbilitiesTokenTtlSec ??
|
|
36
43
|
CLIENT_ABILITIES_TOKEN_TTL_SEC,
|
|
44
|
+
pubsubTokenTtlSec: abilityParams?.pubsubTokenTtlSec ?? PUBSUB_TOKEN_TTL_SEC,
|
|
37
45
|
refreshBeforeExpirySec: abilityParams?.refreshBeforeExpirySec ??
|
|
38
46
|
DEFAULT_REFRESH_BEFORE_EXPIRY_SEC,
|
|
39
47
|
publicKeysCacheTtlMs: abilityParams?.publicKeysCacheTtlMs ?? DEFAULT_PUBLIC_KEYS_CACHE_MS,
|
|
40
48
|
};
|
|
41
49
|
}
|
|
42
|
-
function
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
const [error, setError] = useState(null);
|
|
47
|
-
const inFlightRef = useRef(false);
|
|
48
|
-
const publicKeysRef = useRef(null);
|
|
49
|
-
const publicKeysAtRef = useRef(0);
|
|
50
|
-
const loadPublicKeys = useCallback(async (force = false) => {
|
|
50
|
+
function useCachedPublicKeys(supabase, publicKeysCacheTtlMs, fetchKeys) {
|
|
51
|
+
const keysRef = useRef(null);
|
|
52
|
+
const keysAtRef = useRef(0);
|
|
53
|
+
return useCallback(async (force = false) => {
|
|
51
54
|
const now = Date.now();
|
|
52
55
|
if (!force &&
|
|
53
|
-
|
|
54
|
-
now -
|
|
55
|
-
return
|
|
56
|
+
keysRef.current?.length &&
|
|
57
|
+
now - keysAtRef.current < publicKeysCacheTtlMs) {
|
|
58
|
+
return keysRef.current;
|
|
56
59
|
}
|
|
57
|
-
const { status, data, msg } = await
|
|
60
|
+
const { status, data, msg } = await fetchKeys(supabase);
|
|
58
61
|
if (status !== EnumWebResponse.SUCCESS || !data?.length) {
|
|
59
|
-
throw new Error(msg ?? "
|
|
62
|
+
throw new Error(msg ?? "jwt public keys RPC returned no keys");
|
|
60
63
|
}
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
keysRef.current = data;
|
|
65
|
+
keysAtRef.current = now;
|
|
63
66
|
return data;
|
|
64
|
-
}, [supabase, publicKeysCacheTtlMs]);
|
|
67
|
+
}, [supabase, publicKeysCacheTtlMs, fetchKeys]);
|
|
68
|
+
}
|
|
69
|
+
function useJwtMintLifecycle({ enabled, supabase, cacheKey, ttlSec, refreshBeforeExpirySec, loadPublicKeys, mintToken, verifyToken, }) {
|
|
70
|
+
const [mint, setMint] = useState(null);
|
|
71
|
+
const [inFlight, setInFlight] = useState(false);
|
|
72
|
+
const [error, setError] = useState(null);
|
|
73
|
+
const inFlightRef = useRef(false);
|
|
74
|
+
const status = useMemo(() => derive_jwt_mint_status(enabled, mint, inFlight, error), [enabled, mint, inFlight, error]);
|
|
65
75
|
const refreshMint = useCallback(async () => {
|
|
66
76
|
if (!enabled || inFlightRef.current) {
|
|
67
77
|
return;
|
|
68
78
|
}
|
|
69
79
|
inFlightRef.current = true;
|
|
70
|
-
|
|
80
|
+
setInFlight(true);
|
|
71
81
|
setError(null);
|
|
72
82
|
try {
|
|
73
83
|
const { data: { session }, } = await supabase.auth.getSession();
|
|
74
84
|
if (!session) {
|
|
75
85
|
setMint(null);
|
|
86
|
+
await scoutCache.clearJwtMint(cacheKey);
|
|
76
87
|
return;
|
|
77
88
|
}
|
|
78
|
-
const mintResponse = await
|
|
89
|
+
const mintResponse = await mintToken(supabase);
|
|
79
90
|
if (mintResponse.status !== EnumWebResponse.SUCCESS ||
|
|
80
91
|
!mintResponse.data) {
|
|
81
|
-
setMint(null);
|
|
82
92
|
setError(mintResponse.msg ?? "mint failed");
|
|
83
93
|
return;
|
|
84
94
|
}
|
|
85
95
|
let keys = await loadPublicKeys();
|
|
86
96
|
let verified;
|
|
87
97
|
try {
|
|
88
|
-
verified = await
|
|
98
|
+
verified = await verifyToken(mintResponse.data, keys);
|
|
89
99
|
}
|
|
90
100
|
catch {
|
|
91
101
|
keys = await loadPublicKeys(true);
|
|
92
|
-
verified = await
|
|
102
|
+
verified = await verifyToken(mintResponse.data, keys);
|
|
93
103
|
}
|
|
94
104
|
setMint(verified);
|
|
105
|
+
try {
|
|
106
|
+
await scoutCache.setJwtMint(cacheKey, verified);
|
|
107
|
+
}
|
|
108
|
+
catch (cacheError) {
|
|
109
|
+
console.warn(`[ScoutRefreshProvider] ${cacheKey} cache save failed:`, cacheError);
|
|
110
|
+
}
|
|
95
111
|
}
|
|
96
112
|
catch (e) {
|
|
97
|
-
|
|
98
|
-
setError(e instanceof Error ? e.message : "client abilities mint failed");
|
|
113
|
+
setError(e instanceof Error ? e.message : "mint failed");
|
|
99
114
|
}
|
|
100
115
|
finally {
|
|
101
116
|
inFlightRef.current = false;
|
|
102
|
-
|
|
117
|
+
setInFlight(false);
|
|
103
118
|
}
|
|
104
|
-
}, [enabled, supabase, loadPublicKeys]);
|
|
119
|
+
}, [enabled, supabase, cacheKey, loadPublicKeys, mintToken, verifyToken]);
|
|
105
120
|
useEffect(() => {
|
|
106
121
|
if (!enabled) {
|
|
107
122
|
setMint(null);
|
|
108
123
|
setError(null);
|
|
109
124
|
return;
|
|
110
125
|
}
|
|
126
|
+
let cancelled = false;
|
|
127
|
+
void scoutCache.getJwtMint(cacheKey).then((cached) => {
|
|
128
|
+
if (!cancelled && cached.data) {
|
|
129
|
+
setMint(cached.data);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
111
132
|
void refreshMint();
|
|
112
133
|
const { data: { subscription }, } = supabase.auth.onAuthStateChange((event) => {
|
|
113
134
|
if (event === "SIGNED_OUT") {
|
|
114
135
|
setMint(null);
|
|
115
136
|
setError(null);
|
|
137
|
+
void scoutCache.clearJwtMint(cacheKey);
|
|
116
138
|
return;
|
|
117
139
|
}
|
|
118
140
|
if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
|
|
119
141
|
void refreshMint();
|
|
120
142
|
}
|
|
121
143
|
});
|
|
122
|
-
return () =>
|
|
123
|
-
|
|
144
|
+
return () => {
|
|
145
|
+
cancelled = true;
|
|
146
|
+
subscription.unsubscribe();
|
|
147
|
+
};
|
|
148
|
+
}, [enabled, supabase, cacheKey, refreshMint]);
|
|
124
149
|
useEffect(() => {
|
|
125
150
|
if (!enabled || !mint) {
|
|
126
151
|
return;
|
|
@@ -134,7 +159,35 @@ function useClientAbilitiesMintLifecycle(supabase, config) {
|
|
|
134
159
|
}, delayMs);
|
|
135
160
|
return () => clearTimeout(timer);
|
|
136
161
|
}, [enabled, mint, ttlSec, refreshBeforeExpirySec, refreshMint]);
|
|
137
|
-
return useMemo(() => ({ mint,
|
|
162
|
+
return useMemo(() => ({ mint, status, error, refreshMint }), [mint, status, error, refreshMint]);
|
|
163
|
+
}
|
|
164
|
+
function useClientAbilitiesMintLifecycle(supabase, config) {
|
|
165
|
+
const { mintClientAbilitiesToken: enabled, clientAbilitiesTokenTtlSec: ttlSec, refreshBeforeExpirySec, publicKeysCacheTtlMs, } = config;
|
|
166
|
+
const loadPublicKeys = useCachedPublicKeys(supabase, publicKeysCacheTtlMs, get_client_abilities_jwt_public_keys);
|
|
167
|
+
return useJwtMintLifecycle({
|
|
168
|
+
enabled,
|
|
169
|
+
supabase,
|
|
170
|
+
cacheKey: "client_abilities",
|
|
171
|
+
ttlSec,
|
|
172
|
+
refreshBeforeExpirySec,
|
|
173
|
+
loadPublicKeys,
|
|
174
|
+
mintToken: mint_client_abilities_token,
|
|
175
|
+
verifyToken: verify_client_abilities_token,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function usePubsubTokenMintLifecycle(supabase, config) {
|
|
179
|
+
const { mintPubsubToken: enabled, pubsubTokenTtlSec: ttlSec, refreshBeforeExpirySec, publicKeysCacheTtlMs, } = config;
|
|
180
|
+
const loadPublicKeys = useCachedPublicKeys(supabase, publicKeysCacheTtlMs, get_pubsub_jwt_public_keys);
|
|
181
|
+
return useJwtMintLifecycle({
|
|
182
|
+
enabled,
|
|
183
|
+
supabase,
|
|
184
|
+
cacheKey: "pubsub",
|
|
185
|
+
ttlSec,
|
|
186
|
+
refreshBeforeExpirySec,
|
|
187
|
+
loadPublicKeys,
|
|
188
|
+
mintToken: mint_pubsub_token,
|
|
189
|
+
verifyToken: verify_pubsub_token,
|
|
190
|
+
});
|
|
138
191
|
}
|
|
139
192
|
export function ScoutRefreshProvider({ children, abilityParams, ...refreshOptions }) {
|
|
140
193
|
const urlRef = useRef(process.env.NEXT_PUBLIC_SUPABASE_URL || "");
|
|
@@ -143,6 +196,7 @@ export function ScoutRefreshProvider({ children, abilityParams, ...refreshOption
|
|
|
143
196
|
const abilitiesConfig = useMemo(() => resolveAbilityParams(abilityParams), [abilityParams]);
|
|
144
197
|
useScoutRefresh({ ...refreshOptions, supabase });
|
|
145
198
|
const abilities = useClientAbilitiesMintLifecycle(supabase, abilitiesConfig);
|
|
146
|
-
const
|
|
199
|
+
const pubsub = usePubsubTokenMintLifecycle(supabase, abilitiesConfig);
|
|
200
|
+
const value = useMemo(() => ({ supabase, abilities, pubsub }), [supabase, abilities, pubsub]);
|
|
147
201
|
return (_jsx(ScoutRefreshContext.Provider, { value: value, children: children }));
|
|
148
202
|
}
|