varminer-app-header 2.2.2 → 2.2.3

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.d.ts CHANGED
@@ -119,26 +119,7 @@ declare const getAllDataFromStorage: () => any;
119
119
  * @returns Profile picture URL or null if user_id is not available
120
120
  */
121
121
  declare const getProfilePictureUrl: (baseUrl?: string) => string | null;
122
- /**
123
- * Fetch profile picture from API with headers, get S3 URL, generate presigned URL, and return as blob URL
124
- * This function:
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
135
- */
136
- declare const fetchProfilePictureAsBlobUrl: (baseUrl?: string, messageId?: string, correlationId?: string, awsConfig?: {
137
- accessKeyId: string;
138
- secretAccessKey: string;
139
- region?: string;
140
- bucket?: string;
141
- }) => Promise<string | null>;
122
+ declare const fetchProfilePictureAsBlobUrl: (baseUrl?: string) => Promise<string | null>;
142
123
 
143
124
  export { AppHeader, DrawerProvider, PERSIST_HEADER_KEY, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setHeaderAuth, setI18nLocaleToStorage, translations, useDrawer };
144
125
  export type { AppHeaderProps, HeaderAuthState, SupportedLanguage, Translations, UserDetailsItem, UserDetailsStoredResponse, UserProfile };
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
- // Check if this object itself is auth data
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 (obj.hasOwnProperty(key)) {
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 || parsedData.auth?.accessToken || parsedData.authDetails?.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,43 @@ const getProfilePictureUrl = (baseUrl = "http://objectstore.impact0mics.local:90
346
387
  }
347
388
  };
348
389
  /**
349
- * Generate AWS S3 presigned URL for accessing S3 object
350
- * @param s3Url - Full S3 URL (e.g., https://bucket.s3.region.amazonaws.com/key)
351
- * @param accessKeyId - AWS Access Key ID
352
- * @param secretAccessKey - AWS Secret Access Key
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
356
- */
357
- const generateS3PresignedUrl = async (s3Url, accessKeyId, secretAccessKey, region = "ap-south-2", expiresIn = 3600) => {
358
- try {
359
- // Parse S3 URL to extract bucket, region, and key
360
- // Format: https://bucket.s3.region.amazonaws.com/key or https://bucket.s3-region.amazonaws.com/key
361
- const url = new URL(s3Url);
362
- const hostnameParts = url.hostname.split('.');
363
- let bucket = hostnameParts[0];
364
- let extractedRegion = region;
365
- // Try to extract region from hostname (format: bucket.s3.region.amazonaws.com)
366
- if (hostnameParts.length >= 3 && hostnameParts[1] === 's3') {
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;
372
- }
373
- const key = url.pathname.substring(1); // Remove leading slash
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);
424
- }
425
- else {
426
- keyBuffer = new Uint8Array(key);
427
- }
428
- const messageBuffer = encoder.encode(message);
429
- const cryptoKey = await crypto.subtle.importKey('raw', keyBuffer, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
430
- return await crypto.subtle.sign('HMAC', cryptoKey, messageBuffer);
431
- };
432
- // Helper function to convert ArrayBuffer to hex string
433
- const arrayBufferToHex = (buffer) => {
434
- return Array.from(new Uint8Array(buffer))
435
- .map(b => b.toString(16).padStart(2, '0'))
436
- .join('');
437
- };
438
- /**
439
- * Fetch profile picture from API with headers, get S3 URL, generate presigned URL, and return as blob URL
440
- * This function:
441
- * 1. Fetches the profile picture path from the API
442
- * 2. Extracts the S3 filePath from the JSON response
443
- * 3. Generates a presigned URL for the S3 object
444
- * 4. Fetches the image using the presigned URL
445
- * 5. Converts it to a blob URL that can be used in img src
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.
446
392
  * @param baseUrl - Base URL for the object store API (default: http://objectstore.impact0mics.local:9012)
447
- * @param messageId - Optional message ID for X-Message-Id header (default: generated UUID)
448
- * @param correlationId - Optional correlation ID for X-Correlation-Id header (default: generated UUID)
449
- * @param awsConfig - AWS configuration (accessKeyId, secretAccessKey, region, bucket)
450
393
  * @returns Promise that resolves to blob URL string or null if fetch fails
451
394
  */
452
- const fetchProfilePictureAsBlobUrl = async (baseUrl = "http://objectstore.impact0mics.local:9012", messageId, correlationId, awsConfig) => {
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
+ const fetchProfilePictureAsBlobUrl = async (baseUrl = "http://objectstore.impact0mics.local:9012") => {
453
405
  try {
454
406
  const profilePictureUrl = getProfilePictureUrl(baseUrl);
455
- if (!profilePictureUrl) {
407
+ if (!profilePictureUrl)
456
408
  return null;
457
- }
458
- // AWS credentials (default values provided by user)
459
- const defaultAwsConfig = {
460
- accessKeyId: "AKIAVRUVTJGLBCYZEI5L",
461
- secretAccessKey: "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",
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
409
  const allData = getAllDataFromStorage();
470
- const accessToken = allData.auth?.accessToken;
471
- const headers = {
472
- 'X-Message-Id': msgId,
473
- 'X-Correlation-Id': corrId,
474
- };
410
+ const accessToken = getAccessTokenFromAuth(allData.auth);
411
+ const headers = {};
475
412
  if (accessToken) {
476
- headers['Authorization'] = `Bearer ${accessToken}`;
413
+ headers["Authorization"] = `Bearer ${accessToken}`;
477
414
  }
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;
487
- }
488
- // Parse JSON response
489
- const apiData = await apiResponse.json();
490
- // Extract filePath from response
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}`);
415
+ const response = await fetch(profilePictureUrl, { method: "GET", headers });
416
+ if (!response.ok) {
417
+ console.warn(`Failed to fetch profile picture: ${response.status} ${response.statusText}`);
505
418
  return null;
506
419
  }
507
- // Check if the response is an image
508
- const contentType = imageResponse.headers.get('content-type');
509
- if (!contentType || !contentType.startsWith('image/')) {
420
+ const contentType = response.headers.get("content-type");
421
+ if (!contentType || !contentType.startsWith("image/")) {
510
422
  console.warn(`Profile picture response is not an image: ${contentType}`);
511
423
  return null;
512
424
  }
513
- // Step 4: Convert response to blob
514
- const blob = await imageResponse.blob();
515
- // Step 5: Create blob URL
516
- const blobUrl = URL.createObjectURL(blob);
517
- return blobUrl;
425
+ const blob = await response.blob();
426
+ return URL.createObjectURL(blob);
518
427
  }
519
428
  catch (err) {
520
429
  console.error("Error fetching profile picture:", err);