varminer-app-header 2.2.1 → 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
@@ -79,21 +79,38 @@ interface UserDetailsItem {
79
79
  * Does not write or overwrite this key; IAM app is the source of truth.
80
80
  */
81
81
  declare function getStoredUserDetails(): UserDetailsItem | null;
82
+ /** Unique localStorage key for this header package. Used only for access token; user details come from IAM (linn-i-am-userDetails). */
83
+ declare const PERSIST_HEADER_KEY = "persist:varminer-app-header";
84
+ /** Auth shape stored under PERSIST_HEADER_KEY. Host app should call setHeaderAuth after login so the header can make authenticated calls. */
85
+ interface HeaderAuthState {
86
+ accessToken?: string;
87
+ refreshToken?: string;
88
+ user_id?: number | string;
89
+ [key: string]: unknown;
90
+ }
91
+ /**
92
+ * Store auth (e.g. accessToken) in the header's own persist key. Call this after login so the header can use the token for profile picture etc.
93
+ * User details are not stored here; they come from IAM (linn-i-am-userDetails).
94
+ */
95
+ declare function setHeaderAuth(auth: HeaderAuthState | null): void;
96
+ /**
97
+ * User display data: from IAM only (linn-i-am-userDetails). No dependency on persist:userdb.
98
+ */
82
99
  declare const getUserDataFromStorage: () => {
83
- name: any;
84
- email: any;
85
- role: any;
86
- avatar: any;
87
- initials: any;
100
+ name: string;
101
+ email: string;
102
+ role: string;
103
+ avatar?: string;
104
+ initials?: string;
88
105
  } | null;
89
106
  declare const getNotificationCountFromStorage: () => number;
90
107
  declare const getMessageCountFromStorage: () => number | undefined;
91
108
  declare const getI18nLocaleFromStorage: () => string | null;
92
109
  declare const setI18nLocaleToStorage: (locale: string) => void;
93
110
  /**
94
- * Get all data from localStorage (persist:userdb) including decoded accessToken
95
- * This function reads all available data without hardcoding and doesn't require any parameters
96
- * @returns Comprehensive object containing all available data from localStorage and decoded JWT payload
111
+ * Get auth (and decoded token) for header use. Reads from header's own persist key first; falls back to persist:userdb only for access token.
112
+ * User details are not read from userdb—use getStoredUserDetails / getUserDataFromStorage (IAM) for that.
113
+ * @returns Object with auth, decodedToken, and other keys (user/userDetails/profile null when using header key)
97
114
  */
98
115
  declare const getAllDataFromStorage: () => any;
99
116
  /**
@@ -102,33 +119,7 @@ declare const getAllDataFromStorage: () => any;
102
119
  * @returns Profile picture URL or null if user_id is not available
103
120
  */
104
121
  declare const getProfilePictureUrl: (baseUrl?: string) => string | null;
105
- /**
106
- * Get profile picture upload URL for the object store API.
107
- * URL format: {baseUrl}/v1/objectStore/profilePictureUpload?tenantId=&userId=&roleId=
108
- * @param baseUrl - Base URL for the object store API (default: http://objectstore.impact0mics.local:9012)
109
- * @returns Full upload URL with query params, or null if tenantId, userId, or roleId is missing
110
- */
111
- declare const getProfilePictureUploadUrl: (baseUrl?: string) => string | null;
112
- /**
113
- * Fetch profile picture from API with headers, get S3 URL, generate presigned URL, and return as blob URL
114
- * This function:
115
- * 1. Fetches the profile picture path from the API
116
- * 2. Extracts the S3 filePath from the JSON response
117
- * 3. Generates a presigned URL for the S3 object
118
- * 4. Fetches the image using the presigned URL
119
- * 5. Converts it to a blob URL that can be used in img src
120
- * @param baseUrl - Base URL for the object store API (default: http://objectstore.impact0mics.local:9012)
121
- * @param messageId - Optional message ID for X-Message-Id header (default: generated UUID)
122
- * @param correlationId - Optional correlation ID for X-Correlation-Id header (default: generated UUID)
123
- * @param awsConfig - AWS configuration (accessKeyId, secretAccessKey, region, bucket)
124
- * @returns Promise that resolves to blob URL string or null if fetch fails
125
- */
126
- declare const fetchProfilePictureAsBlobUrl: (baseUrl?: string, messageId?: string, correlationId?: string, awsConfig?: {
127
- accessKeyId: string;
128
- secretAccessKey: string;
129
- region?: string;
130
- bucket?: string;
131
- }) => Promise<string | null>;
122
+ declare const fetchProfilePictureAsBlobUrl: (baseUrl?: string) => Promise<string | null>;
132
123
 
133
- export { AppHeader, DrawerProvider, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUploadUrl, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setI18nLocaleToStorage, translations, useDrawer };
134
- export type { AppHeaderProps, SupportedLanguage, Translations, UserDetailsItem, UserDetailsStoredResponse, UserProfile };
124
+ export { AppHeader, DrawerProvider, PERSIST_HEADER_KEY, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setHeaderAuth, setI18nLocaleToStorage, translations, useDrawer };
125
+ export type { AppHeaderProps, HeaderAuthState, SupportedLanguage, Translations, UserDetailsItem, UserDetailsStoredResponse, UserProfile };
@@ -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,oBAAoB,EACpB,sBAAsB,EACtB,+BAA+B,EAC/B,0BAA0B,EAC1B,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,eAAe,EAAE,yBAAyB,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,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
@@ -57,77 +57,38 @@ function getStoredUserDetails() {
57
57
  return null;
58
58
  }
59
59
  }
60
- const getUserDataFromStorage = () => {
61
- // Prefer IAM user details when available (same origin, after verify-OTP)
62
- const iamUser = getStoredUserDetails();
63
- if (iamUser) {
64
- const name = [iamUser.firstName, iamUser.lastName].filter(Boolean).join(" ").trim();
65
- const role = iamUser.roles?.length ? iamUser.roles[0] : iamUser.workInfo?.jobTitle ?? "";
66
- return {
67
- name: name || "",
68
- email: iamUser.email || "",
69
- role: role || "",
70
- avatar: undefined,
71
- initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
72
- };
60
+ // --- Header-owned persist store (unique key, no conflict with other apps) ---
61
+ /** Unique localStorage key for this header package. Used only for access token; user details come from IAM (linn-i-am-userDetails). */
62
+ const PERSIST_HEADER_KEY = "persist:varminer-app-header";
63
+ /**
64
+ * Store auth (e.g. accessToken) in the header's own persist key. Call this after login so the header can use the token for profile picture etc.
65
+ * User details are not stored here; they come from IAM (linn-i-am-userDetails).
66
+ */
67
+ function setHeaderAuth(auth) {
68
+ try {
69
+ const payload = auth ? { auth } : {};
70
+ localStorage.setItem(PERSIST_HEADER_KEY, JSON.stringify(payload));
73
71
  }
74
- const userDbString = localStorage.getItem("persist:userdb");
75
- if (userDbString) {
76
- try {
77
- const parsedOuter = JSON.parse(userDbString);
78
- const parseNested = (value) => {
79
- if (typeof value === 'string') {
80
- try {
81
- return JSON.parse(value);
82
- }
83
- catch {
84
- return value;
85
- }
86
- }
87
- return value;
88
- };
89
- let userData = null;
90
- if (parsedOuter.userDetails) {
91
- const parsedUserDetails = parseNested(parsedOuter.userDetails);
92
- userData = parsedUserDetails.user || parsedUserDetails.data || parsedUserDetails;
93
- }
94
- if (!userData && parsedOuter.user) {
95
- const parsedUser = parseNested(parsedOuter.user);
96
- userData = parsedUser.user || parsedUser.data || parsedUser.currentUser || parsedUser;
97
- }
98
- if (!userData && parsedOuter.authDetails) {
99
- const parsedAuthDetails = parseNested(parsedOuter.authDetails);
100
- if (parsedAuthDetails.auth) {
101
- userData = parsedAuthDetails.auth.user || parsedAuthDetails.auth.userData;
102
- }
103
- if (!userData) {
104
- userData = parsedAuthDetails.user || parsedAuthDetails.userData || parsedAuthDetails.currentUser;
105
- }
106
- }
107
- if (!userData && parsedOuter.profile) {
108
- const parsedProfile = parseNested(parsedOuter.profile);
109
- userData = parsedProfile.user || parsedProfile.data || parsedProfile;
110
- }
111
- if (userData) {
112
- let name = userData.name || userData.fullName || userData.userName || "";
113
- if (!name && (userData.firstName || userData.lastName)) {
114
- name = [userData.firstName, userData.lastName].filter(Boolean).join(' ');
115
- }
116
- return {
117
- name: name || "",
118
- email: userData.email || userData.emailAddress || "",
119
- role: userData.role || userData.userRole || userData.designation || userData.title || "",
120
- avatar: userData.avatar || userData.profilePicture || userData.imageUrl || userData.profileImage,
121
- initials: userData.initials,
122
- };
123
- }
124
- }
125
- catch (err) {
126
- console.error("Error parsing user data from localStorage:", err);
127
- return null;
128
- }
72
+ catch (err) {
73
+ console.error("Error setting header auth:", err);
129
74
  }
130
- return null;
75
+ }
76
+ /**
77
+ * User display data: from IAM only (linn-i-am-userDetails). No dependency on persist:userdb.
78
+ */
79
+ const getUserDataFromStorage = () => {
80
+ const iamUser = getStoredUserDetails();
81
+ if (!iamUser)
82
+ return null;
83
+ const name = [iamUser.firstName, iamUser.lastName].filter(Boolean).join(" ").trim();
84
+ const role = iamUser.roles?.length ? iamUser.roles[0] : iamUser.workInfo?.jobTitle ?? "";
85
+ return {
86
+ name: name || "",
87
+ email: iamUser.email || "",
88
+ role: role || "",
89
+ avatar: undefined,
90
+ initials: name ? name.split(/\s+/).map((s) => s[0]).join("").slice(0, 2).toUpperCase() : undefined,
91
+ };
131
92
  };
132
93
  const getNotificationCountFromStorage = () => {
133
94
  const userDbString = localStorage.getItem("persist:userdb");
@@ -243,26 +204,91 @@ const decodeJWT = (token) => {
243
204
  return null;
244
205
  }
245
206
  };
207
+ const emptyStorageResult = () => ({
208
+ auth: null,
209
+ user: null,
210
+ authDetails: null,
211
+ userDetails: null,
212
+ profile: null,
213
+ notifications: null,
214
+ messages: null,
215
+ app: null,
216
+ decodedToken: null,
217
+ rawData: null,
218
+ });
246
219
  /**
247
- * Get all data from localStorage (persist:userdb) including decoded accessToken
248
- * This function reads all available data without hardcoding and doesn't require any parameters
249
- * @returns Comprehensive object containing all available data from localStorage and decoded JWT payload
220
+ * Get auth (and decoded token) for header use. Reads from header's own persist key first; falls back to persist:userdb only for access token.
221
+ * User details are not read from userdb—use getStoredUserDetails / getUserDataFromStorage (IAM) for that.
222
+ * @returns Object with auth, decodedToken, and other keys (user/userDetails/profile null when using header key)
250
223
  */
251
224
  const getAllDataFromStorage = () => {
225
+ // Prefer header-owned persist key (unique, no conflict with other apps)
226
+ const headerStr = localStorage.getItem(PERSIST_HEADER_KEY);
227
+ if (headerStr) {
228
+ try {
229
+ const parsed = JSON.parse(headerStr);
230
+ const auth = parsed?.auth;
231
+ const accessToken = auth?.accessToken ?? auth?.access_token ?? auth?.token;
232
+ if (accessToken && typeof accessToken === "string") {
233
+ const decodedToken = decodeJWT(accessToken);
234
+ return {
235
+ ...emptyStorageResult(),
236
+ auth: auth,
237
+ decodedToken: decodedToken ? Object.fromEntries(Object.entries(decodedToken).map(([k, v]) => [k, v ?? null])) : null,
238
+ rawData: parsed,
239
+ };
240
+ }
241
+ }
242
+ catch (err) {
243
+ console.error("Error parsing header persist:", err);
244
+ }
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
+ }
288
+ // Fallback: read access token from persist:userdb (e.g. legacy or shared auth)
252
289
  const userDbString = localStorage.getItem("persist:userdb");
253
290
  if (!userDbString) {
254
- return {
255
- auth: null,
256
- user: null,
257
- authDetails: null,
258
- userDetails: null,
259
- profile: null,
260
- notifications: null,
261
- messages: null,
262
- app: null,
263
- decodedToken: null,
264
- rawData: null,
265
- };
291
+ return emptyStorageResult();
266
292
  }
267
293
  try {
268
294
  const parsedOuter = JSON.parse(userDbString);
@@ -281,17 +307,14 @@ const getAllDataFromStorage = () => {
281
307
  // Parse all top-level keys dynamically (no hardcoding)
282
308
  const parsedData = {};
283
309
  let authData = null;
284
- // Helper to recursively find auth data (contains accessToken or refreshToken)
310
+ // Helper to recursively find auth data (contains accessToken, access_token, token, or refreshToken)
285
311
  const findAuthData = (obj) => {
286
312
  if (!obj || typeof obj !== 'object')
287
313
  return null;
288
- // Check if this object itself is auth data
289
- if (obj.accessToken || obj.refreshToken) {
314
+ if (obj.accessToken || obj.access_token || obj.token || obj.refreshToken)
290
315
  return obj;
291
- }
292
- // Recursively search in nested objects
293
316
  for (const key in obj) {
294
- if (obj.hasOwnProperty(key)) {
317
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
295
318
  const nested = findAuthData(obj[key]);
296
319
  if (nested)
297
320
  return nested;
@@ -309,9 +332,11 @@ const getAllDataFromStorage = () => {
309
332
  parsedData.auth = authData;
310
333
  }
311
334
  });
312
- // Get accessToken and decode it
335
+ // Get accessToken (support accessToken, access_token, token) and decode it
313
336
  let decodedToken = null;
314
- 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;
315
340
  if (accessToken) {
316
341
  decodedToken = decodeJWT(accessToken);
317
342
  }
@@ -340,19 +365,7 @@ const getAllDataFromStorage = () => {
340
365
  }
341
366
  catch (err) {
342
367
  console.error("Error parsing all data from localStorage:", err);
343
- return {
344
- auth: null,
345
- user: null,
346
- authDetails: null,
347
- userDetails: null,
348
- profile: null,
349
- notifications: null,
350
- messages: null,
351
- app: null,
352
- decodedToken: null,
353
- rawData: null,
354
- error: err instanceof Error ? err.message : 'Unknown error',
355
- };
368
+ return { ...emptyStorageResult(), error: err instanceof Error ? err.message : "Unknown error" };
356
369
  }
357
370
  };
358
371
  /**
@@ -374,206 +387,43 @@ const getProfilePictureUrl = (baseUrl = "http://objectstore.impact0mics.local:90
374
387
  }
375
388
  };
376
389
  /**
377
- * Get profile picture upload URL for the object store API.
378
- * URL format: {baseUrl}/v1/objectStore/profilePictureUpload?tenantId=&userId=&roleId=
379
- * @param baseUrl - Base URL for the object store API (default: http://objectstore.impact0mics.local:9012)
380
- * @returns Full upload URL with query params, or null if tenantId, userId, or roleId is missing
381
- */
382
- const getProfilePictureUploadUrl = (baseUrl = "http://objectstore.impact0mics.local:9012") => {
383
- try {
384
- const allData = getAllDataFromStorage();
385
- const iamUser = getStoredUserDetails();
386
- const tenantId = allData.decodedToken?.tenant_id ??
387
- allData.decodedToken?.tenant ??
388
- allData.auth?.tenant_id ??
389
- allData.auth?.tenant ??
390
- null;
391
- const userId = allData.decodedToken?.user_id ??
392
- allData.auth?.user_id ??
393
- iamUser?.userId ??
394
- null;
395
- const roleId = allData.decodedToken?.role_id ??
396
- allData.auth?.role_id ??
397
- null;
398
- if (tenantId == null || userId == null || roleId == null)
399
- return null;
400
- const cleanBaseUrl = baseUrl.replace(/\/$/, "");
401
- const params = new URLSearchParams({
402
- tenantId: String(tenantId),
403
- userId: String(userId),
404
- roleId: String(roleId),
405
- });
406
- return `${cleanBaseUrl}/v1/objectStore/profilePictureUpload?${params.toString()}`;
407
- }
408
- catch (err) {
409
- console.error("Error getting profile picture upload URL:", err);
410
- return null;
411
- }
412
- };
413
- /**
414
- * Generate AWS S3 presigned URL for accessing S3 object
415
- * @param s3Url - Full S3 URL (e.g., https://bucket.s3.region.amazonaws.com/key)
416
- * @param accessKeyId - AWS Access Key ID
417
- * @param secretAccessKey - AWS Secret Access Key
418
- * @param region - AWS Region (default: ap-south-2)
419
- * @param expiresIn - Expiration time in seconds (default: 3600 = 1 hour)
420
- * @returns Presigned URL string
421
- */
422
- const generateS3PresignedUrl = async (s3Url, accessKeyId, secretAccessKey, region = "ap-south-2", expiresIn = 3600) => {
423
- try {
424
- // Parse S3 URL to extract bucket, region, and key
425
- // Format: https://bucket.s3.region.amazonaws.com/key or https://bucket.s3-region.amazonaws.com/key
426
- const url = new URL(s3Url);
427
- const hostnameParts = url.hostname.split('.');
428
- let bucket = hostnameParts[0];
429
- let extractedRegion = region;
430
- // Try to extract region from hostname (format: bucket.s3.region.amazonaws.com)
431
- if (hostnameParts.length >= 3 && hostnameParts[1] === 's3') {
432
- extractedRegion = hostnameParts[2] || region;
433
- }
434
- else if (hostnameParts.length >= 2 && hostnameParts[1].startsWith('s3-')) {
435
- // Format: bucket.s3-region.amazonaws.com
436
- extractedRegion = hostnameParts[1].substring(3) || region;
437
- }
438
- const key = url.pathname.substring(1); // Remove leading slash
439
- // AWS credentials
440
- const awsAccessKeyId = accessKeyId;
441
- const awsSecretAccessKey = secretAccessKey;
442
- const awsRegion = extractedRegion;
443
- // Current timestamp
444
- const now = new Date();
445
- const dateStamp = now.toISOString().slice(0, 10).replace(/-/g, '');
446
- const amzDate = dateStamp + 'T' + now.toISOString().slice(11, 19).replace(/[:-]/g, '') + 'Z';
447
- // Step 1: Create canonical request
448
- const canonicalUri = '/' + encodeURIComponent(key).replace(/%2F/g, '/');
449
- 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`;
450
- const canonicalHeaders = `host:${bucket}.s3.${awsRegion}.amazonaws.com\n`;
451
- const signedHeaders = 'host';
452
- const payloadHash = 'UNSIGNED-PAYLOAD';
453
- const canonicalRequest = `GET\n${canonicalUri}\n${canonicalQuerystring}\n${canonicalHeaders}\n${signedHeaders}\n${payloadHash}`;
454
- // Step 2: Create string to sign
455
- const algorithm = 'AWS4-HMAC-SHA256';
456
- const credentialScope = `${dateStamp}/${awsRegion}/s3/aws4_request`;
457
- const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${await sha256(canonicalRequest)}`;
458
- // Step 3: Calculate signature
459
- const kDate = await hmacSha256('AWS4' + awsSecretAccessKey, dateStamp);
460
- const kRegion = await hmacSha256(kDate, awsRegion);
461
- const kService = await hmacSha256(kRegion, 's3');
462
- const kSigning = await hmacSha256(kService, 'aws4_request');
463
- const signature = await hmacSha256(kSigning, stringToSign);
464
- // Convert signature to hex
465
- const signatureHex = arrayBufferToHex(signature);
466
- // Step 4: Construct presigned URL
467
- const presignedUrl = `https://${bucket}.s3.${awsRegion}.amazonaws.com${canonicalUri}?${canonicalQuerystring}&X-Amz-Signature=${signatureHex}`;
468
- return presignedUrl;
469
- }
470
- catch (err) {
471
- console.error("Error generating S3 presigned URL:", err);
472
- throw err;
473
- }
474
- };
475
- // Helper function for SHA-256 hashing
476
- const sha256 = async (message) => {
477
- const msgBuffer = new TextEncoder().encode(message);
478
- const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
479
- return Array.from(new Uint8Array(hashBuffer))
480
- .map(b => b.toString(16).padStart(2, '0'))
481
- .join('');
482
- };
483
- // Helper function for HMAC-SHA256
484
- const hmacSha256 = async (key, message) => {
485
- const encoder = new TextEncoder();
486
- let keyBuffer;
487
- if (typeof key === 'string') {
488
- keyBuffer = encoder.encode(key);
489
- }
490
- else {
491
- keyBuffer = new Uint8Array(key);
492
- }
493
- const messageBuffer = encoder.encode(message);
494
- const cryptoKey = await crypto.subtle.importKey('raw', keyBuffer, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
495
- return await crypto.subtle.sign('HMAC', cryptoKey, messageBuffer);
496
- };
497
- // Helper function to convert ArrayBuffer to hex string
498
- const arrayBufferToHex = (buffer) => {
499
- return Array.from(new Uint8Array(buffer))
500
- .map(b => b.toString(16).padStart(2, '0'))
501
- .join('');
502
- };
503
- /**
504
- * Fetch profile picture from API with headers, get S3 URL, generate presigned URL, and return as blob URL
505
- * This function:
506
- * 1. Fetches the profile picture path from the API
507
- * 2. Extracts the S3 filePath from the JSON response
508
- * 3. Generates a presigned URL for the S3 object
509
- * 4. Fetches the image using the presigned URL
510
- * 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.
511
392
  * @param baseUrl - Base URL for the object store API (default: http://objectstore.impact0mics.local:9012)
512
- * @param messageId - Optional message ID for X-Message-Id header (default: generated UUID)
513
- * @param correlationId - Optional correlation ID for X-Correlation-Id header (default: generated UUID)
514
- * @param awsConfig - AWS configuration (accessKeyId, secretAccessKey, region, bucket)
515
393
  * @returns Promise that resolves to blob URL string or null if fetch fails
516
394
  */
517
- 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") => {
518
405
  try {
519
406
  const profilePictureUrl = getProfilePictureUrl(baseUrl);
520
- if (!profilePictureUrl) {
521
- return null;
522
- }
523
- // AWS credentials (default values provided by user)
524
- const defaultAwsConfig = {
525
- accessKeyId: "AKIAVRUVTJGLBCYZEI5L",
526
- secretAccessKey: "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",
527
- region: "ap-south-2",
528
- bucket: "development-varminer-test"
529
- };
530
- const finalAwsConfig = awsConfig || defaultAwsConfig;
531
- // Generate message ID and correlation ID if not provided
532
- const msgId = messageId || `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
533
- const corrId = correlationId || `corr-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
534
- // Step 1: Fetch the profile picture path from API (returns JSON with filePath)
535
- const apiResponse = await fetch(profilePictureUrl, {
536
- method: 'GET',
537
- headers: {
538
- 'X-Message-Id': msgId,
539
- 'X-Correlation-Id': corrId,
540
- },
541
- });
542
- // Check if the API response is successful
543
- if (!apiResponse.ok) {
544
- console.warn(`Failed to fetch profile picture path: ${apiResponse.status} ${apiResponse.statusText}`);
545
- return null;
546
- }
547
- // Parse JSON response
548
- const apiData = await apiResponse.json();
549
- // Extract filePath from response
550
- const s3Url = apiData?.filePath;
551
- if (!s3Url || typeof s3Url !== 'string') {
552
- console.warn('Profile picture API response does not contain valid filePath');
407
+ if (!profilePictureUrl)
553
408
  return null;
409
+ const allData = getAllDataFromStorage();
410
+ const accessToken = getAccessTokenFromAuth(allData.auth);
411
+ const headers = {};
412
+ if (accessToken) {
413
+ headers["Authorization"] = `Bearer ${accessToken}`;
554
414
  }
555
- // Step 2: Generate presigned URL for S3 object
556
- const presignedUrl = await generateS3PresignedUrl(s3Url, finalAwsConfig.accessKeyId, finalAwsConfig.secretAccessKey, finalAwsConfig.region);
557
- // Step 3: Fetch the image using presigned URL
558
- const imageResponse = await fetch(presignedUrl, {
559
- method: 'GET',
560
- });
561
- // Check if the image response is successful
562
- if (!imageResponse.ok) {
563
- 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}`);
564
418
  return null;
565
419
  }
566
- // Check if the response is an image
567
- const contentType = imageResponse.headers.get('content-type');
568
- if (!contentType || !contentType.startsWith('image/')) {
420
+ const contentType = response.headers.get("content-type");
421
+ if (!contentType || !contentType.startsWith("image/")) {
569
422
  console.warn(`Profile picture response is not an image: ${contentType}`);
570
423
  return null;
571
424
  }
572
- // Step 4: Convert response to blob
573
- const blob = await imageResponse.blob();
574
- // Step 5: Create blob URL
575
- const blobUrl = URL.createObjectURL(blob);
576
- return blobUrl;
425
+ const blob = await response.blob();
426
+ return URL.createObjectURL(blob);
577
427
  }
578
428
  catch (err) {
579
429
  console.error("Error fetching profile picture:", err);
@@ -1164,5 +1014,5 @@ const AppHeader = ({ language: languageProp }) => {
1164
1014
  }, children: jsx(MoreIcon, {}) }) })] }) }), renderMobileMenu, renderMenu] }));
1165
1015
  };
1166
1016
 
1167
- export { AppHeader, DrawerProvider, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUploadUrl, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setI18nLocaleToStorage, translations, useDrawer };
1017
+ export { AppHeader, DrawerProvider, PERSIST_HEADER_KEY, USER_DETAILS_STORAGE_KEY, fetchProfilePictureAsBlobUrl, getAllDataFromStorage, getI18nLocaleFromStorage, getMessageCountFromStorage, getNotificationCountFromStorage, getProfilePictureUrl, getStoredUserDetails, getTranslations, getUserDataFromStorage, setHeaderAuth, setI18nLocaleToStorage, translations, useDrawer };
1168
1018
  //# sourceMappingURL=index.esm.js.map