varminer-app-header 2.2.2 → 2.2.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/AppHeader.d.ts.map +1 -1
- package/dist/index.d.ts +7 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +200 -169
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +200 -168
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/localStorage.d.ts +4 -18
- package/dist/utils/localStorage.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/AppHeader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AppHeader.d.ts","sourceRoot":"","sources":["../src/AppHeader.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAe,MAAM,SAAS,CAAC;AAKtD,OAAO,sBAAsB,CAAC;AAQ9B,QAAA,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"AppHeader.d.ts","sourceRoot":"","sources":["../src/AppHeader.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,cAAc,EAAe,MAAM,SAAS,CAAC;AAKtD,OAAO,sBAAsB,CAAC;AAQ9B,QAAA,MAAM,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,CAszBvC,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ interface UserProfile {
|
|
|
11
11
|
}
|
|
12
12
|
interface AppHeaderProps {
|
|
13
13
|
language?: 'en' | 'es';
|
|
14
|
+
/** When provided, used as Bearer token for profile picture and other authenticated requests. */
|
|
15
|
+
accessToken?: string | null;
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
declare const AppHeader: React__default.FC<AppHeaderProps>;
|
|
@@ -120,25 +122,11 @@ declare const getAllDataFromStorage: () => any;
|
|
|
120
122
|
*/
|
|
121
123
|
declare const getProfilePictureUrl: (baseUrl?: string) => string | null;
|
|
122
124
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* 1. Fetches the profile picture path from the API
|
|
126
|
-
* 2. Extracts the S3 filePath from the JSON response
|
|
127
|
-
* 3. Generates a presigned URL for the S3 object
|
|
128
|
-
* 4. Fetches the image using the presigned URL
|
|
129
|
-
* 5. Converts it to a blob URL that can be used in img src
|
|
130
|
-
* @param baseUrl - Base URL for the object store API (default: http://objectstore.impact0mics.local:9012)
|
|
131
|
-
* @param messageId - Optional message ID for X-Message-Id header (default: generated UUID)
|
|
132
|
-
* @param correlationId - Optional correlation ID for X-Correlation-Id header (default: generated UUID)
|
|
133
|
-
* @param awsConfig - AWS configuration (accessKeyId, secretAccessKey, region, bucket)
|
|
134
|
-
* @returns Promise that resolves to blob URL string or null if fetch fails
|
|
125
|
+
* Get access token from all known storage keys (header, IAM, userdb, and plain keys).
|
|
126
|
+
* persist:userdb shape: authDetails (stringified) contains auth.accessToken.
|
|
135
127
|
*/
|
|
136
|
-
declare
|
|
137
|
-
|
|
138
|
-
secretAccessKey: string;
|
|
139
|
-
region?: string;
|
|
140
|
-
bucket?: string;
|
|
141
|
-
}) => Promise<string | null>;
|
|
128
|
+
declare function getAccessTokenForRequest(): string | undefined;
|
|
129
|
+
declare const fetchProfilePictureAsBlobUrl: (baseUrl?: string, accessTokenOverride?: string | null) => Promise<string | null>;
|
|
142
130
|
|
|
143
|
-
export { AppHeader, DrawerProvider, PERSIST_HEADER_KEY, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setHeaderAuth, setI18nLocaleToStorage, translations, useDrawer };
|
|
131
|
+
export { AppHeader, DrawerProvider, PERSIST_HEADER_KEY, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAccessTokenForRequest, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setHeaderAuth, setI18nLocaleToStorage, translations, useDrawer };
|
|
144
132
|
export type { AppHeaderProps, HeaderAuthState, SupportedLanguage, Translations, UserDetailsItem, UserDetailsStoredResponse, UserProfile };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,sBAAsB,EACtB,+BAA+B,EAC/B,0BAA0B,EAC1B,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5D,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EACL,wBAAwB,EACxB,kBAAkB,EAClB,oBAAoB,EACpB,aAAa,EACb,sBAAsB,EACtB,+BAA+B,EAC/B,0BAA0B,EAC1B,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,oBAAoB,EACpB,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -228,8 +228,8 @@ const getAllDataFromStorage = () => {
|
|
|
228
228
|
try {
|
|
229
229
|
const parsed = JSON.parse(headerStr);
|
|
230
230
|
const auth = parsed?.auth;
|
|
231
|
-
const accessToken = auth?.accessToken;
|
|
232
|
-
if (accessToken) {
|
|
231
|
+
const accessToken = auth?.accessToken ?? auth?.access_token ?? auth?.token;
|
|
232
|
+
if (accessToken && typeof accessToken === "string") {
|
|
233
233
|
const decodedToken = decodeJWT(accessToken);
|
|
234
234
|
return {
|
|
235
235
|
...emptyStorageResult(),
|
|
@@ -243,6 +243,48 @@ const getAllDataFromStorage = () => {
|
|
|
243
243
|
console.error("Error parsing header persist:", err);
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
|
+
// Fallback: try IAM persist key (persist:linn-i-am) then persist:userdb
|
|
247
|
+
const tryParsePersistForAuth = (raw) => {
|
|
248
|
+
if (!raw)
|
|
249
|
+
return null;
|
|
250
|
+
try {
|
|
251
|
+
const outer = JSON.parse(raw);
|
|
252
|
+
const parseNested = (v) => typeof v === "string" ? (() => { try {
|
|
253
|
+
return JSON.parse(v);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
return v;
|
|
257
|
+
} })() : v;
|
|
258
|
+
for (const key of Object.keys(outer)) {
|
|
259
|
+
const parsed = parseNested(outer[key]);
|
|
260
|
+
if (parsed?.accessToken || parsed?.access_token || parsed?.token || parsed?.refreshToken)
|
|
261
|
+
return parsed;
|
|
262
|
+
if (parsed?.auth && typeof parsed.auth === "object") {
|
|
263
|
+
const a = parsed.auth;
|
|
264
|
+
if (a.accessToken || a.access_token || a.token)
|
|
265
|
+
return a;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
/* ignore */
|
|
271
|
+
}
|
|
272
|
+
return null;
|
|
273
|
+
};
|
|
274
|
+
const iamPersist = localStorage.getItem("persist:linn-i-am");
|
|
275
|
+
const iamAuth = tryParsePersistForAuth(iamPersist);
|
|
276
|
+
if (iamAuth) {
|
|
277
|
+
const token = (iamAuth.accessToken ?? iamAuth.access_token ?? iamAuth.token);
|
|
278
|
+
if (token) {
|
|
279
|
+
const decodedToken = decodeJWT(token);
|
|
280
|
+
return {
|
|
281
|
+
...emptyStorageResult(),
|
|
282
|
+
auth: iamAuth,
|
|
283
|
+
decodedToken: decodedToken ? Object.fromEntries(Object.entries(decodedToken).map(([k, v]) => [k, v ?? null])) : null,
|
|
284
|
+
rawData: iamAuth,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
246
288
|
// Fallback: read access token from persist:userdb (e.g. legacy or shared auth)
|
|
247
289
|
const userDbString = localStorage.getItem("persist:userdb");
|
|
248
290
|
if (!userDbString) {
|
|
@@ -265,17 +307,14 @@ const getAllDataFromStorage = () => {
|
|
|
265
307
|
// Parse all top-level keys dynamically (no hardcoding)
|
|
266
308
|
const parsedData = {};
|
|
267
309
|
let authData = null;
|
|
268
|
-
// Helper to recursively find auth data (contains accessToken or refreshToken)
|
|
310
|
+
// Helper to recursively find auth data (contains accessToken, access_token, token, or refreshToken)
|
|
269
311
|
const findAuthData = (obj) => {
|
|
270
312
|
if (!obj || typeof obj !== 'object')
|
|
271
313
|
return null;
|
|
272
|
-
|
|
273
|
-
if (obj.accessToken || obj.refreshToken) {
|
|
314
|
+
if (obj.accessToken || obj.access_token || obj.token || obj.refreshToken)
|
|
274
315
|
return obj;
|
|
275
|
-
}
|
|
276
|
-
// Recursively search in nested objects
|
|
277
316
|
for (const key in obj) {
|
|
278
|
-
if (
|
|
317
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
279
318
|
const nested = findAuthData(obj[key]);
|
|
280
319
|
if (nested)
|
|
281
320
|
return nested;
|
|
@@ -293,9 +332,11 @@ const getAllDataFromStorage = () => {
|
|
|
293
332
|
parsedData.auth = authData;
|
|
294
333
|
}
|
|
295
334
|
});
|
|
296
|
-
// Get accessToken and decode it
|
|
335
|
+
// Get accessToken (support accessToken, access_token, token) and decode it
|
|
297
336
|
let decodedToken = null;
|
|
298
|
-
const accessToken = authData?.accessToken
|
|
337
|
+
const accessToken = authData?.accessToken ?? authData?.access_token ?? authData?.token ??
|
|
338
|
+
parsedData.auth?.accessToken ?? parsedData.auth?.access_token ?? parsedData.auth?.token ??
|
|
339
|
+
parsedData.authDetails?.accessToken ?? parsedData.authDetails?.access_token ?? parsedData.authDetails?.token;
|
|
299
340
|
if (accessToken) {
|
|
300
341
|
decodedToken = decodeJWT(accessToken);
|
|
301
342
|
}
|
|
@@ -346,175 +387,159 @@ const getProfilePictureUrl = (baseUrl = "http://objectstore.impact0mics.local:90
|
|
|
346
387
|
}
|
|
347
388
|
};
|
|
348
389
|
/**
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
* @param
|
|
352
|
-
* @
|
|
353
|
-
* @param region - AWS Region (default: ap-south-2)
|
|
354
|
-
* @param expiresIn - Expiration time in seconds (default: 3600 = 1 hour)
|
|
355
|
-
* @returns Presigned URL string
|
|
390
|
+
* Fetch profile picture from object store API (plain GET with Authorization header).
|
|
391
|
+
* API returns the image directly; response is converted to a blob URL for use in img src.
|
|
392
|
+
* @param baseUrl - Base URL for the object store API (default: http://objectstore.impact0mics.local:9012)
|
|
393
|
+
* @returns Promise that resolves to blob URL string or null if fetch fails
|
|
356
394
|
*/
|
|
357
|
-
|
|
395
|
+
/** Resolve access token from auth object (supports accessToken, access_token, token). */
|
|
396
|
+
function getAccessTokenFromAuth(auth) {
|
|
397
|
+
if (!auth || typeof auth !== "object")
|
|
398
|
+
return undefined;
|
|
399
|
+
const token = auth.accessToken ??
|
|
400
|
+
auth.access_token ??
|
|
401
|
+
auth.token;
|
|
402
|
+
return typeof token === "string" && token.length > 0 ? token : undefined;
|
|
403
|
+
}
|
|
404
|
+
/** True if string looks like a JWT (three base64 parts) or a bearer token, not JSON. */
|
|
405
|
+
function looksLikeToken(s) {
|
|
406
|
+
return s.length > 0 && !s.trimStart().startsWith("{") && !s.trimStart().startsWith("[");
|
|
407
|
+
}
|
|
408
|
+
/** Recursively find first string value at keys accessToken, access_token, or token. */
|
|
409
|
+
function findTokenInObject(obj) {
|
|
410
|
+
if (obj === null || obj === undefined)
|
|
411
|
+
return undefined;
|
|
412
|
+
if (typeof obj === "string")
|
|
413
|
+
return looksLikeToken(obj) ? obj : undefined;
|
|
414
|
+
if (typeof obj !== "object")
|
|
415
|
+
return undefined;
|
|
416
|
+
const rec = obj;
|
|
417
|
+
const direct = rec.accessToken ?? rec.access_token ?? rec.token;
|
|
418
|
+
if (typeof direct === "string" && looksLikeToken(direct))
|
|
419
|
+
return direct;
|
|
420
|
+
for (const key of Object.keys(rec)) {
|
|
421
|
+
const found = findTokenInObject(rec[key]);
|
|
422
|
+
if (found)
|
|
423
|
+
return found;
|
|
424
|
+
}
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
/** Parse redux-persist style value (may be double stringified). */
|
|
428
|
+
function parsePersistValue(raw) {
|
|
429
|
+
if (!raw)
|
|
430
|
+
return null;
|
|
358
431
|
try {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
extractedRegion = hostnameParts[2] || region;
|
|
368
|
-
}
|
|
369
|
-
else if (hostnameParts.length >= 2 && hostnameParts[1].startsWith('s3-')) {
|
|
370
|
-
// Format: bucket.s3-region.amazonaws.com
|
|
371
|
-
extractedRegion = hostnameParts[1].substring(3) || region;
|
|
432
|
+
const first = JSON.parse(raw);
|
|
433
|
+
if (typeof first === "string") {
|
|
434
|
+
try {
|
|
435
|
+
return JSON.parse(first);
|
|
436
|
+
}
|
|
437
|
+
catch {
|
|
438
|
+
return first;
|
|
439
|
+
}
|
|
372
440
|
}
|
|
373
|
-
|
|
374
|
-
// AWS credentials
|
|
375
|
-
const awsAccessKeyId = accessKeyId;
|
|
376
|
-
const awsSecretAccessKey = secretAccessKey;
|
|
377
|
-
const awsRegion = extractedRegion;
|
|
378
|
-
// Current timestamp
|
|
379
|
-
const now = new Date();
|
|
380
|
-
const dateStamp = now.toISOString().slice(0, 10).replace(/-/g, '');
|
|
381
|
-
const amzDate = dateStamp + 'T' + now.toISOString().slice(11, 19).replace(/[:-]/g, '') + 'Z';
|
|
382
|
-
// Step 1: Create canonical request
|
|
383
|
-
const canonicalUri = '/' + encodeURIComponent(key).replace(/%2F/g, '/');
|
|
384
|
-
const canonicalQuerystring = `X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=${encodeURIComponent(awsAccessKeyId + '/' + dateStamp + '/' + awsRegion + '/s3/aws4_request')}&X-Amz-Date=${amzDate}&X-Amz-Expires=${expiresIn}&X-Amz-SignedHeaders=host`;
|
|
385
|
-
const canonicalHeaders = `host:${bucket}.s3.${awsRegion}.amazonaws.com\n`;
|
|
386
|
-
const signedHeaders = 'host';
|
|
387
|
-
const payloadHash = 'UNSIGNED-PAYLOAD';
|
|
388
|
-
const canonicalRequest = `GET\n${canonicalUri}\n${canonicalQuerystring}\n${canonicalHeaders}\n${signedHeaders}\n${payloadHash}`;
|
|
389
|
-
// Step 2: Create string to sign
|
|
390
|
-
const algorithm = 'AWS4-HMAC-SHA256';
|
|
391
|
-
const credentialScope = `${dateStamp}/${awsRegion}/s3/aws4_request`;
|
|
392
|
-
const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${await sha256(canonicalRequest)}`;
|
|
393
|
-
// Step 3: Calculate signature
|
|
394
|
-
const kDate = await hmacSha256('AWS4' + awsSecretAccessKey, dateStamp);
|
|
395
|
-
const kRegion = await hmacSha256(kDate, awsRegion);
|
|
396
|
-
const kService = await hmacSha256(kRegion, 's3');
|
|
397
|
-
const kSigning = await hmacSha256(kService, 'aws4_request');
|
|
398
|
-
const signature = await hmacSha256(kSigning, stringToSign);
|
|
399
|
-
// Convert signature to hex
|
|
400
|
-
const signatureHex = arrayBufferToHex(signature);
|
|
401
|
-
// Step 4: Construct presigned URL
|
|
402
|
-
const presignedUrl = `https://${bucket}.s3.${awsRegion}.amazonaws.com${canonicalUri}?${canonicalQuerystring}&X-Amz-Signature=${signatureHex}`;
|
|
403
|
-
return presignedUrl;
|
|
404
|
-
}
|
|
405
|
-
catch (err) {
|
|
406
|
-
console.error("Error generating S3 presigned URL:", err);
|
|
407
|
-
throw err;
|
|
408
|
-
}
|
|
409
|
-
};
|
|
410
|
-
// Helper function for SHA-256 hashing
|
|
411
|
-
const sha256 = async (message) => {
|
|
412
|
-
const msgBuffer = new TextEncoder().encode(message);
|
|
413
|
-
const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
|
|
414
|
-
return Array.from(new Uint8Array(hashBuffer))
|
|
415
|
-
.map(b => b.toString(16).padStart(2, '0'))
|
|
416
|
-
.join('');
|
|
417
|
-
};
|
|
418
|
-
// Helper function for HMAC-SHA256
|
|
419
|
-
const hmacSha256 = async (key, message) => {
|
|
420
|
-
const encoder = new TextEncoder();
|
|
421
|
-
let keyBuffer;
|
|
422
|
-
if (typeof key === 'string') {
|
|
423
|
-
keyBuffer = encoder.encode(key);
|
|
441
|
+
return first;
|
|
424
442
|
}
|
|
425
|
-
|
|
426
|
-
|
|
443
|
+
catch {
|
|
444
|
+
return null;
|
|
427
445
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
};
|
|
446
|
+
}
|
|
447
|
+
/** Get a nested value that may be a string (need parse) or already an object. */
|
|
448
|
+
function parseNestedValue(val) {
|
|
449
|
+
if (val == null)
|
|
450
|
+
return null;
|
|
451
|
+
if (typeof val === "string")
|
|
452
|
+
return parsePersistValue(val);
|
|
453
|
+
return val;
|
|
454
|
+
}
|
|
438
455
|
/**
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
456
|
+
* Extract access token from persist:userdb shape: authDetails (string) → parse → auth.accessToken.
|
|
457
|
+
* Structure: { authDetails: "{\"auth\":{\"accessToken\":\"...\"}}", profileInformation: "...", _persist: "..." }
|
|
458
|
+
*/
|
|
459
|
+
function getTokenFromUserDbPersist(parsed) {
|
|
460
|
+
const authDetails = parsed.authDetails;
|
|
461
|
+
const inner = parseNestedValue(authDetails);
|
|
462
|
+
const obj = typeof inner === "object" && inner !== null ? inner : null;
|
|
463
|
+
if (!obj)
|
|
464
|
+
return undefined;
|
|
465
|
+
const auth = obj.auth;
|
|
466
|
+
const authObj = typeof auth === "object" && auth !== null ? auth : null;
|
|
467
|
+
if (!authObj)
|
|
468
|
+
return undefined;
|
|
469
|
+
const token = authObj.accessToken ??
|
|
470
|
+
authObj.access_token ??
|
|
471
|
+
authObj.token;
|
|
472
|
+
return typeof token === "string" && looksLikeToken(token) ? token : undefined;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Get access token from all known storage keys (header, IAM, userdb, and plain keys).
|
|
476
|
+
* persist:userdb shape: authDetails (stringified) contains auth.accessToken.
|
|
451
477
|
*/
|
|
452
|
-
|
|
478
|
+
function getAccessTokenForRequest() {
|
|
479
|
+
const keysToTry = [
|
|
480
|
+
PERSIST_HEADER_KEY,
|
|
481
|
+
"persist:linn-i-am",
|
|
482
|
+
"persist:userdb",
|
|
483
|
+
"token",
|
|
484
|
+
"accessToken",
|
|
485
|
+
"auth",
|
|
486
|
+
];
|
|
487
|
+
for (const key of keysToTry) {
|
|
488
|
+
const raw = localStorage.getItem(key);
|
|
489
|
+
if (!raw)
|
|
490
|
+
continue;
|
|
491
|
+
const parsed = key.startsWith("persist:") ? parsePersistValue(raw) : (() => { try {
|
|
492
|
+
return JSON.parse(raw);
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
return raw;
|
|
496
|
+
} })();
|
|
497
|
+
const token = findTokenInObject(parsed);
|
|
498
|
+
if (token)
|
|
499
|
+
return token;
|
|
500
|
+
if (key.startsWith("persist:")) {
|
|
501
|
+
const outer = typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
502
|
+
if (outer) {
|
|
503
|
+
if (key === "persist:userdb") {
|
|
504
|
+
const fromUserDb = getTokenFromUserDbPersist(outer);
|
|
505
|
+
if (fromUserDb)
|
|
506
|
+
return fromUserDb;
|
|
507
|
+
}
|
|
508
|
+
for (const k of Object.keys(outer)) {
|
|
509
|
+
const inner = parseNestedValue(outer[k]);
|
|
510
|
+
const t = findTokenInObject(inner);
|
|
511
|
+
if (t)
|
|
512
|
+
return t;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return getAccessTokenFromAuth(getAllDataFromStorage().auth);
|
|
518
|
+
}
|
|
519
|
+
const fetchProfilePictureAsBlobUrl = async (baseUrl = "http://objectstore.impact0mics.local:9012", accessTokenOverride) => {
|
|
453
520
|
try {
|
|
454
521
|
const profilePictureUrl = getProfilePictureUrl(baseUrl);
|
|
455
|
-
if (!profilePictureUrl)
|
|
522
|
+
if (!profilePictureUrl)
|
|
456
523
|
return null;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
secretAccessKey: "kbMVqmx6s29njcS5P48qAqpXlb1oir6+b7zu1Qxi",
|
|
462
|
-
region: "ap-south-2",
|
|
463
|
-
bucket: "development-varminer-test"
|
|
464
|
-
};
|
|
465
|
-
const finalAwsConfig = awsConfig || defaultAwsConfig;
|
|
466
|
-
// Generate message ID and correlation ID if not provided
|
|
467
|
-
const msgId = messageId || `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
468
|
-
const corrId = correlationId || `corr-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
469
|
-
const allData = getAllDataFromStorage();
|
|
470
|
-
const accessToken = allData.auth?.accessToken;
|
|
471
|
-
const headers = {
|
|
472
|
-
'X-Message-Id': msgId,
|
|
473
|
-
'X-Correlation-Id': corrId,
|
|
474
|
-
};
|
|
524
|
+
const accessToken = (typeof accessTokenOverride === "string" && accessTokenOverride.length > 0
|
|
525
|
+
? accessTokenOverride
|
|
526
|
+
: null) ?? getAccessTokenForRequest();
|
|
527
|
+
const headers = {};
|
|
475
528
|
if (accessToken) {
|
|
476
|
-
headers[
|
|
477
|
-
}
|
|
478
|
-
// Step 1: Fetch the profile picture path from API (returns JSON with filePath)
|
|
479
|
-
const apiResponse = await fetch(profilePictureUrl, {
|
|
480
|
-
method: 'GET',
|
|
481
|
-
headers,
|
|
482
|
-
});
|
|
483
|
-
// Check if the API response is successful
|
|
484
|
-
if (!apiResponse.ok) {
|
|
485
|
-
console.warn(`Failed to fetch profile picture path: ${apiResponse.status} ${apiResponse.statusText}`);
|
|
486
|
-
return null;
|
|
529
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
487
530
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const s3Url = apiData?.filePath;
|
|
492
|
-
if (!s3Url || typeof s3Url !== 'string') {
|
|
493
|
-
console.warn('Profile picture API response does not contain valid filePath');
|
|
494
|
-
return null;
|
|
495
|
-
}
|
|
496
|
-
// Step 2: Generate presigned URL for S3 object
|
|
497
|
-
const presignedUrl = await generateS3PresignedUrl(s3Url, finalAwsConfig.accessKeyId, finalAwsConfig.secretAccessKey, finalAwsConfig.region);
|
|
498
|
-
// Step 3: Fetch the image using presigned URL
|
|
499
|
-
const imageResponse = await fetch(presignedUrl, {
|
|
500
|
-
method: 'GET',
|
|
501
|
-
});
|
|
502
|
-
// Check if the image response is successful
|
|
503
|
-
if (!imageResponse.ok) {
|
|
504
|
-
console.warn(`Failed to fetch profile picture image: ${imageResponse.status} ${imageResponse.statusText}`);
|
|
531
|
+
const response = await fetch(profilePictureUrl, { method: "GET", headers });
|
|
532
|
+
if (!response.ok) {
|
|
533
|
+
console.warn(`Failed to fetch profile picture: ${response.status} ${response.statusText}`);
|
|
505
534
|
return null;
|
|
506
535
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
if (!contentType || !contentType.startsWith('image/')) {
|
|
536
|
+
const contentType = response.headers.get("content-type");
|
|
537
|
+
if (!contentType || !contentType.startsWith("image/")) {
|
|
510
538
|
console.warn(`Profile picture response is not an image: ${contentType}`);
|
|
511
539
|
return null;
|
|
512
540
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
// Step 5: Create blob URL
|
|
516
|
-
const blobUrl = URL.createObjectURL(blob);
|
|
517
|
-
return blobUrl;
|
|
541
|
+
const blob = await response.blob();
|
|
542
|
+
return URL.createObjectURL(blob);
|
|
518
543
|
}
|
|
519
544
|
catch (err) {
|
|
520
545
|
console.error("Error fetching profile picture:", err);
|
|
@@ -634,7 +659,7 @@ const DEFAULT_ROUTES = {
|
|
|
634
659
|
profile: "/user/profile",
|
|
635
660
|
logout: "/user/login",
|
|
636
661
|
};
|
|
637
|
-
const AppHeader = ({ language: languageProp }) => {
|
|
662
|
+
const AppHeader = ({ language: languageProp, accessToken: accessTokenProp }) => {
|
|
638
663
|
// Get initial language from props, URL, localStorage, or default to 'en'
|
|
639
664
|
const getInitialLanguage = () => {
|
|
640
665
|
// Priority 1: Props
|
|
@@ -731,12 +756,18 @@ const AppHeader = ({ language: languageProp }) => {
|
|
|
731
756
|
userRole = userRole || profileData.role || profileData.userRole || "";
|
|
732
757
|
}
|
|
733
758
|
}
|
|
759
|
+
const avatarSrc = storedUser?.avatar ??
|
|
760
|
+
allData.auth?.avatar ??
|
|
761
|
+
allData.profile?.avatar;
|
|
762
|
+
const initialsVal = storedUser?.initials ??
|
|
763
|
+
allData.auth?.initials ??
|
|
764
|
+
allData.profile?.initials;
|
|
734
765
|
return {
|
|
735
766
|
name: userName || "",
|
|
736
767
|
email: userEmail || "",
|
|
737
768
|
role: userRole || "",
|
|
738
|
-
avatar:
|
|
739
|
-
initials:
|
|
769
|
+
avatar: typeof avatarSrc === "string" ? avatarSrc : undefined,
|
|
770
|
+
initials: typeof initialsVal === "string" ? initialsVal : undefined,
|
|
740
771
|
};
|
|
741
772
|
});
|
|
742
773
|
const [notificationCount, setNotificationCount] = React__default.useState(() => {
|
|
@@ -751,8 +782,8 @@ const AppHeader = ({ language: languageProp }) => {
|
|
|
751
782
|
// Fetch profile picture from API when component mounts or user data changes
|
|
752
783
|
React__default.useEffect(() => {
|
|
753
784
|
const fetchProfilePicture = async () => {
|
|
754
|
-
|
|
755
|
-
const blobUrl = await fetchProfilePictureAsBlobUrl();
|
|
785
|
+
const token = accessTokenProp ?? getAccessTokenForRequest();
|
|
786
|
+
const blobUrl = await fetchProfilePictureAsBlobUrl(undefined, token ?? undefined);
|
|
756
787
|
if (blobUrl) {
|
|
757
788
|
// Clean up previous blob URL if it exists
|
|
758
789
|
setProfilePictureBlobUrl((prevUrl) => {
|
|
@@ -773,7 +804,7 @@ const AppHeader = ({ language: languageProp }) => {
|
|
|
773
804
|
return null;
|
|
774
805
|
});
|
|
775
806
|
};
|
|
776
|
-
}, []); //
|
|
807
|
+
}, [accessTokenProp]); // Refetch when accessToken prop changes (e.g. after login)
|
|
777
808
|
React__default.useEffect(() => {
|
|
778
809
|
const allData = getAllDataFromStorage();
|
|
779
810
|
let userName = "";
|
|
@@ -1105,5 +1136,5 @@ const AppHeader = ({ language: languageProp }) => {
|
|
|
1105
1136
|
}, children: jsx(MoreIcon, {}) }) })] }) }), renderMobileMenu, renderMenu] }));
|
|
1106
1137
|
};
|
|
1107
1138
|
|
|
1108
|
-
export { AppHeader, DrawerProvider, PERSIST_HEADER_KEY, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setHeaderAuth, setI18nLocaleToStorage, translations, useDrawer };
|
|
1139
|
+
export { AppHeader, DrawerProvider, PERSIST_HEADER_KEY, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAccessTokenForRequest, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setHeaderAuth, setI18nLocaleToStorage, translations, useDrawer };
|
|
1109
1140
|
//# sourceMappingURL=index.esm.js.map
|