@imtbl/auth 2.10.7-alpha.6 → 2.11.1-alpha.0

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/src/Auth.ts CHANGED
@@ -42,8 +42,6 @@ import { isAccessTokenExpiredOrExpiring } from './utils/token';
42
42
  import LoginPopupOverlay from './overlay/loginPopupOverlay';
43
43
  import { LocalForageAsyncStorage } from './storage/LocalForageAsyncStorage';
44
44
 
45
- const LOGIN_POPUP_CLOSED_POLLING_DURATION = 500;
46
-
47
45
  const formUrlEncodedHeader = {
48
46
  headers: {
49
47
  'Content-Type': 'application/x-www-form-urlencoded',
@@ -206,8 +204,7 @@ export class Auth {
206
204
 
207
205
  // Emit LOGGED_IN event and identify user if logged in
208
206
  if (user) {
209
- this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
210
- identify({ passportId: user.profile.sub });
207
+ this.handleSuccessfulLogin(user);
211
208
  }
212
209
 
213
210
  return user;
@@ -233,8 +230,7 @@ export class Auth {
233
230
  return withMetricsAsync(async () => {
234
231
  const user = await this.loginCallbackInternal();
235
232
  if (user) {
236
- this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
237
- identify({ passportId: user.profile.sub });
233
+ this.handleSuccessfulLogin(user);
238
234
  }
239
235
  return user;
240
236
  }, 'loginCallback');
@@ -256,7 +252,7 @@ export class Auth {
256
252
  * @returns Promise that resolves with the user or null if not authenticated
257
253
  */
258
254
  async getUser(): Promise<User | null> {
259
- return withMetricsAsync(async () => this.getUserInternal(), 'getUserInfo', false);
255
+ return this.getUserInternal();
260
256
  }
261
257
 
262
258
  /**
@@ -275,7 +271,9 @@ export class Auth {
275
271
  return user;
276
272
  }
277
273
 
278
- return this.loginWithPopup();
274
+ const loggedInUser = await this.loginWithPopup();
275
+ this.handleSuccessfulLogin(loggedInUser);
276
+ return loggedInUser;
279
277
  }
280
278
 
281
279
  /**
@@ -354,8 +352,7 @@ export class Auth {
354
352
  async loginWithPKCEFlowCallback(authorizationCode: string, state: string): Promise<User> {
355
353
  return withMetricsAsync(async () => {
356
354
  const user = await this.loginWithPKCEFlowCallbackInternal(authorizationCode, state);
357
- this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
358
- identify({ passportId: user.profile.sub });
355
+ this.handleSuccessfulLogin(user);
359
356
  return user;
360
357
  }, 'loginWithPKCEFlowCallback');
361
358
  }
@@ -368,8 +365,7 @@ export class Auth {
368
365
  async storeTokens(tokenResponse: DeviceTokenResponse): Promise<User> {
369
366
  return withMetricsAsync(async () => {
370
367
  const user = await this.storeTokensInternal(tokenResponse);
371
- this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
372
- identify({ passportId: user.profile.sub });
368
+ this.handleSuccessfulLogin(user);
373
369
  return user;
374
370
  }, 'storeTokens');
375
371
  }
@@ -413,6 +409,11 @@ export class Auth {
413
409
  return this.config.oidcConfiguration.clientId;
414
410
  }
415
411
 
412
+ private handleSuccessfulLogin(user: User): void {
413
+ this.eventEmitter.emit(AuthEvents.LOGGED_IN, user);
414
+ identify({ passportId: user.profile.sub });
415
+ }
416
+
416
417
  private buildExtraQueryParams(
417
418
  directLoginOptions?: DirectLoginOptions,
418
419
  imPassportTraceId?: string,
@@ -420,7 +421,6 @@ export class Auth {
420
421
  const params: Record<string, string> = {
421
422
  ...(this.userManager.settings?.extraQueryParams ?? {}),
422
423
  rid: getDetail(Detail.RUNTIME_ID) || '',
423
- third_party_a_id: '',
424
424
  };
425
425
 
426
426
  if (directLoginOptions) {
@@ -472,7 +472,7 @@ export class Auth {
472
472
  const signinPopup = async () => {
473
473
  const extraQueryParams = this.buildExtraQueryParams(directLoginOptionsToUse, imPassportTraceId);
474
474
 
475
- const userPromise = this.userManager.signinPopup({
475
+ return this.userManager.signinPopup({
476
476
  extraQueryParams,
477
477
  popupWindowFeatures: {
478
478
  width: 410,
@@ -480,27 +480,6 @@ export class Auth {
480
480
  },
481
481
  popupWindowTarget,
482
482
  });
483
-
484
- const popupRef = window.open('', popupWindowTarget);
485
- if (popupRef) {
486
- const popupClosedPromise = new Promise<never>((_, reject) => {
487
- const timer = setInterval(() => {
488
- if (popupRef.closed) {
489
- clearInterval(timer);
490
- reject(new Error('Popup closed by user'));
491
- }
492
- }, LOGIN_POPUP_CLOSED_POLLING_DURATION);
493
-
494
- userPromise.finally(() => {
495
- clearInterval(timer);
496
- popupRef.close();
497
- });
498
- });
499
-
500
- return Promise.race([userPromise, popupClosedPromise]);
501
- }
502
-
503
- return userPromise;
504
483
  };
505
484
 
506
485
  return new Promise((resolve, reject) => {
@@ -542,8 +521,13 @@ export class Auth {
542
521
 
543
522
  private static mapOidcUserToDomainModel = (oidcUser: OidcUser): User => {
544
523
  let passport: PassportMetadata | undefined;
524
+ let username: string | undefined;
545
525
  if (oidcUser.id_token) {
546
- passport = jwt_decode<IdTokenPayload>(oidcUser.id_token)?.passport;
526
+ const idTokenPayload = jwt_decode<IdTokenPayload>(oidcUser.id_token);
527
+ passport = idTokenPayload?.passport;
528
+ if (idTokenPayload?.username) {
529
+ username = idTokenPayload?.username;
530
+ }
547
531
  }
548
532
 
549
533
  const user: User = {
@@ -555,6 +539,7 @@ export class Auth {
555
539
  sub: oidcUser.profile.sub,
556
540
  email: oidcUser.profile.email,
557
541
  nickname: oidcUser.profile.nickname,
542
+ username,
558
543
  },
559
544
  };
560
545
  if (passport?.zkevm_eth_address && passport?.zkevm_user_admin_address) {
@@ -582,29 +567,13 @@ export class Auth {
582
567
  email: idTokenPayload.email,
583
568
  nickname: idTokenPayload.nickname,
584
569
  passport: idTokenPayload.passport,
570
+ ...(idTokenPayload.username ? { username: idTokenPayload.username } : {}),
585
571
  },
586
572
  });
587
573
  };
588
574
 
589
- private static shouldUseSigninPopupCallback(): boolean {
590
- try {
591
- const urlParams = new URLSearchParams(window.location.search);
592
- const stateParam = urlParams.get('state');
593
- const localStorageKey = `oidc.${stateParam}`;
594
- const localStorageValue = localStorage.getItem(localStorageKey);
595
- const loginState = JSON.parse(localStorageValue || '{}');
596
- return loginState?.request_type === 'si:p';
597
- } catch (err) {
598
- return false;
599
- }
600
- }
601
-
602
575
  private async loginCallbackInternal(): Promise<User | undefined> {
603
576
  return withPassportError(async () => {
604
- if (Auth.shouldUseSigninPopupCallback()) {
605
- await this.userManager.signinPopupCallback(undefined, true);
606
- return undefined;
607
- }
608
577
  const oidcUser = await this.userManager.signinCallback();
609
578
  if (!oidcUser) {
610
579
  return undefined;
@@ -0,0 +1,21 @@
1
+ import { isAPIError } from './errors';
2
+
3
+ describe('isAPIError', () => {
4
+ it('returns true when code and message fields exist', () => {
5
+ expect(isAPIError({ code: 'BAD_REQUEST', message: 'Invalid' })).toBe(true);
6
+ });
7
+
8
+ it.each([
9
+ 'Not found',
10
+ 404,
11
+ null,
12
+ undefined,
13
+ ])('returns false for non-object value: %p', (value) => {
14
+ expect(isAPIError(value)).toBe(false);
15
+ });
16
+
17
+ it('returns false when required fields are missing', () => {
18
+ expect(isAPIError({ code: 'BAD_REQUEST' })).toBe(false);
19
+ expect(isAPIError({ message: 'Invalid' })).toBe(false);
20
+ });
21
+ });
package/src/errors.ts CHANGED
@@ -23,10 +23,16 @@ export enum PassportErrorType {
23
23
  LINK_WALLET_DUPLICATE_NONCE_ERROR = 'LINK_WALLET_DUPLICATE_NONCE_ERROR',
24
24
  LINK_WALLET_GENERIC_ERROR = 'LINK_WALLET_GENERIC_ERROR',
25
25
  SERVICE_UNAVAILABLE_ERROR = 'SERVICE_UNAVAILABLE_ERROR',
26
+ TRANSACTION_REJECTED = 'TRANSACTION_REJECTED',
26
27
  }
27
28
 
28
29
  export function isAPIError(error: any): error is imx.APIError {
29
- return 'code' in error && 'message' in error;
30
+ return (
31
+ typeof error === 'object'
32
+ && error !== null
33
+ && 'code' in error
34
+ && 'message' in error
35
+ );
30
36
  }
31
37
 
32
38
  export class PassportError extends Error {
package/src/index.ts CHANGED
@@ -29,4 +29,6 @@ export {
29
29
  export { default as TypedEventEmitter } from './utils/typedEventEmitter';
30
30
 
31
31
  // Export errors
32
- export { PassportError, PassportErrorType, withPassportError } from './errors';
32
+ export {
33
+ PassportError, PassportErrorType, withPassportError, isAPIError,
34
+ } from './errors';
package/src/types.ts CHANGED
@@ -9,6 +9,7 @@ export type UserProfile = {
9
9
  email?: string;
10
10
  nickname?: string;
11
11
  sub: string;
12
+ username?: string;
12
13
  };
13
14
 
14
15
  export enum RollupType {
@@ -91,6 +92,7 @@ export type TokenPayload = {
91
92
 
92
93
  export type IdTokenPayload = {
93
94
  passport?: PassportMetadata;
95
+ username?: string;
94
96
  email: string;
95
97
  nickname: string;
96
98
  aud: string;
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": [],
4
+ "include": ["src"]
5
+ }
6
+
package/tsconfig.json CHANGED
@@ -10,6 +10,10 @@
10
10
  "exclude": [
11
11
  "node_modules",
12
12
  "dist",
13
+ "src/**/*.test.ts",
14
+ "src/**/*.test.tsx",
15
+ "src/**/*.spec.ts",
16
+ "src/**/*.spec.tsx"
13
17
  ]
14
18
  }
15
19