varminer-app-header 2.2.3 → 2.2.5

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/index.js CHANGED
@@ -421,17 +421,161 @@ function getAccessTokenFromAuth(auth) {
421
421
  auth.token;
422
422
  return typeof token === "string" && token.length > 0 ? token : undefined;
423
423
  }
424
- const fetchProfilePictureAsBlobUrl = async (baseUrl = "http://objectstore.impact0mics.local:9012") => {
424
+ /** True if string looks like a JWT (three base64 parts) or a bearer token, not JSON. */
425
+ function looksLikeToken(s) {
426
+ return s.length > 0 && !s.trimStart().startsWith("{") && !s.trimStart().startsWith("[");
427
+ }
428
+ /** Recursively find first string value at keys accessToken, access_token, or token. */
429
+ function findTokenInObject(obj) {
430
+ if (obj === null || obj === undefined)
431
+ return undefined;
432
+ if (typeof obj === "string")
433
+ return looksLikeToken(obj) ? obj : undefined;
434
+ if (typeof obj !== "object")
435
+ return undefined;
436
+ const rec = obj;
437
+ const direct = rec.accessToken ?? rec.access_token ?? rec.token;
438
+ if (typeof direct === "string" && looksLikeToken(direct))
439
+ return direct;
440
+ for (const key of Object.keys(rec)) {
441
+ const found = findTokenInObject(rec[key]);
442
+ if (found)
443
+ return found;
444
+ }
445
+ return undefined;
446
+ }
447
+ /** Parse redux-persist style value (may be double stringified). */
448
+ function parsePersistValue(raw) {
449
+ if (!raw)
450
+ return null;
425
451
  try {
452
+ const first = JSON.parse(raw);
453
+ if (typeof first === "string") {
454
+ try {
455
+ return JSON.parse(first);
456
+ }
457
+ catch {
458
+ return first;
459
+ }
460
+ }
461
+ return first;
462
+ }
463
+ catch {
464
+ return null;
465
+ }
466
+ }
467
+ /** Get a nested value that may be a string (need parse) or already an object. */
468
+ function parseNestedValue(val) {
469
+ if (val == null)
470
+ return null;
471
+ if (typeof val === "string")
472
+ return parsePersistValue(val);
473
+ return val;
474
+ }
475
+ const AUTH_DEBUG = true; // set to false to disable access-token debug logs
476
+ /**
477
+ * Extract access token from persist:userdb shape: authDetails (string) → parse → auth.accessToken.
478
+ * Structure: { authDetails: "{\"auth\":{\"accessToken\":\"...\"}}", profileInformation: "...", _persist: "..." }
479
+ */
480
+ function getTokenFromUserDbPersist(parsed) {
481
+ console.log("[header-auth] getTokenFromUserDbPersist: parsed keys", Object.keys(parsed));
482
+ const authDetails = parsed.authDetails;
483
+ const inner = parseNestedValue(authDetails);
484
+ const obj = typeof inner === "object" && inner !== null ? inner : null;
485
+ console.log("[header-auth] getTokenFromUserDbPersist: inner type", typeof inner, "obj keys", obj ? Object.keys(obj) : null);
486
+ if (!obj)
487
+ return undefined;
488
+ const auth = obj.auth;
489
+ const authObj = typeof auth === "object" && auth !== null ? auth : null;
490
+ console.log("[header-auth] getTokenFromUserDbPersist: authObj keys", authObj ? Object.keys(authObj) : null);
491
+ if (!authObj)
492
+ return undefined;
493
+ const token = authObj.accessToken ??
494
+ authObj.access_token ??
495
+ authObj.token;
496
+ const ok = typeof token === "string" && looksLikeToken(token);
497
+ console.log("[header-auth] getTokenFromUserDbPersist: token found", !!ok, "length", typeof token === "string" ? token.length : 0);
498
+ return ok ? token : undefined;
499
+ }
500
+ /**
501
+ * Get access token from all known storage keys (header, IAM, userdb, and plain keys).
502
+ * persist:userdb shape: authDetails (stringified) contains auth.accessToken.
503
+ */
504
+ function getAccessTokenForRequest() {
505
+ console.log("[header-auth] getAccessTokenForRequest: start");
506
+ const keysToTry = [
507
+ PERSIST_HEADER_KEY,
508
+ "persist:linn-i-am",
509
+ "persist:userdb",
510
+ "token",
511
+ "accessToken",
512
+ "auth",
513
+ ];
514
+ for (const key of keysToTry) {
515
+ const raw = localStorage.getItem(key);
516
+ console.log("[header-auth] getAccessTokenForRequest: key", key, "raw present", !!raw, "raw length", raw?.length ?? 0);
517
+ if (!raw)
518
+ continue;
519
+ const parsed = key.startsWith("persist:") ? parsePersistValue(raw) : (() => { try {
520
+ return JSON.parse(raw);
521
+ }
522
+ catch {
523
+ return raw;
524
+ } })();
525
+ const token = findTokenInObject(parsed);
526
+ if (token) {
527
+ console.log("[header-auth] getAccessTokenForRequest: token from findTokenInObject(parsed), key", key);
528
+ return token;
529
+ }
530
+ if (key.startsWith("persist:")) {
531
+ const outer = typeof parsed === "object" && parsed !== null ? parsed : null;
532
+ if (outer) {
533
+ if (key === "persist:userdb") {
534
+ const fromUserDb = getTokenFromUserDbPersist(outer);
535
+ if (fromUserDb) {
536
+ console.log("[header-auth] getAccessTokenForRequest: token from getTokenFromUserDbPersist");
537
+ return fromUserDb;
538
+ }
539
+ }
540
+ for (const k of Object.keys(outer)) {
541
+ const inner = parseNestedValue(outer[k]);
542
+ const t = findTokenInObject(inner);
543
+ if (t) {
544
+ console.log("[header-auth] getAccessTokenForRequest: token from inner key", k);
545
+ return t;
546
+ }
547
+ }
548
+ }
549
+ }
550
+ }
551
+ const allData = getAllDataFromStorage();
552
+ const fallback = getAccessTokenFromAuth(allData.auth);
553
+ console.log("[header-auth] getAccessTokenForRequest: fallback getAllDataFromStorage().auth, token present", !!fallback);
554
+ return fallback;
555
+ }
556
+ const fetchProfilePictureAsBlobUrl = async (baseUrl = "http://objectstore.impact0mics.local:9012", accessTokenOverride) => {
557
+ try {
558
+ if (AUTH_DEBUG)
559
+ console.log("[header-auth] fetchProfilePictureAsBlobUrl: start, accessTokenOverride present", typeof accessTokenOverride === "string" && accessTokenOverride.length > 0);
426
560
  const profilePictureUrl = getProfilePictureUrl(baseUrl);
427
- if (!profilePictureUrl)
561
+ if (!profilePictureUrl) {
562
+ if (AUTH_DEBUG)
563
+ console.log("[header-auth] fetchProfilePictureAsBlobUrl: no profilePictureUrl, abort");
428
564
  return null;
429
- const allData = getAllDataFromStorage();
430
- const accessToken = getAccessTokenFromAuth(allData.auth);
565
+ }
566
+ if (AUTH_DEBUG)
567
+ console.log("[header-auth] fetchProfilePictureAsBlobUrl: profilePictureUrl", profilePictureUrl);
568
+ const accessToken = (typeof accessTokenOverride === "string" && accessTokenOverride.length > 0
569
+ ? accessTokenOverride
570
+ : null) ?? getAccessTokenForRequest();
571
+ if (AUTH_DEBUG)
572
+ console.log("[header-auth] fetchProfilePictureAsBlobUrl: accessToken present", !!accessToken, "length", accessToken?.length ?? 0);
431
573
  const headers = {};
432
574
  if (accessToken) {
433
575
  headers["Authorization"] = `Bearer ${accessToken}`;
434
576
  }
577
+ if (AUTH_DEBUG)
578
+ console.log("[header-auth] fetchProfilePictureAsBlobUrl: request headers", { ...headers, Authorization: headers["Authorization"] ? "Bearer ***" : "(none)" });
435
579
  const response = await fetch(profilePictureUrl, { method: "GET", headers });
436
580
  if (!response.ok) {
437
581
  console.warn(`Failed to fetch profile picture: ${response.status} ${response.statusText}`);
@@ -563,7 +707,7 @@ const DEFAULT_ROUTES = {
563
707
  profile: "/user/profile",
564
708
  logout: "/user/login",
565
709
  };
566
- const AppHeader = ({ language: languageProp }) => {
710
+ const AppHeader = ({ language: languageProp, accessToken: accessTokenProp }) => {
567
711
  // Get initial language from props, URL, localStorage, or default to 'en'
568
712
  const getInitialLanguage = () => {
569
713
  // Priority 1: Props
@@ -660,12 +804,18 @@ const AppHeader = ({ language: languageProp }) => {
660
804
  userRole = userRole || profileData.role || profileData.userRole || "";
661
805
  }
662
806
  }
807
+ const avatarSrc = storedUser?.avatar ??
808
+ allData.auth?.avatar ??
809
+ allData.profile?.avatar;
810
+ const initialsVal = storedUser?.initials ??
811
+ allData.auth?.initials ??
812
+ allData.profile?.initials;
663
813
  return {
664
814
  name: userName || "",
665
815
  email: userEmail || "",
666
816
  role: userRole || "",
667
- avatar: storedUser?.avatar || allData.auth?.avatar || allData.profile?.avatar || undefined,
668
- initials: storedUser?.initials || allData.auth?.initials || allData.profile?.initials || undefined,
817
+ avatar: typeof avatarSrc === "string" ? avatarSrc : undefined,
818
+ initials: typeof initialsVal === "string" ? initialsVal : undefined,
669
819
  };
670
820
  });
671
821
  const [notificationCount, setNotificationCount] = React.useState(() => {
@@ -680,8 +830,10 @@ const AppHeader = ({ language: languageProp }) => {
680
830
  // Fetch profile picture from API when component mounts or user data changes
681
831
  React.useEffect(() => {
682
832
  const fetchProfilePicture = async () => {
683
- // Try to fetch profile picture from API
684
- const blobUrl = await fetchProfilePictureAsBlobUrl();
833
+ console.log("[header-auth] AppHeader: profile picture effect, accessTokenProp present", !!accessTokenProp);
834
+ const token = accessTokenProp ?? getAccessTokenForRequest();
835
+ console.log("[header-auth] AppHeader: token for request present", !!token, "from prop", !!accessTokenProp);
836
+ const blobUrl = await fetchProfilePictureAsBlobUrl(undefined, token ?? undefined);
685
837
  if (blobUrl) {
686
838
  // Clean up previous blob URL if it exists
687
839
  setProfilePictureBlobUrl((prevUrl) => {
@@ -702,7 +854,7 @@ const AppHeader = ({ language: languageProp }) => {
702
854
  return null;
703
855
  });
704
856
  };
705
- }, []); // Only run once on mount - fetch when component loads
857
+ }, [accessTokenProp]); // Refetch when accessToken prop changes (e.g. after login)
706
858
  React.useEffect(() => {
707
859
  const allData = getAllDataFromStorage();
708
860
  let userName = "";
@@ -1039,6 +1191,7 @@ exports.DrawerProvider = DrawerProvider;
1039
1191
  exports.PERSIST_HEADER_KEY = PERSIST_HEADER_KEY;
1040
1192
  exports.USER_DETAILS_STORAGE_KEY = USER_DETAILS_STORAGE_KEY;
1041
1193
  exports.fetchProfilePictureAsBlobUrl = fetchProfilePictureAsBlobUrl;
1194
+ exports.getAccessTokenForRequest = getAccessTokenForRequest;
1042
1195
  exports.getAllDataFromStorage = getAllDataFromStorage;
1043
1196
  exports.getI18nLocaleFromStorage = getI18nLocaleFromStorage;
1044
1197
  exports.getMessageCountFromStorage = getMessageCountFromStorage;