@spidy092/auth-client 3.1.3 → 3.1.4
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/api.cjs +23 -0
- package/dist/api.cjs.map +1 -1
- package/dist/api.js +23 -0
- package/dist/api.js.map +1 -1
- package/dist/index.cjs +156 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +156 -30
- package/dist/index.js.map +1 -1
- package/dist/preferences.cjs +23 -0
- package/dist/preferences.cjs.map +1 -1
- package/dist/preferences.js +23 -0
- package/dist/preferences.js.map +1 -1
- package/dist/react/AuthProvider.cjs +165 -30
- package/dist/react/AuthProvider.cjs.map +1 -1
- package/dist/react/AuthProvider.js +165 -30
- package/dist/react/AuthProvider.js.map +1 -1
- package/dist/react/PreferencesProvider.cjs +23 -0
- package/dist/react/PreferencesProvider.cjs.map +1 -1
- package/dist/react/PreferencesProvider.js +23 -0
- package/dist/react/PreferencesProvider.js.map +1 -1
- package/dist/react/useAuth.cjs.map +1 -1
- package/dist/react/useAuth.js.map +1 -1
- package/dist/react/useSessionMonitor.cjs +23 -0
- package/dist/react/useSessionMonitor.cjs.map +1 -1
- package/dist/react/useSessionMonitor.js +23 -0
- package/dist/react/useSessionMonitor.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -340,6 +340,28 @@ function clearLoginLock() {
|
|
|
340
340
|
} catch {
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
|
+
async function reportClientDiagnostic(safe) {
|
|
344
|
+
if (typeof fetch !== "function" || typeof getToken !== "function") return;
|
|
345
|
+
if (safe.outcome === "SUCCESS" && !safe.event.startsWith("PROFILE_") && !safe.event.startsWith("SESSION_")) return;
|
|
346
|
+
const { authBaseUrl } = getConfig();
|
|
347
|
+
const token = getToken();
|
|
348
|
+
if (!authBaseUrl || !token) return;
|
|
349
|
+
try {
|
|
350
|
+
await fetch(`${authBaseUrl.replace(/\/+$/, "")}/client-telemetry`, {
|
|
351
|
+
method: "POST",
|
|
352
|
+
credentials: "include",
|
|
353
|
+
keepalive: true,
|
|
354
|
+
headers: {
|
|
355
|
+
"Content-Type": "application/json",
|
|
356
|
+
Authorization: `Bearer ${token}`,
|
|
357
|
+
"X-Correlation-ID": safe.correlationId,
|
|
358
|
+
"X-Request-ID": safe.correlationId
|
|
359
|
+
},
|
|
360
|
+
body: JSON.stringify(safe)
|
|
361
|
+
});
|
|
362
|
+
} catch {
|
|
363
|
+
}
|
|
364
|
+
}
|
|
343
365
|
async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
344
366
|
const context = getDiagnosticContext();
|
|
345
367
|
const safe = {
|
|
@@ -356,6 +378,7 @@ async function emitAuthDiagnostic(event, outcome, reasonCode, details = {}) {
|
|
|
356
378
|
};
|
|
357
379
|
const method = outcome === "FAILURE" ? "error" : outcome === "WARNING" ? "warn" : "info";
|
|
358
380
|
console[method]("[auth-client]", safe);
|
|
381
|
+
void reportClientDiagnostic(safe);
|
|
359
382
|
return safe;
|
|
360
383
|
}
|
|
361
384
|
|
|
@@ -1185,23 +1208,72 @@ var preferences = {
|
|
|
1185
1208
|
// react/AuthProvider.jsx
|
|
1186
1209
|
import React, { createContext, useState, useEffect, useRef } from "react";
|
|
1187
1210
|
var AuthContext = createContext();
|
|
1188
|
-
function AuthProvider({ children, onSessionExpired }) {
|
|
1211
|
+
function AuthProvider({ children, onSessionExpired, manageSessionSecurity = true }) {
|
|
1189
1212
|
const [token, setTokenState] = useState(getToken());
|
|
1190
1213
|
const [user, setUser] = useState(null);
|
|
1191
1214
|
const [loading, setLoading] = useState(!!token);
|
|
1192
1215
|
const [sessionValid, setSessionValid] = useState(true);
|
|
1193
1216
|
const sessionSecurityRef = useRef(null);
|
|
1217
|
+
const onSessionExpiredRef = useRef(onSessionExpired);
|
|
1218
|
+
const recoveryInFlightRef = useRef(null);
|
|
1219
|
+
const profileRecoveryTokensRef = useRef(/* @__PURE__ */ new Set());
|
|
1220
|
+
useEffect(() => {
|
|
1221
|
+
onSessionExpiredRef.current = onSessionExpired;
|
|
1222
|
+
}, [onSessionExpired]);
|
|
1223
|
+
useEffect(() => {
|
|
1224
|
+
const unsubscribe = addTokenListener((nextToken, previousToken) => {
|
|
1225
|
+
if (nextToken === previousToken) return;
|
|
1226
|
+
setTokenState(nextToken);
|
|
1227
|
+
if (nextToken) {
|
|
1228
|
+
setSessionValid(true);
|
|
1229
|
+
setLoading(true);
|
|
1230
|
+
} else {
|
|
1231
|
+
setSessionValid(false);
|
|
1232
|
+
setUser(null);
|
|
1233
|
+
setLoading(false);
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
return unsubscribe;
|
|
1237
|
+
}, []);
|
|
1238
|
+
const invalidateLocalSession = () => {
|
|
1239
|
+
clearToken();
|
|
1240
|
+
setTokenState(null);
|
|
1241
|
+
setUser(null);
|
|
1242
|
+
setSessionValid(false);
|
|
1243
|
+
setLoading(false);
|
|
1244
|
+
};
|
|
1194
1245
|
const handleSessionInvalid = (reason) => {
|
|
1195
1246
|
console.log("\u{1F6A8} AuthProvider: Session invalidated -", reason);
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1247
|
+
if (recoveryInFlightRef.current) return recoveryInFlightRef.current;
|
|
1248
|
+
const recover = async () => {
|
|
1249
|
+
const callback = onSessionExpiredRef.current;
|
|
1250
|
+
if (typeof callback === "function") {
|
|
1251
|
+
try {
|
|
1252
|
+
await callback(reason);
|
|
1253
|
+
const recoveredToken = getToken();
|
|
1254
|
+
if (recoveredToken) {
|
|
1255
|
+
setTokenState(recoveredToken);
|
|
1256
|
+
setSessionValid(true);
|
|
1257
|
+
setLoading(true);
|
|
1258
|
+
return true;
|
|
1259
|
+
}
|
|
1260
|
+
} catch (error) {
|
|
1261
|
+
await emitAuthDiagnostic("SESSION_RECOVERY_FAILED", "FAILURE", reason, {
|
|
1262
|
+
status: (error == null ? void 0 : error.status) || null,
|
|
1263
|
+
errorCode: (error == null ? void 0 : error.code) || null
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
invalidateLocalSession();
|
|
1268
|
+
return false;
|
|
1269
|
+
};
|
|
1270
|
+
recoveryInFlightRef.current = recover().finally(() => {
|
|
1271
|
+
recoveryInFlightRef.current = null;
|
|
1272
|
+
});
|
|
1273
|
+
return recoveryInFlightRef.current;
|
|
1202
1274
|
};
|
|
1203
1275
|
useEffect(() => {
|
|
1204
|
-
if (token && !sessionSecurityRef.current) {
|
|
1276
|
+
if (manageSessionSecurity && token && !sessionSecurityRef.current) {
|
|
1205
1277
|
console.log("\u{1F510} AuthProvider: Starting session security");
|
|
1206
1278
|
const unsubscribe = onSessionInvalid(handleSessionInvalid);
|
|
1207
1279
|
sessionSecurityRef.current = startSessionSecurity(handleSessionInvalid);
|
|
@@ -1213,11 +1285,11 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
1213
1285
|
}
|
|
1214
1286
|
};
|
|
1215
1287
|
}
|
|
1216
|
-
if (!token && sessionSecurityRef.current) {
|
|
1288
|
+
if ((!manageSessionSecurity || !token) && sessionSecurityRef.current) {
|
|
1217
1289
|
sessionSecurityRef.current.stopAll();
|
|
1218
1290
|
sessionSecurityRef.current = null;
|
|
1219
1291
|
}
|
|
1220
|
-
}, [token]);
|
|
1292
|
+
}, [manageSessionSecurity, token]);
|
|
1221
1293
|
useEffect(() => {
|
|
1222
1294
|
console.log("\u{1F50D} AuthProvider useEffect triggered:", {
|
|
1223
1295
|
hasToken: !!token,
|
|
@@ -1238,26 +1310,79 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
1238
1310
|
authBaseUrl,
|
|
1239
1311
|
tokenPreview: token.slice(0, 50) + "..."
|
|
1240
1312
|
});
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1313
|
+
let cancelled = false;
|
|
1314
|
+
const fetchProfile = async (accessToken2) => {
|
|
1315
|
+
const response = await fetch(`${authBaseUrl}/account/profile`, {
|
|
1316
|
+
headers: { Authorization: `Bearer ${accessToken2}` },
|
|
1317
|
+
credentials: "include"
|
|
1318
|
+
});
|
|
1319
|
+
console.log("\u{1F4E5} Profile response status:", response.status);
|
|
1320
|
+
if (!response.ok) {
|
|
1321
|
+
const error = new Error(`Profile request failed: ${response.status}`);
|
|
1322
|
+
error.status = response.status;
|
|
1323
|
+
throw error;
|
|
1324
|
+
}
|
|
1325
|
+
return response.json();
|
|
1326
|
+
};
|
|
1327
|
+
const loadProfile = async () => {
|
|
1328
|
+
try {
|
|
1329
|
+
const responseBody = await fetchProfile(token);
|
|
1330
|
+
if (cancelled) return;
|
|
1331
|
+
const userData = (responseBody == null ? void 0 : responseBody.data) ?? responseBody;
|
|
1332
|
+
console.log("\u2705 Profile fetched successfully:", userData.email);
|
|
1333
|
+
setUser(userData);
|
|
1334
|
+
setSessionValid(true);
|
|
1335
|
+
setLoading(false);
|
|
1336
|
+
} catch (error) {
|
|
1337
|
+
if (cancelled) return;
|
|
1338
|
+
const status = Number((error == null ? void 0 : error.status) || 0);
|
|
1339
|
+
const isUnauthorized = status === 401;
|
|
1340
|
+
const callback = onSessionExpiredRef.current;
|
|
1341
|
+
await emitAuthDiagnostic(
|
|
1342
|
+
"PROFILE_REQUEST_FAILED",
|
|
1343
|
+
isUnauthorized ? "FAILURE" : "WARNING",
|
|
1344
|
+
isUnauthorized ? "PROFILE_UNAUTHORIZED" : status ? `PROFILE_HTTP_${status}` : "PROFILE_NETWORK_ERROR",
|
|
1345
|
+
{ status, errorName: error == null ? void 0 : error.name, errorCode: error == null ? void 0 : error.code }
|
|
1346
|
+
);
|
|
1347
|
+
if (!isUnauthorized) {
|
|
1348
|
+
console.warn("\u26A0\uFE0F Profile unavailable; retaining the current auth session", error);
|
|
1349
|
+
setLoading(false);
|
|
1350
|
+
return;
|
|
1351
|
+
}
|
|
1352
|
+
if (typeof callback === "function" && !profileRecoveryTokensRef.current.has(token)) {
|
|
1353
|
+
profileRecoveryTokensRef.current.add(token);
|
|
1354
|
+
try {
|
|
1355
|
+
await callback("profile_unauthorized");
|
|
1356
|
+
const recoveredToken = getToken();
|
|
1357
|
+
if (recoveredToken && recoveredToken !== token) {
|
|
1358
|
+
setTokenState(recoveredToken);
|
|
1359
|
+
setSessionValid(true);
|
|
1360
|
+
setLoading(true);
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
if (recoveredToken) {
|
|
1364
|
+
const responseBody = await fetchProfile(recoveredToken);
|
|
1365
|
+
if (cancelled) return;
|
|
1366
|
+
const userData = (responseBody == null ? void 0 : responseBody.data) ?? responseBody;
|
|
1367
|
+
setUser(userData);
|
|
1368
|
+
setSessionValid(true);
|
|
1369
|
+
setLoading(false);
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
} catch (recoveryError) {
|
|
1373
|
+
await emitAuthDiagnostic("PROFILE_RECOVERY_FAILED", "FAILURE", "PROFILE_REFRESH_FAILED", {
|
|
1374
|
+
status: (recoveryError == null ? void 0 : recoveryError.status) || null,
|
|
1375
|
+
errorCode: (recoveryError == null ? void 0 : recoveryError.code) || null
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
invalidateLocalSession();
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
void loadProfile();
|
|
1383
|
+
return () => {
|
|
1384
|
+
cancelled = true;
|
|
1385
|
+
};
|
|
1261
1386
|
}, [token]);
|
|
1262
1387
|
const login2 = (clientKey, redirectUri, state) => {
|
|
1263
1388
|
login(clientKey, redirectUri, state);
|
|
@@ -1286,6 +1411,7 @@ function AuthProvider({ children, onSessionExpired }) {
|
|
|
1286
1411
|
setToken(newToken);
|
|
1287
1412
|
setTokenState(newToken);
|
|
1288
1413
|
setSessionValid(true);
|
|
1414
|
+
if (newToken) setLoading(true);
|
|
1289
1415
|
},
|
|
1290
1416
|
clearToken: () => {
|
|
1291
1417
|
stopSessionSecurity();
|