@sambath999/localize-token 12.3.1 → 12.3.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.
@@ -1,17 +1,17 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, NgModule, Component, ViewEncapsulation, ChangeDetectorRef, Injector, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
3
3
  import { __awaiter } from 'tslib';
4
- import { BehaviorSubject } from 'rxjs';
4
+ import { BehaviorSubject, takeUntil, catchError, throwError, Subject } from 'rxjs';
5
5
  import * as jwt_decode from 'jwt-decode';
6
6
  import * as i1 from '@angular/common/http';
7
- import { HttpHeaders, HttpClient } from '@angular/common/http';
7
+ import { HttpErrorResponse, HttpHeaders, HttpClient } from '@angular/common/http';
8
8
  import { MessageService } from 'primeng/api';
9
9
  import { DynamicDialogRef, DynamicDialogConfig, DialogService } from 'primeng/dynamicdialog';
10
+ import { DomSanitizer, BrowserModule } from '@angular/platform-browser';
10
11
  import { CommonModule } from '@angular/common';
11
12
  import { ToastModule } from 'primeng/toast';
12
13
  import { InputTextModule } from 'primeng/inputtext';
13
14
  import { ButtonModule } from 'primeng/button';
14
- import { BrowserModule } from '@angular/platform-browser';
15
15
  import { FormsModule } from '@angular/forms';
16
16
 
17
17
  /**
@@ -208,6 +208,8 @@ class LocalizeTokenService {
208
208
  }
209
209
  }
210
210
  tenantToken(name) {
211
+ if (!name)
212
+ return undefined;
211
213
  return LocalizeToken.storage.get(name);
212
214
  }
213
215
  storageGet() {
@@ -224,6 +226,11 @@ class LocalizeTokenService {
224
226
  const base64 = btoa(JSON.stringify(value));
225
227
  LocalizeToken.storage.set(this.config.authTokenName, base64);
226
228
  }
229
+ tokensValid(tenantTokenName) {
230
+ var _a, _b;
231
+ return !!((_a = this.refreshToken) === null || _a === void 0 ? void 0 : _a.length)
232
+ && (!this.config.needTenant || !!((_b = this.tenantToken(tenantTokenName)) === null || _b === void 0 ? void 0 : _b.length));
233
+ }
227
234
  get decodeRefreshToken() {
228
235
  const token = LocalizeToken.storage.get(this.config.refreshTokenName);
229
236
  if (!token)
@@ -242,136 +249,452 @@ LocalizeTokenService.ctorParameters = () => [];
242
249
  */
243
250
  var EMethod;
244
251
  (function (EMethod) {
245
- EMethod[EMethod["POST"] = 1] = "POST";
246
- EMethod[EMethod["GET"] = 2] = "GET";
247
- EMethod[EMethod["PUT"] = 3] = "PUT";
248
- EMethod[EMethod["DELETE"] = 4] = "DELETE";
249
- EMethod[EMethod["PATCH"] = 5] = "PATCH";
250
- })(EMethod || (EMethod = {}));
252
+ EMethod["POST"] = "post";
253
+ EMethod["GET"] = "get";
254
+ EMethod["PUT"] = "put";
255
+ EMethod["DELETE"] = "delete";
256
+ EMethod["PATCH"] = "patch";
257
+ })(EMethod || (EMethod = {}));
258
+
259
+ class LocalizeApiHelper {
260
+ constructor() {
261
+ this.defaultRetryOptions = {
262
+ connectionError: {
263
+ message: 'Connection error occurred. Please wait',
264
+ blockScreen: true,
265
+ blockScreenZIndex: 10000
266
+ }
267
+ };
268
+ }
269
+ performRetry(options) {
270
+ return __awaiter(this, void 0, void 0, function* () {
271
+ let attempts = 0;
272
+ let lastError;
273
+ let consoleCount = 0;
274
+ // Merge default retry options with provided options
275
+ options = Object.assign(Object.assign({}, this.defaultRetryOptions), options);
276
+ let styleElement;
277
+ while (attempts < options.maxRetries()) {
278
+ try {
279
+ const result = yield options.callback();
280
+ this.removeBlocker(styleElement);
281
+ return result;
282
+ }
283
+ catch (error) {
284
+ lastError = error;
285
+ if (consoleCount >= 7) {
286
+ console.clear();
287
+ consoleCount = 0;
288
+ }
289
+ if (options.retryUnless && !options.retryUnless(error))
290
+ throw error; // If the error should not be retried, rethrow it
291
+ // Handle connection error
292
+ styleElement = yield this.onConnectionError(options, error);
293
+ if (options.onError)
294
+ yield this.invokeHook(options.onError.bind(this, error));
295
+ if (attempts >= options.maxRetries() - 1)
296
+ throw error;
297
+ attempts++;
298
+ consoleCount++;
299
+ console.warn(`Attempt ${attempts} failed. Retrying...`, error);
300
+ yield waitFor(options.delay);
301
+ }
302
+ }
303
+ console.warn(`Failed after ${options.maxRetries} attempts`);
304
+ throw lastError;
305
+ });
306
+ }
307
+ performRequestWithRetry(options, config, performRequest) {
308
+ var _a, _b, _c, _d;
309
+ return __awaiter(this, void 0, void 0, function* () {
310
+ const retryUnless = ((_a = config.retryOptions) === null || _a === void 0 ? void 0 : _a.retryFunction)
311
+ || this.isConnectionError;
312
+ return yield this.performRetry({
313
+ connectionError: (_b = config.retryOptions) === null || _b === void 0 ? void 0 : _b.onConnectionError,
314
+ maxRetries: () => { var _a, _b; return (_b = (_a = config.retryOptions) === null || _a === void 0 ? void 0 : _a.maxRetries) !== null && _b !== void 0 ? _b : 1000; },
315
+ delay: (_d = (_c = config.retryOptions) === null || _c === void 0 ? void 0 : _c.delay) !== null && _d !== void 0 ? _d : 500,
316
+ callback: () => performRequest(options),
317
+ retryUnless: retryUnless,
318
+ });
319
+ });
320
+ }
321
+ buildUrl(baseUrl, path) {
322
+ const normalizedUrl = `${baseUrl.trim().replace(/\/?$/, '/')}${path.trim().replace(/^\//, '')}`;
323
+ return normalizedUrl.endsWith('/')
324
+ ? normalizedUrl.slice(0, -1)
325
+ : normalizedUrl;
326
+ }
327
+ normalizeError(error) {
328
+ var _a, _b, _c;
329
+ return {
330
+ code: ((_a = error.error) === null || _a === void 0 ? void 0 : _a.code) || `HTTP_${error.status}`,
331
+ message: ((_b = error.error) === null || _b === void 0 ? void 0 : _b.message) || error.message,
332
+ details: (_c = error.error) === null || _c === void 0 ? void 0 : _c.details,
333
+ status: error.status
334
+ };
335
+ }
336
+ invokeHook(callback) {
337
+ return __awaiter(this, void 0, void 0, function* () {
338
+ if (!callback)
339
+ return;
340
+ const result = callback();
341
+ if (result instanceof Promise) {
342
+ yield result;
343
+ }
344
+ });
345
+ }
346
+ createRequest(instance, method, url, body, options) {
347
+ const request$ = instance.client.request(method, url, Object.assign(Object.assign({}, options), { body, observe: 'response' })).pipe(takeUntil(instance.destroy$()), catchError((error) => {
348
+ // Convert to a non-observable error to handle in the promise
349
+ return throwError(() => this.normalizeError(error));
350
+ }));
351
+ return request$;
352
+ }
353
+ defaultRetryFunction(error) {
354
+ // Don't retry for other errors (like 400, 401, 403, etc.)
355
+ if (!this.isConnectionError(error))
356
+ throw error;
357
+ return true;
358
+ }
359
+ isConnectionError(error) {
360
+ const isNetworkError = error.status === 0;
361
+ const isServerError = error.status >= 1000 && error.status < 600;
362
+ return isNetworkError || isServerError;
363
+ }
364
+ onConnectionError(options, error) {
365
+ var _a;
366
+ return __awaiter(this, void 0, void 0, function* () {
367
+ if (!options.connectionError)
368
+ return;
369
+ let styleElement;
370
+ if (this.isConnectionError(error)) {
371
+ styleElement = this.screenBlocker(options, error, true);
372
+ yield this.invokeHook((_a = options.connectionError.callback) === null || _a === void 0 ? void 0 : _a.bind(this, error));
373
+ return styleElement;
374
+ }
375
+ else {
376
+ this.screenBlocker(options, error, false);
377
+ styleElement === null || styleElement === void 0 ? void 0 : styleElement.remove();
378
+ }
379
+ });
380
+ }
381
+ validateConfig(config) {
382
+ var _a;
383
+ if (LocalizeToken.config.needTenant && !((_a = config.tenantTokenName) === null || _a === void 0 ? void 0 : _a.trim().length)) {
384
+ throw Error('Tenant token is required but tenantTokenName is not configured');
385
+ }
386
+ if (!LocalizeToken.config.revokeTokenUrl.trim().length) {
387
+ throw Error('Revoke token URL is not configured - token refresh will not work');
388
+ }
389
+ }
390
+ screenBlocker(optons, error, add = true) {
391
+ var _a, _b, _c, _d;
392
+ if (!((_a = optons.connectionError) === null || _a === void 0 ? void 0 : _a.blockScreen))
393
+ return;
394
+ if (error instanceof HttpErrorResponse)
395
+ error = this.normalizeError(error);
396
+ const message = ((_b = optons.connectionError) === null || _b === void 0 ? void 0 : _b.message)
397
+ || 'Connection error occurred. Please wait';
398
+ const errorMessage = (error === null || error === void 0 ? void 0 : error.message) || 'An error occurred';
399
+ const suggestinMessage = ((_c = optons.connectionError) === null || _c === void 0 ? void 0 : _c.suggestionMessage)
400
+ || 'Please check your internet connection or the server status.';
401
+ const zIndex = ((_d = optons.connectionError) === null || _d === void 0 ? void 0 : _d.blockScreenZIndex) || 10000;
402
+ const body = document.body;
403
+ const blcokerHtml = `
404
+ <div class="lze-blocker">
405
+ <div class="lze-blocker__message">
406
+ ${message}
407
+ <span class="lze-blocker__dotting">
408
+ <span class="lze-blocker__dot"></span>
409
+ <span class="lze-blocker__dot"></span>
410
+ <span class="lze-blocker__dot"></span>
411
+ </span>
412
+ </div>
413
+ <div class="lze-blocker__error">${errorMessage}</div>
414
+ <div class="lze-blocker__error_suggestion">${suggestinMessage}</div>
415
+ <div class="lze-blocker__spinner"></div>
416
+ </div>
417
+ `;
418
+ const style = `
419
+ .lze-blocker {
420
+ position: fixed;
421
+ top: 0;
422
+ left: 0;
423
+ width: 100%;
424
+ height: 100%;
425
+ background: rgba(0, 0, 0, 0.8);
426
+ z-index: ${zIndex};
427
+ display: flex;
428
+ align-items: center;
429
+ justify-content: center;
430
+ flex-direction: column;
431
+ color: #fff;
432
+ font-family: Arial, sans-serif;
433
+ text-align: center;
434
+ padding: 20px;
435
+ box-sizing: border-box;
436
+ overflow: hidden;
437
+ user-select: none;
438
+ }
439
+
440
+ .lze-blocker__spinner {
441
+ border: 4px solid rgba(255, 255, 255, 0.1);
442
+ border-top: 4px solid #fff;
443
+ border-radius: 50%;
444
+ width: 50px;
445
+ height: 50px;
446
+ animation: spin 1s linear infinite;
447
+ margin-top: 20px;
448
+ }
449
+
450
+ .lze-blocker__message {
451
+ color: #fff;
452
+ font-size: 18px;
453
+ margin-bottom: 10px;
454
+ }
455
+
456
+ .lze-blocker__dotting {
457
+ display: inline-block;
458
+ vertical-align: middle;
459
+ }
460
+ .lze-blocker__dot {
461
+ display: inline-block;
462
+ width: 7px;
463
+ height: 7px;
464
+ background-color: #ffffff;
465
+ border-radius: 50%;
466
+ margin-left: 3px;
467
+ opacity: 0.3;
468
+ animation: dotting 1s infinite;
469
+ }
470
+ .lze-blocker__dot:nth-child(1) {
471
+ animation-delay: 0s;
472
+ opacity: 1;
473
+ }
474
+ .lze-blocker__dot:nth-child(2) {
475
+ animation-delay: 0.2s;
476
+ }
477
+ .lze-blocker__dot:nth-child(3) {
478
+ animation-delay: 0.4s;
479
+ }
480
+
481
+ @keyframes dotting {
482
+ 0%, 80%, 100% { opacity: 0.3; }
483
+ 40% { opacity: 1; }
484
+ }
485
+
486
+ .lze-blocker__error {
487
+ color: #f00;
488
+ font-size: 14px;
489
+ margin-bottom: 10px;
490
+ text-shadow: 0 0 1px #ff5f5f;
491
+ }
492
+
493
+ .lze-blocker__error_suggestion {
494
+ color: #ccc;
495
+ font-size: 14px;
496
+ margin-top: 10px;
497
+ }
498
+
499
+ @keyframes spin {
500
+ 0% { transform: rotate(0deg); }
501
+ 100% { transform: rotate(360deg); }
502
+ }
503
+ `;
504
+ const styleElement = document.createElement('style');
505
+ if (add) {
506
+ if (!document.querySelector('.lze-blocker')) {
507
+ styleElement.innerHTML = style;
508
+ document.head.appendChild(styleElement);
509
+ body.insertAdjacentHTML('beforeend', blcokerHtml);
510
+ }
511
+ }
512
+ else {
513
+ this.removeBlocker(styleElement);
514
+ }
515
+ return styleElement;
516
+ }
517
+ removeBlocker(styleElement) {
518
+ const blocker = document.querySelector('.lze-blocker');
519
+ blocker === null || blocker === void 0 ? void 0 : blocker.remove();
520
+ styleElement === null || styleElement === void 0 ? void 0 : styleElement.remove();
521
+ }
522
+ }
523
+ const ApiHelper = new LocalizeApiHelper();
524
+
525
+ const SCHEMES = LocalizeToken.httpHeaders;
251
526
  class LocalizeApiService {
252
527
  constructor(httpClient, localizeTokenService) {
253
528
  this.httpClient = httpClient;
254
529
  this.localizeTokenService = localizeTokenService;
530
+ this.destroy$ = new Subject();
255
531
  this.isRequestingSubject = new BehaviorSubject(false);
256
532
  this.isResolvedStartupSubject = new BehaviorSubject(false);
257
- this.apiConfigs = {};
533
+ this.needTenant = LocalizeToken.config.needTenant;
534
+ this.config = {
535
+ waitEachRequest: { milliseconds: 0 },
536
+ enableRequestCancellation: true,
537
+ retryOptions: {
538
+ maxRetries: 1000,
539
+ delay: 1000,
540
+ retryFunction: ApiHelper.defaultRetryFunction.bind(this),
541
+ },
542
+ };
543
+ this.apiOptions = {
544
+ method: EMethod.GET,
545
+ requestBody: null,
546
+ };
258
547
  /**
259
548
  * A higher-order function that returns a curried function for making API requests.
260
549
  *
261
550
  * @param baseUrl - The base URL of the API.
262
551
  * @returns A curried function that can be used to make API requests.
263
552
  */
264
- this.func = (baseUrl) => (path, method = EMethod.GET, value = null, isFormData = false, headers) => this.base(baseUrl, path, method, value, isFormData, headers);
553
+ this.func = (baseUrl) => (path, method = EMethod.GET, reqBody = null, reqHeaders) => this.request(baseUrl, path, method, reqBody, reqHeaders);
265
554
  }
266
- get isRequesting() { return this.isRequestingSubject.value; }
267
555
  get isResolvedStartup() { return this.isResolvedStartupSubject.value; }
556
+ get isRequesting() { return this.isRequestingSubject.value; }
557
+ get isRevokingToken() { return this.localizeTokenService.isRevokingToken; }
558
+ set isRevokingToken(value) { this.localizeTokenService.isRevokingToken = value; }
559
+ get accessToken() { return this.localizeTokenService.accessToken; }
560
+ set accessToken(value) { this.localizeTokenService.accessToken = value; }
561
+ get refreshToken() { return this.localizeTokenService.refreshToken; }
562
+ get tenantToken() { return this.localizeTokenService.tenantToken(this.config.tenantTokenName); }
268
563
  /**
269
564
  * Initialize the API service.
270
565
  * @param apiConfigs - The API configurations.
271
566
  */
272
567
  init(apiConfigs) {
273
- this.apiConfigs = apiConfigs;
568
+ this.config = Object.assign(Object.assign({}, this.config), apiConfigs);
569
+ ApiHelper.validateConfig(this.config);
570
+ }
571
+ cancelPendingRequests() {
572
+ this.config.enableRequestCancellation
573
+ && this.destroy$.next();
574
+ }
575
+ ngOnDestroy() {
576
+ this.destroy$.next();
577
+ this.destroy$.complete();
274
578
  }
275
- base(baseUrl, path, method = EMethod.GET, value = null, isFormData = false, headers) {
579
+ request(baseUrl, path, method = EMethod.GET, reqBody = null, reqHeaders) {
276
580
  return __awaiter(this, void 0, void 0, function* () {
277
- yield this.ifPromise(this.apiConfigs.onPrepareRequest);
278
- const url = `${baseUrl.trim().replace(/\/?$/, '/')}${path.trim().replace(/^\//, '')}`;
279
- const httpMethod = EMethod[method].toLowerCase();
280
- const request = () => { return { body: value, headers: this.options(isFormData, headers) }; };
281
- // Wait for previous request to complete
282
- yield this.toWaitForPreviousRequest();
283
- // Process request
581
+ yield ApiHelper.invokeHook(this.config.onPrepareRequest);
582
+ const apiOptions = this.buildApiOptions(baseUrl, path, method, reqBody, reqHeaders);
284
583
  try {
285
- return yield this.processRequest(httpMethod, url, request());
584
+ yield this.toWaitForPreviousRequest();
585
+ return yield ApiHelper.performRequestWithRetry(apiOptions, this.config, this.performRequest.bind(this));
286
586
  }
287
- // Handle unauthorized error if any
288
587
  catch (error) {
289
- if (error.status !== 401) {
290
- throw error;
291
- }
292
- return yield this.onUnauthorizedError(httpMethod, url, request);
293
- }
294
- });
295
- }
296
- onUnauthorizedError(httpMethod, url, request) {
297
- return __awaiter(this, void 0, void 0, function* () {
298
- yield this.revokeToken();
299
- if (!this.isResolvedStartup) {
300
- return yield this.processRequest(httpMethod, url, request());
588
+ return yield this.handleOnRequestError(error, apiOptions);
301
589
  }
302
590
  });
303
591
  }
304
- toWaitForPreviousRequest() {
305
- var _a;
592
+ handleOnRequestError(error, options) {
306
593
  return __awaiter(this, void 0, void 0, function* () {
307
- if (this.localizeTokenService.isRevokingToken) {
308
- yield waitUntil(() => !this.localizeTokenService.isRevokingToken);
309
- }
310
- // to wait for each request in 50ms, even if the request is not completed
311
- if ((_a = this.apiConfigs.waitEachRequest) === null || _a === void 0 ? void 0 : _a.milliseconds) {
312
- yield waitFor(this.apiConfigs.waitEachRequest.milliseconds, this.isRequesting);
313
- }
594
+ if (error.status !== 401 || this.isResolvedStartup)
595
+ throw error;
596
+ return yield ApiHelper.performRetry({
597
+ maxRetries: () => 1000,
598
+ delay: 500,
599
+ retryUnless: (error) => error.status === 401 || ApiHelper.isConnectionError(error),
600
+ callback: () => __awaiter(this, void 0, void 0, function* () {
601
+ // Only handle 401 Unauthorized errors
602
+ yield this.revokeToken();
603
+ // Retry the request with the new access token
604
+ return yield this.performRequest(options);
605
+ })
606
+ });
314
607
  });
315
608
  }
316
- processRequest(method, url, options) {
609
+ performRequest(options) {
317
610
  return __awaiter(this, void 0, void 0, function* () {
611
+ // Build the request options
612
+ const buildOptions = { headers: this.buildHeaderOptions(options) };
613
+ // Create the request observable
614
+ const request$ = ApiHelper.createRequest({
615
+ client: this.httpClient,
616
+ destroy$: () => this.destroy$
617
+ }, options.method, options.requestUrl, options.requestBody, buildOptions);
618
+ // Set the isRequesting state to true before making the request
318
619
  this.isRequestingSubject.next(true);
319
- const result = yield new Promise((resolve, reject) => this.httpClient.request(method, url, options).subscribe({ next: resolve, error: reject }));
620
+ const response = yield new Promise((resolve, reject) => request$.subscribe({ next: (res) => resolve(res.body), error: reject }));
621
+ // Reset the isRequesting state after the request completes
320
622
  this.isRequestingSubject.next(false);
321
- return result;
623
+ return response;
322
624
  });
323
625
  }
324
626
  revokeToken() {
325
627
  return __awaiter(this, void 0, void 0, function* () {
326
- if (this.localizeTokenService.isRevokingToken) {
327
- yield waitUntil(() => !this.localizeTokenService.isRevokingToken);
328
- return;
329
- }
330
628
  try {
331
- this.localizeTokenService.isRevokingToken = true;
332
- const reqUrl = LocalizeToken.config.revokeTokenUrl;
333
- const reqHeaders = this.options().append(LocalizeToken.httpHeaders.X_REFRESH_TOKEN, `${this.localizeTokenService.refreshToken}`);
334
- const revokeToken = yield new Promise((resolve, reject) => this.httpClient.get(reqUrl, { headers: reqHeaders }).subscribe({ next: resolve, error: reject }));
335
- if (revokeToken === null || revokeToken === void 0 ? void 0 : revokeToken.status) {
336
- this.localizeTokenService.accessToken = revokeToken.message;
337
- }
338
- else if (!this.localizeTokenService.refreshToken) {
339
- yield this.ifPromise(this.apiConfigs.onAutoLogout);
340
- }
341
- else {
342
- if (this.apiConfigs.onRevokeUnauthorized) {
343
- yield this.ifPromise(this.apiConfigs.onRevokeUnauthorized);
344
- // await this.revokeToken(true);
345
- }
346
- }
629
+ if (yield this.interceptRevokeToken())
630
+ return;
631
+ this.isRevokingToken = true;
632
+ const apiOptions = Object.assign(Object.assign({}, this.buildApiOptions(LocalizeToken.config.revokeTokenUrl)), { refreshToken: true });
633
+ // const revokeToken = await this.performRequest(apiOptions);
634
+ const revokeToken = yield ApiHelper.performRequestWithRetry(apiOptions, this.config, this.performRequest.bind(this));
635
+ yield this.handleOnTokenRevoked(revokeToken);
636
+ }
637
+ catch (error) {
638
+ // Handle the error, log it
639
+ yield ApiHelper.invokeHook(this.config.onAutoLogout);
347
640
  }
348
641
  finally {
349
- this.localizeTokenService.isRevokingToken = false;
642
+ // Reset the revoking token state
643
+ this.isRevokingToken = false;
350
644
  }
351
645
  });
352
646
  }
353
647
  /** default http request options */
354
- options(isFormData = false, headers = {}) {
355
- const defaultHeaders = { [LocalizeToken.httpHeaders.AUTHORIZATION]: `Bearer ${this.localizeTokenService.accessToken}`, };
356
- if (LocalizeToken.config.needTenant) {
357
- defaultHeaders[LocalizeToken.httpHeaders.X_TENANT] = `${this.localizeTokenService.tenantToken(this.apiConfigs.tenantTokenName)}`;
358
- }
359
- if (!isFormData) {
360
- defaultHeaders[LocalizeToken.httpHeaders.CONTENT_TYPE] = 'application/json';
648
+ buildHeaderOptions(options) {
649
+ let headers = Object.assign(Object.assign({}, (options.refreshToken && { [SCHEMES.X_REFRESH_TOKEN]: `${this.refreshToken}` })), (!options.isFormData && { [SCHEMES.CONTENT_TYPE]: 'application/json' }));
650
+ if (!options.refreshToken) {
651
+ headers = Object.assign(Object.assign(Object.assign({}, headers), { [SCHEMES.AUTHORIZATION]: `Bearer ${this.accessToken}` }), (this.needTenant && { [SCHEMES.X_TENANT]: `${this.tenantToken}` }));
361
652
  }
362
- const filteredHeaders = Object.keys(defaultHeaders).filter(key => !Object.keys(headers).includes(key))
363
- .reduce((acc, key) => (Object.assign(Object.assign({}, acc), { [key]: defaultHeaders[key] })), {});
364
- const mergedHeaders = Object.assign(Object.assign({}, filteredHeaders), headers);
365
- return new HttpHeaders(mergedHeaders);
653
+ return new HttpHeaders(Object.assign(Object.assign({}, headers), options.headers));
366
654
  }
367
- ifPromise(fn) {
655
+ buildApiOptions(baseUrl, path = '', method = EMethod.GET, requestBody = null, headers) {
656
+ const requestUrl = ApiHelper.buildUrl(baseUrl, path);
657
+ const isFormData = requestBody && requestBody instanceof FormData;
658
+ return Object.assign(Object.assign({}, this.apiOptions), { headers, method, requestUrl, requestBody, isFormData });
659
+ }
660
+ toWaitForPreviousRequest() {
661
+ var _a;
368
662
  return __awaiter(this, void 0, void 0, function* () {
369
- if (!fn)
370
- return;
371
- return fn instanceof Promise ? yield fn() : fn();
663
+ this.isRevokingToken &&
664
+ (yield waitUntil(() => !this.isRevokingToken));
665
+ // to wait for each request in 50ms, even if the request is not completed
666
+ ((_a = this.config.waitEachRequest) === null || _a === void 0 ? void 0 : _a.milliseconds) &&
667
+ (yield waitFor(this.config.waitEachRequest.milliseconds, this.isRequesting));
668
+ });
669
+ }
670
+ handleOnTokenRevoked(response) {
671
+ return __awaiter(this, void 0, void 0, function* () {
672
+ if (response === null || response === void 0 ? void 0 : response.status) {
673
+ // If the response is successful, update the access token
674
+ this.accessToken = response.message;
675
+ }
676
+ else {
677
+ // If the response indicates an error, invoke the onRevokeUnauthorized hook
678
+ console.warn('Token revocation failed, refresh token is expired.', response.message);
679
+ yield ApiHelper.invokeHook(this.config.onRevokeUnauthorized);
680
+ }
681
+ });
682
+ }
683
+ interceptRevokeToken() {
684
+ return __awaiter(this, void 0, void 0, function* () {
685
+ if (this.isRevokingToken) {
686
+ console.warn('Token is already being revoked. Waiting for the current operation to complete...');
687
+ yield waitUntil(() => !this.isRevokingToken);
688
+ return true;
689
+ }
690
+ if (!this.refreshToken) {
691
+ // await ApiHelper.invokeHook(this.apiConfigs.onAutoLogout);
692
+ throw new Error('Refresh token is missing. Please login again.');
693
+ }
694
+ return false;
372
695
  });
373
696
  }
374
- } //class
697
+ }
375
698
  LocalizeApiService.ɵprov = i0.ɵɵdefineInjectable({ factory: function LocalizeApiService_Factory() { return new LocalizeApiService(i0.ɵɵinject(i1.HttpClient), i0.ɵɵinject(LocalizeTokenService)); }, token: LocalizeApiService, providedIn: "root" });
376
699
  LocalizeApiService.decorators = [
377
700
  { type: Injectable, args: [{
@@ -390,18 +713,19 @@ LocalizeTokenModule.decorators = [
390
713
  providers: [
391
714
  LocalizeTokenService,
392
715
  LocalizeApiService
393
- ],
716
+ ]
394
717
  },] }
395
718
  ];
396
719
 
397
720
  class LocalizeLogindlgComponent {
398
- constructor(messageService, cdt, dlgRef, dlgConfig, tokenService, httpClient) {
721
+ constructor(messageService, cdt, dlgRef, dlgConfig, tokenService, httpClient, sanitizer) {
399
722
  this.messageService = messageService;
400
723
  this.cdt = cdt;
401
724
  this.dlgRef = dlgRef;
402
725
  this.dlgConfig = dlgConfig;
403
726
  this.tokenService = tokenService;
404
727
  this.httpClient = httpClient;
728
+ this.sanitizer = sanitizer;
405
729
  this.messageKey = "$login-dlg";
406
730
  this.loading = false;
407
731
  this.success = false;
@@ -409,6 +733,7 @@ class LocalizeLogindlgComponent {
409
733
  this.clickLogout = () => { var _a; return (_a = this.logout) === null || _a === void 0 ? void 0 : _a.call(this); };
410
734
  this.decodeToken = this.tokenService.decodeRefreshToken;
411
735
  this.loginConfig = this.dlgConfig.data.loginConfig;
736
+ this.properties = this.loginConfig.properties;
412
737
  }
413
738
  ngOnInit() {
414
739
  this.dlgConfig.closable = false;
@@ -426,31 +751,37 @@ class LocalizeLogindlgComponent {
426
751
  var _a, _b;
427
752
  return __awaiter(this, void 0, void 0, function* () {
428
753
  if (!this.isValidPassword) {
429
- this.showMessage("error", "Password is required and must be at least 6 characters");
430
- return;
754
+ return this.showMessage("error", "Password is required and must be at least 6 characters");
431
755
  }
432
756
  this.loading = true;
433
757
  const loginRes = yield this.login();
434
758
  if (!(loginRes === null || loginRes === void 0 ? void 0 : loginRes.status)) {
435
- this.showMessage("error", (_a = loginRes.message) !== null && _a !== void 0 ? _a : "An error occurred");
436
- return;
759
+ return this.showMessage("error", (_a = loginRes.message) !== null && _a !== void 0 ? _a : "An error occurred");
437
760
  }
438
761
  this.tokenService.accessToken = loginRes.tokens.accessToken;
439
- const cookieOptions = { expires: (_b = this.loginConfig.expire) !== null && _b !== void 0 ? _b : 5 };
762
+ const cookieOptions = { expires: (_b = this.loginConfig.expire) !== null && _b !== void 0 ? _b : 365 };
440
763
  LocalizeToken.storage.set(this.config.refreshTokenName, loginRes.tokens.refreshToken, cookieOptions);
441
764
  this.success = true;
442
- setTimeout(() => this.dlgRef.close(true), 2000);
765
+ setTimeout(() => {
766
+ this.dlgConfig.dismissableMask = true;
767
+ this.dlgConfig.modal = false;
768
+ this.dlgRef.close(true);
769
+ }, 2000);
443
770
  });
444
771
  }
445
772
  login() {
773
+ var _a, _b, _c;
446
774
  return __awaiter(this, void 0, void 0, function* () {
447
- if (!this.loginUrl || !this.loginUrl.trim().length) {
775
+ if (!((_a = this.loginUrl) === null || _a === void 0 ? void 0 : _a.trim().length)) {
448
776
  this.showMessage("error", "Login url is required");
449
777
  throw new Error("Login url is required");
450
778
  }
451
779
  try {
452
- return yield new Promise((resolve, reject) => this.httpClient.post(this.loginUrl, { password: this.password.trim() }, { headers: this.getHeaders() })
453
- .subscribe({ next: resolve, error: reject }));
780
+ if (this.loginConfig.loginFunction) {
781
+ console.log("Using custom login function");
782
+ return yield this.loginConfig.loginFunction((_c = (_b = this.decodeToken) === null || _b === void 0 ? void 0 : _b.email) !== null && _c !== void 0 ? _c : '', this.password.trim(), this.getHeaders());
783
+ }
784
+ return yield new Promise((resolve, reject) => this.httpClient.post(this.loginUrl, { password: this.password.trim() }, { headers: this.getHeaders() }).subscribe({ next: resolve, error: reject }));
454
785
  }
455
786
  catch (e) {
456
787
  this.showMessage("error", e.message);
@@ -467,21 +798,27 @@ class LocalizeLogindlgComponent {
467
798
  }
468
799
  get isValidPassword() {
469
800
  this.loading = false;
470
- return this.password && this.password.trim().length >= 6 && this.password.trim().length <= 50;
801
+ return this.properties.passwordValidator
802
+ ? this.properties.passwordValidator(this.password)
803
+ : this.password && this.password.trim().length >= 6 && this.password.trim().length <= 50;
471
804
  }
472
805
  showMessage(severity, summary) {
473
806
  this.messageService.add({ key: this.messageKey, severity, summary });
474
807
  this.loading = false;
475
808
  }
809
+ get sanitizedTitle() {
810
+ var _a;
811
+ return this.sanitizer.bypassSecurityTrustHtml((_a = this.properties.title) !== null && _a !== void 0 ? _a : '');
812
+ }
476
813
  }
477
814
  LocalizeLogindlgComponent.decorators = [
478
815
  { type: Component, args: [{
479
816
  template: `<p-toast key="$login-dlg" position="top-center"></p-toast>
480
817
  <div id="login-dlg-wrap">
481
818
  <div id="login-dlg-header">
482
- <div id="login-logo" class="p-mb-2"></div>
483
- <h3 *ngIf="!success">Your session is expired! <br> Please login again to continue.</h3>
484
- <h3 *ngIf="success" style="color:green !important;">You haved successfully logged in.</h3>
819
+ <div id="login-logo" class="p-mb-2" style="background: url('{{properties.logoImage}}') no-repeat"></div>
820
+ <h3 *ngIf="!success" [innerHTML]="sanitizedTitle"></h3>
821
+ <h3 *ngIf="success" style="color:green !important;">{{properties.loginSuccessMessage}}</h3>
485
822
  </div>
486
823
  <div id="login-dlg-content">
487
824
  <ng-container *ngIf="!success">
@@ -493,7 +830,7 @@ LocalizeLogindlgComponent.decorators = [
493
830
  <span class="p-inputgroup-addon">
494
831
  <i class="material-icons-round">person</i>
495
832
  </span>
496
- <input disabled pInputText type="text" placeholder="Username" [value]="decodeToken?.email" />
833
+ <input disabled pInputText type="text" placeholder="{{properties.username?.placeHolder}}" [value]="decodeToken?.email" />
497
834
  </div>
498
835
  </div>
499
836
 
@@ -502,18 +839,20 @@ LocalizeLogindlgComponent.decorators = [
502
839
  <span class="p-inputgroup-addon">
503
840
  <i class="material-icons-round">lock</i>
504
841
  </span>
505
- <input [disabled]="loading" (keydown.enter)="clickLogin()" pInputText type="password" placeholder="Password" [(ngModel)]="password"
842
+ <input [disabled]="loading" (keydown.enter)="clickLogin()" pInputText type="password"
843
+ placeholder="{{properties.password?.placeHolder}}" [(ngModel)]="password"
506
844
  autofocus />
507
845
  </div>
508
846
  </div>
509
847
  <div class="login-dlg-elm">
510
- <button style="width: 100%;" pButton type="button" label="Login" (click)="clickLogin()"
848
+ <button style="width: 100%;" pButton type="button" label="{{properties.loginButton?.placeHolder}}" (click)="clickLogin()"
511
849
  [disabled]="!password || loading"></button>
512
850
  </div>
513
851
 
514
- <div class="login-dlg-elm" style="display:flex;align-items: center;user-select: none;">
515
- <span>No, I want to login with another user.</span>
516
- <button class="p-button-text" pButton type="button" label="Logout" (click)="clickLogout()"></button>
852
+ <div class="login-dlg-elm login-dlg-suggest" style="display:flex;align-items: center;user-select: none;">
853
+ <span>{{properties.logoutButton?.message}}</span>
854
+ <button class="p-button-text" pButton type="button" label="{{properties.logoutButton?.placeHolder}}"
855
+ (click)="clickLogout()"></button>
517
856
  </div>
518
857
  </ng-container>
519
858
 
@@ -543,11 +882,23 @@ LocalizeLogindlgComponent.decorators = [
543
882
  max-width: 400px;
544
883
  margin: 0 auto;
545
884
  padding: 30px;
885
+ height: 100%;
546
886
  }
547
887
 
548
888
  .login-dlg-elm {
549
889
  margin-top: 1rem;
550
890
  }
891
+
892
+ .login-dlg-elm.login-dlg-suggest {
893
+ display: flex ;
894
+ align-items: center;
895
+ user-select: none;
896
+ border-bottom: solid 1px #ddd;
897
+ border-radius: 5px;
898
+ padding: 5px 10px;
899
+ background: #f9f9f9;
900
+ box-shadow: 1px 5px 10px -12px #000;
901
+ }
551
902
 
552
903
  #login-dlg-header {
553
904
  display: flex;
@@ -564,10 +915,10 @@ LocalizeLogindlgComponent.decorators = [
564
915
  }
565
916
 
566
917
  #login-logo {
567
- height: 40px;
568
- width: 40px;
569
- background: url("/assets/images/logo-300px.png") no-repeat;
570
- background-size: contain;
918
+ height: 55px;
919
+ width: 55px;
920
+ /* background: url("/assets/images/logo-300px.png") no-repeat; */
921
+ background-size: contain !important;
571
922
  }
572
923
 
573
924
  #login-dlg-content .p-inputgroup {
@@ -579,6 +930,10 @@ LocalizeLogindlgComponent.decorators = [
579
930
  border-radius: 15px 0 0 15px;
580
931
  width: 50px;
581
932
  }
933
+ #login-dlg-content *{
934
+ font-size: .9rem;
935
+ /* font-family: 'Lexend', 'Roboto', sans-serif, 'material-icons-round'; */
936
+ }
582
937
 
583
938
  #login-dlg-content .p-inputgroup .p-inputgroup-addon * {
584
939
  font-size: 1rem;
@@ -773,7 +1128,8 @@ LocalizeLogindlgComponent.ctorParameters = () => [
773
1128
  { type: DynamicDialogRef },
774
1129
  { type: DynamicDialogConfig },
775
1130
  { type: LocalizeTokenService },
776
- { type: HttpClient }
1131
+ { type: HttpClient },
1132
+ { type: DomSanitizer }
777
1133
  ];
778
1134
 
779
1135
  class LocalizeLogindlgService {
@@ -782,12 +1138,9 @@ class LocalizeLogindlgService {
782
1138
  }
783
1139
  openLoginDialog(loginConfig, config) {
784
1140
  return __awaiter(this, void 0, void 0, function* () {
785
- config !== null && config !== void 0 ? config : (config = {
786
- header: 'Login',
787
- height: '650px',
788
- style: { 'max-width': '400px', width: '100%', 'height': '650px' },
789
- });
790
- config.data = Object.assign(Object.assign({}, config.data || {}), { loginConfig });
1141
+ config = this.intercepDialogConfig(config);
1142
+ this.initConfig(loginConfig);
1143
+ config.data = Object.assign(Object.assign({}, (config.data || {})), { loginConfig });
791
1144
  const dialogService = this.injector.get(DialogService);
792
1145
  const dialog = dialogService.open(LocalizeLogindlgComponent, config);
793
1146
  yield new Promise((resolve) => dialog.onClose.subscribe(res => {
@@ -797,6 +1150,36 @@ class LocalizeLogindlgService {
797
1150
  }));
798
1151
  });
799
1152
  }
1153
+ intercepDialogConfig(config) {
1154
+ config !== null && config !== void 0 ? config : (config = {
1155
+ header: 'Login',
1156
+ style: { 'max-width': '400px', width: '100%', 'height': '650px' },
1157
+ modal: true,
1158
+ closable: false,
1159
+ showHeader: false,
1160
+ });
1161
+ config = Object.assign(Object.assign({}, config), {
1162
+ contentStyle: { 'height': '100%', 'border-radius': '20px' }
1163
+ });
1164
+ config.style = Object.assign(Object.assign({}, config.style), { 'border-radius': '20px' });
1165
+ return config;
1166
+ }
1167
+ initConfig(loginConfig) {
1168
+ var _a;
1169
+ loginConfig !== null && loginConfig !== void 0 ? loginConfig : (loginConfig = {});
1170
+ (_a = loginConfig.properties) !== null && _a !== void 0 ? _a : (loginConfig.properties = {
1171
+ title: 'Your session is expired!<br/> Please login again to continue.',
1172
+ loginSuccessMessage: 'You have successfully logged in.',
1173
+ logoImage: '/assets/images/logo-300px.png',
1174
+ username: { placeHolder: 'Username' },
1175
+ password: { placeHolder: 'Password' },
1176
+ loginButton: { placeHolder: 'Login' },
1177
+ logoutButton: {
1178
+ message: 'No, I want to login with another user.',
1179
+ placeHolder: 'Logout'
1180
+ }
1181
+ });
1182
+ }
800
1183
  }
801
1184
  LocalizeLogindlgService.ɵprov = i0.ɵɵdefineInjectable({ factory: function LocalizeLogindlgService_Factory() { return new LocalizeLogindlgService(i0.ɵɵinject(i0.INJECTOR)); }, token: LocalizeLogindlgService, providedIn: "root" });
802
1185
  LocalizeLogindlgService.decorators = [
@@ -831,5 +1214,5 @@ LocalizeLogindlgModule.decorators = [
831
1214
  * Generated bundle index. Do not edit.
832
1215
  */
833
1216
 
834
- export { EMethod, LocalizeApiService, LocalizeLogindlgComponent, LocalizeLogindlgModule, LocalizeLogindlgService, LocalizeToken, LocalizeTokenModule, LocalizeTokenService, LocalizeTokenStorage, extractMainDomain, waitFor, waitUntil };
1217
+ export { ApiHelper, EMethod, LocalizeApiService, LocalizeLogindlgComponent, LocalizeLogindlgModule, LocalizeLogindlgService, LocalizeToken, LocalizeTokenModule, LocalizeTokenService, LocalizeTokenStorage, extractMainDomain, waitFor, waitUntil };
835
1218
  //# sourceMappingURL=sambath999-localize-token.js.map