@opexa/portal-sdk 0.59.127 → 0.59.129
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/README.md +1698 -1698
- package/dist/{chunk-5WRVWQBT.js → chunk-7APXFZ5G.js} +3 -3
- package/dist/chunk-7APXFZ5G.js.map +1 -0
- package/dist/{chunk-36U3QUDP.js → chunk-ROZQZKKD.js} +17 -10
- package/dist/chunk-ROZQZKKD.js.map +1 -0
- package/dist/{chunk-ROBGEUSE.js → chunk-WVFSGB7Y.js} +2 -2
- package/dist/chunk-WVFSGB7Y.js.map +1 -0
- package/dist/index.cjs +277 -102
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +266 -98
- package/dist/index.js.map +1 -1
- package/dist/services/index.cjs +14 -7
- package/dist/services/index.cjs.map +1 -1
- package/dist/services/index.d.cts +4 -4
- package/dist/services/index.d.ts +4 -4
- package/dist/services/index.js +2 -2
- package/dist/{types-CO_xQd_7.d.cts → types-B-Y3xNfe.d.cts} +1 -1
- package/dist/{types-B2ydKuMW.d.ts → types-EDjOGXkh.d.ts} +1 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-36U3QUDP.js.map +0 -1
- package/dist/chunk-5WRVWQBT.js.map +0 -1
- package/dist/chunk-ROBGEUSE.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CmsPortalService, GameService, ExtensionService, FileService, WalletService, AccountService, ReportService, PortalService, TriggerService, AuthService, getFingerPrint, isIOSPlatform } from './chunk-
|
|
2
|
-
import { GraphQLClient, isPlainObject } from './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { CmsPortalService, GameService, ExtensionService, FileService, WalletService, AccountService, ReportService, PortalService, TriggerService, AuthService, getFingerPrint, isIOSPlatform } from './chunk-ROZQZKKD.js';
|
|
2
|
+
import { GraphQLClient, isPlainObject } from './chunk-7APXFZ5G.js';
|
|
3
|
+
import './chunk-WVFSGB7Y.js';
|
|
4
4
|
import { ObjectId } from '@opexa/object-id';
|
|
5
5
|
export { ObjectId } from '@opexa/object-id';
|
|
6
6
|
import { Capacitor } from '@capacitor/core';
|
|
@@ -380,6 +380,36 @@ function createRefreshTokenStore(logger, sessionPrefix) {
|
|
|
380
380
|
return new PreferencesRefreshTokenStore(key, logger);
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
// src/sdk/session-lifecycle.ts
|
|
384
|
+
var SessionLifecycle = class {
|
|
385
|
+
controller = new AbortController();
|
|
386
|
+
get signal() {
|
|
387
|
+
return this.controller.signal;
|
|
388
|
+
}
|
|
389
|
+
renew() {
|
|
390
|
+
this.controller.abort();
|
|
391
|
+
this.controller = new AbortController();
|
|
392
|
+
return this.controller.signal;
|
|
393
|
+
}
|
|
394
|
+
logout() {
|
|
395
|
+
this.renew();
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
var CredentialMutationLock = class {
|
|
399
|
+
tail = Promise.resolve();
|
|
400
|
+
wait() {
|
|
401
|
+
return this.tail;
|
|
402
|
+
}
|
|
403
|
+
run(operation) {
|
|
404
|
+
const result = this.tail.then(operation, operation);
|
|
405
|
+
this.tail = result.then(
|
|
406
|
+
() => void 0,
|
|
407
|
+
() => void 0
|
|
408
|
+
);
|
|
409
|
+
return result;
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
383
413
|
// src/sdk/session-manager.ts
|
|
384
414
|
var SessionManager = class {
|
|
385
415
|
logger;
|
|
@@ -388,6 +418,8 @@ var SessionManager = class {
|
|
|
388
418
|
authService;
|
|
389
419
|
walletService;
|
|
390
420
|
_refreshing = false;
|
|
421
|
+
lifecycle = new SessionLifecycle();
|
|
422
|
+
mutations = new CredentialMutationLock();
|
|
391
423
|
/*
|
|
392
424
|
* v4 access tokens live in memory only, so an XSS-readable storage layer
|
|
393
425
|
* never holds a live one. Re-minted from the HttpOnly cookie, or from
|
|
@@ -417,38 +449,44 @@ var SessionManager = class {
|
|
|
417
449
|
set refreshing(value) {
|
|
418
450
|
this._refreshing = value;
|
|
419
451
|
}
|
|
420
|
-
async persist(data, version) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
452
|
+
async persist(data, version, signal) {
|
|
453
|
+
return this.mutations.run(async () => {
|
|
454
|
+
if (signal.aborted) return true;
|
|
455
|
+
const now = /* @__PURE__ */ new Date();
|
|
456
|
+
this.refreshing = false;
|
|
457
|
+
this.v4RefreshPromise = null;
|
|
458
|
+
if (version === 4) {
|
|
459
|
+
if (!data.session || !data.accessToken) {
|
|
460
|
+
this.logger.error(
|
|
461
|
+
"Malformed session response: expected 'session' and 'accessToken'."
|
|
462
|
+
);
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
this.v4AccessToken = data.accessToken;
|
|
466
|
+
this.v4AccessTokenExpiresAt = addMinutes(now, 4).getTime();
|
|
467
|
+
this.invalidReason = null;
|
|
468
|
+
if (data.refreshToken) {
|
|
469
|
+
await this.refreshTokenStore.set(data.refreshToken);
|
|
470
|
+
}
|
|
471
|
+
if (signal.aborted) return true;
|
|
472
|
+
localStorage.setItem(
|
|
473
|
+
this.storageKey,
|
|
474
|
+
JSON.stringify({ version, session: data.session })
|
|
426
475
|
);
|
|
427
|
-
return
|
|
476
|
+
return true;
|
|
428
477
|
}
|
|
429
|
-
this.v4AccessToken = data.accessToken;
|
|
430
|
-
this.v4AccessTokenExpiresAt = addMinutes(now, 4).getTime();
|
|
431
478
|
this.invalidReason = null;
|
|
432
|
-
if (data.refreshToken) {
|
|
433
|
-
await this.refreshTokenStore.set(data.refreshToken);
|
|
434
|
-
}
|
|
435
479
|
localStorage.setItem(
|
|
436
480
|
this.storageKey,
|
|
437
|
-
JSON.stringify({
|
|
481
|
+
JSON.stringify({
|
|
482
|
+
version,
|
|
483
|
+
...data,
|
|
484
|
+
accessTokenExpiresAt: addMinutes(now, 8).getTime(),
|
|
485
|
+
refreshTokenExpiresAt: subMinutes(addDays(now, 1), 2).getTime()
|
|
486
|
+
})
|
|
438
487
|
);
|
|
439
488
|
return true;
|
|
440
|
-
}
|
|
441
|
-
this.invalidReason = null;
|
|
442
|
-
localStorage.setItem(
|
|
443
|
-
this.storageKey,
|
|
444
|
-
JSON.stringify({
|
|
445
|
-
version,
|
|
446
|
-
...data,
|
|
447
|
-
accessTokenExpiresAt: addMinutes(now, 8).getTime(),
|
|
448
|
-
refreshTokenExpiresAt: subMinutes(addDays(now, 1), 2).getTime()
|
|
449
|
-
})
|
|
450
|
-
);
|
|
451
|
-
return true;
|
|
489
|
+
});
|
|
452
490
|
}
|
|
453
491
|
malformedResponseError() {
|
|
454
492
|
return {
|
|
@@ -460,6 +498,10 @@ var SessionManager = class {
|
|
|
460
498
|
};
|
|
461
499
|
}
|
|
462
500
|
async create(input, version = 1) {
|
|
501
|
+
const waitingSignal = this.lifecycle.signal;
|
|
502
|
+
await this.mutations.wait();
|
|
503
|
+
if (waitingSignal.aborted) return { ok: true, data: null };
|
|
504
|
+
const signal = this.lifecycle.renew();
|
|
463
505
|
if (this.isServer) {
|
|
464
506
|
this.logger.warn("'localStorage' is not available on the server.");
|
|
465
507
|
return {
|
|
@@ -495,7 +537,7 @@ var SessionManager = class {
|
|
|
495
537
|
maxAttempt: 5
|
|
496
538
|
})();
|
|
497
539
|
if (!r1.ok) return r1;
|
|
498
|
-
if (!await this.persist(r1.data, version))
|
|
540
|
+
if (!await this.persist(r1.data, version, signal))
|
|
499
541
|
return this.malformedResponseError();
|
|
500
542
|
return {
|
|
501
543
|
ok: true,
|
|
@@ -505,7 +547,7 @@ var SessionManager = class {
|
|
|
505
547
|
if (input.type === "MOBILE_NUMBER") {
|
|
506
548
|
const res2 = await this.authService.createSession(input, version);
|
|
507
549
|
if (res2.ok) {
|
|
508
|
-
if (!await this.persist(res2.data, version))
|
|
550
|
+
if (!await this.persist(res2.data, version, signal))
|
|
509
551
|
return this.malformedResponseError();
|
|
510
552
|
return {
|
|
511
553
|
ok: true,
|
|
@@ -524,7 +566,7 @@ var SessionManager = class {
|
|
|
524
566
|
version
|
|
525
567
|
);
|
|
526
568
|
if (res2.ok) {
|
|
527
|
-
if (!await this.persist(res2.data, version))
|
|
569
|
+
if (!await this.persist(res2.data, version, signal))
|
|
528
570
|
return this.malformedResponseError();
|
|
529
571
|
return {
|
|
530
572
|
ok: true,
|
|
@@ -537,7 +579,7 @@ var SessionManager = class {
|
|
|
537
579
|
localStorage.setItem(this.platformStorageKey, "CABINET");
|
|
538
580
|
const res2 = await this.authService.createSession(input, version);
|
|
539
581
|
if (res2.ok) {
|
|
540
|
-
if (!await this.persist(res2.data, version))
|
|
582
|
+
if (!await this.persist(res2.data, version, signal))
|
|
541
583
|
return this.malformedResponseError();
|
|
542
584
|
return {
|
|
543
585
|
ok: true,
|
|
@@ -556,7 +598,7 @@ var SessionManager = class {
|
|
|
556
598
|
}
|
|
557
599
|
};
|
|
558
600
|
}
|
|
559
|
-
if (!await this.persist(res.data, version))
|
|
601
|
+
if (!await this.persist(res.data, version, signal))
|
|
560
602
|
return this.malformedResponseError();
|
|
561
603
|
return {
|
|
562
604
|
ok: true,
|
|
@@ -564,11 +606,15 @@ var SessionManager = class {
|
|
|
564
606
|
};
|
|
565
607
|
}
|
|
566
608
|
async createFromAuthenticator(input) {
|
|
609
|
+
const waitingSignal = this.lifecycle.signal;
|
|
610
|
+
await this.mutations.wait();
|
|
611
|
+
if (waitingSignal.aborted) return { ok: true };
|
|
612
|
+
const signal = this.lifecycle.renew();
|
|
567
613
|
const res = await this.authService.authenticate(input);
|
|
568
614
|
if (res.ok) {
|
|
569
615
|
if (this.isServer) {
|
|
570
616
|
this.logger.warn("'localStorage' is not available on the server.");
|
|
571
|
-
} else if (!await this.persist(res.data, 1)) {
|
|
617
|
+
} else if (!await this.persist(res.data, 1, signal)) {
|
|
572
618
|
return this.malformedResponseError();
|
|
573
619
|
}
|
|
574
620
|
return { ok: true };
|
|
@@ -577,6 +623,7 @@ var SessionManager = class {
|
|
|
577
623
|
}
|
|
578
624
|
}
|
|
579
625
|
async get() {
|
|
626
|
+
const signal = this.lifecycle.signal;
|
|
580
627
|
if (this.isServer) {
|
|
581
628
|
this.logger.warn("'localStorage' is not available on the server.");
|
|
582
629
|
return {
|
|
@@ -586,6 +633,7 @@ var SessionManager = class {
|
|
|
586
633
|
}
|
|
587
634
|
if (this.refreshing) {
|
|
588
635
|
await sleep(1e3);
|
|
636
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
589
637
|
return await this.get();
|
|
590
638
|
}
|
|
591
639
|
const val = localStorage.getItem(this.storageKey);
|
|
@@ -620,8 +668,10 @@ var SessionManager = class {
|
|
|
620
668
|
this.refreshing = true;
|
|
621
669
|
const res = await this.authService.refreshSession(
|
|
622
670
|
obj.refreshToken,
|
|
623
|
-
obj.version ?? 1
|
|
671
|
+
obj.version ?? 1,
|
|
672
|
+
signal
|
|
624
673
|
);
|
|
674
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
625
675
|
this.refreshing = false;
|
|
626
676
|
if (!res.ok) {
|
|
627
677
|
this.logger.error(`Failed to refresh session: ${res.error.message}`);
|
|
@@ -654,6 +704,8 @@ var SessionManager = class {
|
|
|
654
704
|
data: obj
|
|
655
705
|
};
|
|
656
706
|
} catch {
|
|
707
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
708
|
+
this.refreshing = false;
|
|
657
709
|
return {
|
|
658
710
|
ok: false,
|
|
659
711
|
error: {
|
|
@@ -678,6 +730,7 @@ var SessionManager = class {
|
|
|
678
730
|
return await this.refreshV4(session);
|
|
679
731
|
}
|
|
680
732
|
async refresh() {
|
|
733
|
+
const signal = this.lifecycle.signal;
|
|
681
734
|
if (this.isServer) {
|
|
682
735
|
this.logger.warn("'localStorage' is not available on the server.");
|
|
683
736
|
return {
|
|
@@ -703,8 +756,10 @@ var SessionManager = class {
|
|
|
703
756
|
this.refreshing = true;
|
|
704
757
|
const res = await this.authService.refreshSession(
|
|
705
758
|
obj.refreshToken,
|
|
706
|
-
obj.version ?? 1
|
|
759
|
+
obj.version ?? 1,
|
|
760
|
+
signal
|
|
707
761
|
);
|
|
762
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
708
763
|
this.refreshing = false;
|
|
709
764
|
if (!res.ok) {
|
|
710
765
|
this.logger.error(`Failed to refresh session: ${res.error.message}`);
|
|
@@ -737,6 +792,8 @@ var SessionManager = class {
|
|
|
737
792
|
data: obj
|
|
738
793
|
};
|
|
739
794
|
} catch {
|
|
795
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
796
|
+
this.refreshing = false;
|
|
740
797
|
return {
|
|
741
798
|
ok: false,
|
|
742
799
|
error: {
|
|
@@ -748,18 +805,20 @@ var SessionManager = class {
|
|
|
748
805
|
}
|
|
749
806
|
async refreshV4(session) {
|
|
750
807
|
if (this.v4RefreshPromise) return await this.v4RefreshPromise;
|
|
751
|
-
|
|
808
|
+
const promise = this.requestV4Refresh(session, this.lifecycle.signal);
|
|
809
|
+
this.v4RefreshPromise = promise;
|
|
752
810
|
try {
|
|
753
|
-
return await
|
|
811
|
+
return await promise;
|
|
754
812
|
} finally {
|
|
755
|
-
this.v4RefreshPromise = null;
|
|
813
|
+
if (this.v4RefreshPromise === promise) this.v4RefreshPromise = null;
|
|
756
814
|
}
|
|
757
815
|
}
|
|
758
|
-
async requestV4Refresh(session) {
|
|
816
|
+
async requestV4Refresh(session, signal) {
|
|
759
817
|
this.logger.info("Refreshing session...");
|
|
760
818
|
let refreshToken;
|
|
761
819
|
if (isIOSPlatform()) {
|
|
762
820
|
refreshToken = await this.refreshTokenStore.get() ?? void 0;
|
|
821
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
763
822
|
if (!refreshToken) {
|
|
764
823
|
this.logger.warn("No stored refresh token. Session expired.");
|
|
765
824
|
this.v4AccessToken = null;
|
|
@@ -776,7 +835,8 @@ var SessionManager = class {
|
|
|
776
835
|
}
|
|
777
836
|
}
|
|
778
837
|
this.refreshing = true;
|
|
779
|
-
const res = await this.authService.refreshSession(refreshToken, 4);
|
|
838
|
+
const res = await this.authService.refreshSession(refreshToken, 4, signal);
|
|
839
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
780
840
|
if (!res.ok) {
|
|
781
841
|
this.logger.error(`Failed to refresh session: ${res.error.message}`);
|
|
782
842
|
const terminal = res.error.name === "InvalidTokenError" || res.error.name === "AccountBlacklistedError" || res.error.name === "VerificationLockedError" || res.error.name === "SessionExpiredError";
|
|
@@ -788,6 +848,7 @@ var SessionManager = class {
|
|
|
788
848
|
}
|
|
789
849
|
this.refreshing = false;
|
|
790
850
|
if (terminal) await this.refreshTokenStore.remove();
|
|
851
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
791
852
|
return {
|
|
792
853
|
ok: false,
|
|
793
854
|
error: res.error
|
|
@@ -797,8 +858,13 @@ var SessionManager = class {
|
|
|
797
858
|
this.logger.success("Session refreshed!");
|
|
798
859
|
this.invalidReason = null;
|
|
799
860
|
if (res.data.refreshToken) {
|
|
800
|
-
await this.
|
|
861
|
+
await this.mutations.run(async () => {
|
|
862
|
+
if (!signal.aborted && res.data.refreshToken) {
|
|
863
|
+
await this.refreshTokenStore.set(res.data.refreshToken);
|
|
864
|
+
}
|
|
865
|
+
});
|
|
801
866
|
}
|
|
867
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
802
868
|
const now = /* @__PURE__ */ new Date();
|
|
803
869
|
this.v4AccessToken = res.data.accessToken;
|
|
804
870
|
this.v4AccessTokenExpiresAt = addMinutes(now, 4).getTime();
|
|
@@ -816,26 +882,53 @@ var SessionManager = class {
|
|
|
816
882
|
this.logger.warn("'localStorage' is not available on the server.");
|
|
817
883
|
return;
|
|
818
884
|
}
|
|
819
|
-
let version = 1;
|
|
885
|
+
let version = this.v4AccessToken ? 4 : 1;
|
|
886
|
+
let accessToken = this.v4AccessToken ?? void 0;
|
|
887
|
+
let accessTokenExpiresAt = this.v4AccessTokenExpiresAt;
|
|
888
|
+
let refreshToken;
|
|
820
889
|
const val = localStorage.getItem(this.storageKey);
|
|
821
890
|
if (val) {
|
|
822
891
|
try {
|
|
823
892
|
const stored = JSON.parse(val);
|
|
824
893
|
version = stored.version ?? 1;
|
|
894
|
+
accessToken = stored.version === 4 ? this.v4AccessToken ?? void 0 : stored.accessToken;
|
|
895
|
+
accessTokenExpiresAt = stored.version === 4 ? this.v4AccessTokenExpiresAt : stored.accessTokenExpiresAt;
|
|
896
|
+
if (stored.version !== 4) refreshToken = stored.refreshToken;
|
|
825
897
|
} catch {
|
|
826
898
|
}
|
|
827
899
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
}
|
|
900
|
+
this.lifecycle.logout();
|
|
901
|
+
this.refreshing = false;
|
|
902
|
+
this.v4RefreshPromise = null;
|
|
832
903
|
this.v4AccessToken = null;
|
|
833
904
|
this.v4AccessTokenExpiresAt = null;
|
|
834
905
|
this.invalidReason = null;
|
|
835
|
-
await this.refreshTokenStore.remove();
|
|
836
906
|
localStorage.removeItem(this.storageKey);
|
|
907
|
+
await this.mutations.run(async () => {
|
|
908
|
+
try {
|
|
909
|
+
if (val && (!accessToken || !accessTokenExpiresAt || Date.now() > accessTokenExpiresAt)) {
|
|
910
|
+
if (version === 4 && isIOSPlatform()) {
|
|
911
|
+
refreshToken = await this.refreshTokenStore.get() ?? void 0;
|
|
912
|
+
}
|
|
913
|
+
if (refreshToken || version === 4 && !isIOSPlatform()) {
|
|
914
|
+
accessToken = void 0;
|
|
915
|
+
const res = await this.authService.refreshSession(
|
|
916
|
+
refreshToken,
|
|
917
|
+
version
|
|
918
|
+
);
|
|
919
|
+
if (res.ok) accessToken = res.data.accessToken;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (accessToken) {
|
|
923
|
+
await this.authService.destroySession(accessToken, version);
|
|
924
|
+
}
|
|
925
|
+
} finally {
|
|
926
|
+
if (version === 4) await this.refreshTokenStore.remove();
|
|
927
|
+
}
|
|
928
|
+
});
|
|
837
929
|
}
|
|
838
930
|
async verify() {
|
|
931
|
+
const signal = this.lifecycle.signal;
|
|
839
932
|
if (this.isServer) {
|
|
840
933
|
this.logger.warn("'localStorage' is not available on the server.");
|
|
841
934
|
return { valid: true };
|
|
@@ -848,7 +941,8 @@ var SessionManager = class {
|
|
|
848
941
|
try {
|
|
849
942
|
const stored = JSON.parse(val);
|
|
850
943
|
if (stored.version === 4) {
|
|
851
|
-
const res = await this.verifyV4(stored.session);
|
|
944
|
+
const res = await this.verifyV4(stored.session, signal);
|
|
945
|
+
if (signal.aborted) return { valid: true };
|
|
852
946
|
if (!res.valid) localStorage.removeItem(this.storageKey);
|
|
853
947
|
return res;
|
|
854
948
|
}
|
|
@@ -856,32 +950,37 @@ var SessionManager = class {
|
|
|
856
950
|
}
|
|
857
951
|
}
|
|
858
952
|
const s = await this.get();
|
|
953
|
+
if (signal.aborted) return { valid: true };
|
|
859
954
|
if (s.error?.name === "InvalidTokenError" || s.error?.name === "SessionExpiredError" || s.error?.name === "AccountBlacklistedError") {
|
|
860
955
|
this.invalidReason = "INVALID_SESSION";
|
|
861
956
|
return { valid: false, reason: "INVALID_SESSION" };
|
|
862
957
|
}
|
|
863
958
|
if (!s.data) return { valid: true };
|
|
864
|
-
const v = await this.authService.verifySession(s.data.accessToken);
|
|
959
|
+
const v = await this.authService.verifySession(s.data.accessToken, signal);
|
|
960
|
+
if (signal.aborted) return { valid: true };
|
|
865
961
|
if (!v) {
|
|
866
962
|
this.invalidReason = "INVALID_SESSION";
|
|
867
963
|
localStorage.removeItem(this.storageKey);
|
|
868
964
|
}
|
|
869
965
|
return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
|
|
870
966
|
}
|
|
871
|
-
async verifyV4(session) {
|
|
967
|
+
async verifyV4(session, signal) {
|
|
872
968
|
if (!this.v4AccessToken || !this.v4AccessTokenExpiresAt || isAfter(/* @__PURE__ */ new Date(), new Date(this.v4AccessTokenExpiresAt))) {
|
|
873
969
|
const res = await this.refreshV4(session);
|
|
970
|
+
if (signal.aborted) return { valid: true };
|
|
874
971
|
if (res.ok) return { valid: true };
|
|
875
972
|
if (!this.invalidReason) return { valid: true };
|
|
876
973
|
return { valid: false, reason: this.invalidReason };
|
|
877
974
|
}
|
|
878
|
-
const v = await this.authService.verifySession(this.v4AccessToken);
|
|
975
|
+
const v = await this.authService.verifySession(this.v4AccessToken, signal);
|
|
976
|
+
if (signal.aborted) return { valid: true };
|
|
879
977
|
if (!v) {
|
|
880
978
|
localStorage.removeItem(this.storageKey);
|
|
881
979
|
this.v4AccessToken = null;
|
|
882
980
|
this.v4AccessTokenExpiresAt = null;
|
|
883
981
|
this.invalidReason = "INVALID_SESSION";
|
|
884
982
|
await this.refreshTokenStore.remove();
|
|
983
|
+
if (signal.aborted) return { valid: true };
|
|
885
984
|
}
|
|
886
985
|
return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
|
|
887
986
|
}
|
|
@@ -910,6 +1009,8 @@ var SessionManagerCookie = class {
|
|
|
910
1009
|
authService;
|
|
911
1010
|
walletService;
|
|
912
1011
|
_refreshing = false;
|
|
1012
|
+
lifecycle = new SessionLifecycle();
|
|
1013
|
+
mutations = new CredentialMutationLock();
|
|
913
1014
|
/*
|
|
914
1015
|
* v4 access tokens live in memory only, so an XSS-readable storage layer
|
|
915
1016
|
* never holds a live one. Re-minted from the HttpOnly cookie, or from
|
|
@@ -932,34 +1033,44 @@ var SessionManagerCookie = class {
|
|
|
932
1033
|
set refreshing(value) {
|
|
933
1034
|
this._refreshing = value;
|
|
934
1035
|
}
|
|
935
|
-
async persist(data, version) {
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
this.
|
|
940
|
-
this.
|
|
941
|
-
|
|
942
|
-
|
|
1036
|
+
async persist(data, version, signal) {
|
|
1037
|
+
return this.mutations.run(async () => {
|
|
1038
|
+
if (signal.aborted) return;
|
|
1039
|
+
const now = /* @__PURE__ */ new Date();
|
|
1040
|
+
this.refreshing = false;
|
|
1041
|
+
this.v4RefreshPromise = null;
|
|
1042
|
+
this.invalidReason = null;
|
|
1043
|
+
if (version === 4) {
|
|
1044
|
+
this.v4AccessToken = data.accessToken ?? null;
|
|
1045
|
+
this.v4AccessTokenExpiresAt = addMinutes(now, 5).getTime();
|
|
1046
|
+
if (data.refreshToken) {
|
|
1047
|
+
await this.refreshTokenStore.set(data.refreshToken);
|
|
1048
|
+
}
|
|
1049
|
+
if (signal.aborted) return;
|
|
1050
|
+
cookies.set(
|
|
1051
|
+
this.storageKey,
|
|
1052
|
+
JSON.stringify({ version, session: data.session }),
|
|
1053
|
+
{ expires: subMinutes(addDays(now, 15), 2) }
|
|
1054
|
+
);
|
|
1055
|
+
return;
|
|
943
1056
|
}
|
|
944
1057
|
cookies.set(
|
|
945
1058
|
this.storageKey,
|
|
946
|
-
JSON.stringify({
|
|
947
|
-
|
|
1059
|
+
JSON.stringify({
|
|
1060
|
+
version,
|
|
1061
|
+
...data,
|
|
1062
|
+
accessTokenExpiresAt: addMinutes(now, 8).getTime(),
|
|
1063
|
+
refreshTokenExpiresAt: subMinutes(addDays(now, 30), 2).getTime()
|
|
1064
|
+
}),
|
|
1065
|
+
{ expires: subMinutes(addDays(now, 30), 2) }
|
|
948
1066
|
);
|
|
949
|
-
|
|
950
|
-
}
|
|
951
|
-
cookies.set(
|
|
952
|
-
this.storageKey,
|
|
953
|
-
JSON.stringify({
|
|
954
|
-
version,
|
|
955
|
-
...data,
|
|
956
|
-
accessTokenExpiresAt: addMinutes(now, 8).getTime(),
|
|
957
|
-
refreshTokenExpiresAt: subMinutes(addDays(now, 30), 2).getTime()
|
|
958
|
-
}),
|
|
959
|
-
{ expires: subMinutes(addDays(now, 30), 2) }
|
|
960
|
-
);
|
|
1067
|
+
});
|
|
961
1068
|
}
|
|
962
1069
|
async create(input, version = 1) {
|
|
1070
|
+
const waitingSignal = this.lifecycle.signal;
|
|
1071
|
+
await this.mutations.wait();
|
|
1072
|
+
if (waitingSignal.aborted) return { ok: true, data: null };
|
|
1073
|
+
const signal = this.lifecycle.renew();
|
|
963
1074
|
if (input.type === "MAYA") {
|
|
964
1075
|
localStorage.setItem(this.platformStorageKey, "MAYA");
|
|
965
1076
|
const f0 = () => this.walletService.mayaSession({ id: input.sessionId });
|
|
@@ -985,7 +1096,7 @@ var SessionManagerCookie = class {
|
|
|
985
1096
|
maxAttempt: 5
|
|
986
1097
|
})();
|
|
987
1098
|
if (!r1.ok) return r1;
|
|
988
|
-
await this.persist(r1.data, version);
|
|
1099
|
+
await this.persist(r1.data, version, signal);
|
|
989
1100
|
return {
|
|
990
1101
|
ok: true,
|
|
991
1102
|
data: null
|
|
@@ -994,7 +1105,7 @@ var SessionManagerCookie = class {
|
|
|
994
1105
|
if (input.type === "MOBILE_NUMBER") {
|
|
995
1106
|
const res2 = await this.authService.createSession(input, version);
|
|
996
1107
|
if (res2.ok) {
|
|
997
|
-
await this.persist(res2.data, version);
|
|
1108
|
+
await this.persist(res2.data, version, signal);
|
|
998
1109
|
return {
|
|
999
1110
|
ok: true,
|
|
1000
1111
|
data: null
|
|
@@ -1011,7 +1122,7 @@ var SessionManagerCookie = class {
|
|
|
1011
1122
|
version
|
|
1012
1123
|
);
|
|
1013
1124
|
if (res2.ok) {
|
|
1014
|
-
await this.persist(res2.data, version);
|
|
1125
|
+
await this.persist(res2.data, version, signal);
|
|
1015
1126
|
return {
|
|
1016
1127
|
ok: true,
|
|
1017
1128
|
data: null
|
|
@@ -1023,7 +1134,7 @@ var SessionManagerCookie = class {
|
|
|
1023
1134
|
localStorage.setItem(this.platformStorageKey, "CABINET");
|
|
1024
1135
|
const res2 = await this.authService.createSession(input, version);
|
|
1025
1136
|
if (res2.ok) {
|
|
1026
|
-
await this.persist(res2.data, version);
|
|
1137
|
+
await this.persist(res2.data, version, signal);
|
|
1027
1138
|
return {
|
|
1028
1139
|
ok: true,
|
|
1029
1140
|
data: null
|
|
@@ -1041,19 +1152,23 @@ var SessionManagerCookie = class {
|
|
|
1041
1152
|
}
|
|
1042
1153
|
};
|
|
1043
1154
|
}
|
|
1044
|
-
await this.persist(res.data, version);
|
|
1155
|
+
await this.persist(res.data, version, signal);
|
|
1045
1156
|
return {
|
|
1046
1157
|
ok: true,
|
|
1047
1158
|
data: null
|
|
1048
1159
|
};
|
|
1049
1160
|
}
|
|
1050
1161
|
async createFromAuthenticator(input) {
|
|
1162
|
+
const waitingSignal = this.lifecycle.signal;
|
|
1163
|
+
await this.mutations.wait();
|
|
1164
|
+
if (waitingSignal.aborted) return { ok: true };
|
|
1165
|
+
const signal = this.lifecycle.renew();
|
|
1051
1166
|
const res = await this.authService.authenticate(input);
|
|
1052
1167
|
if (res.ok) {
|
|
1053
1168
|
if (this.isServer) {
|
|
1054
1169
|
this.logger.warn("'client cookies' is not available on the server.");
|
|
1055
1170
|
} else {
|
|
1056
|
-
await this.persist(res.data, 1);
|
|
1171
|
+
await this.persist(res.data, 1, signal);
|
|
1057
1172
|
}
|
|
1058
1173
|
return { ok: true };
|
|
1059
1174
|
} else {
|
|
@@ -1061,6 +1176,7 @@ var SessionManagerCookie = class {
|
|
|
1061
1176
|
}
|
|
1062
1177
|
}
|
|
1063
1178
|
async get() {
|
|
1179
|
+
const signal = this.lifecycle.signal;
|
|
1064
1180
|
if (this.isServer) {
|
|
1065
1181
|
this.logger.warn("'client cookies' is not available on the server.");
|
|
1066
1182
|
return {
|
|
@@ -1070,6 +1186,7 @@ var SessionManagerCookie = class {
|
|
|
1070
1186
|
}
|
|
1071
1187
|
if (this.refreshing) {
|
|
1072
1188
|
await sleep(1e3);
|
|
1189
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1073
1190
|
return await this.get();
|
|
1074
1191
|
}
|
|
1075
1192
|
const val = cookies.get(this.storageKey);
|
|
@@ -1104,8 +1221,10 @@ var SessionManagerCookie = class {
|
|
|
1104
1221
|
this.refreshing = true;
|
|
1105
1222
|
const res = await this.authService.refreshSession(
|
|
1106
1223
|
obj.refreshToken,
|
|
1107
|
-
obj.version ?? 1
|
|
1224
|
+
obj.version ?? 1,
|
|
1225
|
+
signal
|
|
1108
1226
|
);
|
|
1227
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1109
1228
|
this.refreshing = false;
|
|
1110
1229
|
if (!res.ok) {
|
|
1111
1230
|
this.logger.error(`Failed to refresh session: ${res.error.message}`);
|
|
@@ -1141,6 +1260,8 @@ var SessionManagerCookie = class {
|
|
|
1141
1260
|
data: obj
|
|
1142
1261
|
};
|
|
1143
1262
|
} catch {
|
|
1263
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1264
|
+
this.refreshing = false;
|
|
1144
1265
|
return {
|
|
1145
1266
|
ok: false,
|
|
1146
1267
|
error: {
|
|
@@ -1165,6 +1286,7 @@ var SessionManagerCookie = class {
|
|
|
1165
1286
|
return await this.refreshV4(session);
|
|
1166
1287
|
}
|
|
1167
1288
|
async refresh() {
|
|
1289
|
+
const signal = this.lifecycle.signal;
|
|
1168
1290
|
if (this.isServer) {
|
|
1169
1291
|
this.logger.warn("'client cookies' is not available on the server.");
|
|
1170
1292
|
return {
|
|
@@ -1190,8 +1312,10 @@ var SessionManagerCookie = class {
|
|
|
1190
1312
|
this.refreshing = true;
|
|
1191
1313
|
const res = await this.authService.refreshSession(
|
|
1192
1314
|
obj.refreshToken,
|
|
1193
|
-
obj.version ?? 1
|
|
1315
|
+
obj.version ?? 1,
|
|
1316
|
+
signal
|
|
1194
1317
|
);
|
|
1318
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1195
1319
|
this.refreshing = false;
|
|
1196
1320
|
if (!res.ok) {
|
|
1197
1321
|
this.logger.error(`Failed to refresh session: ${res.error.message}`);
|
|
@@ -1226,6 +1350,8 @@ var SessionManagerCookie = class {
|
|
|
1226
1350
|
data: obj
|
|
1227
1351
|
};
|
|
1228
1352
|
} catch {
|
|
1353
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1354
|
+
this.refreshing = false;
|
|
1229
1355
|
return {
|
|
1230
1356
|
ok: false,
|
|
1231
1357
|
error: {
|
|
@@ -1237,18 +1363,20 @@ var SessionManagerCookie = class {
|
|
|
1237
1363
|
}
|
|
1238
1364
|
async refreshV4(session) {
|
|
1239
1365
|
if (this.v4RefreshPromise) return await this.v4RefreshPromise;
|
|
1240
|
-
|
|
1366
|
+
const promise = this.requestV4Refresh(session, this.lifecycle.signal);
|
|
1367
|
+
this.v4RefreshPromise = promise;
|
|
1241
1368
|
try {
|
|
1242
|
-
return await
|
|
1369
|
+
return await promise;
|
|
1243
1370
|
} finally {
|
|
1244
|
-
this.v4RefreshPromise = null;
|
|
1371
|
+
if (this.v4RefreshPromise === promise) this.v4RefreshPromise = null;
|
|
1245
1372
|
}
|
|
1246
1373
|
}
|
|
1247
|
-
async requestV4Refresh(session) {
|
|
1374
|
+
async requestV4Refresh(session, signal) {
|
|
1248
1375
|
this.logger.info("Refreshing session...");
|
|
1249
1376
|
let refreshToken;
|
|
1250
1377
|
if (isIOSPlatform()) {
|
|
1251
1378
|
refreshToken = await this.refreshTokenStore.get() ?? void 0;
|
|
1379
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1252
1380
|
if (!refreshToken) {
|
|
1253
1381
|
this.logger.warn("No stored refresh token. Session expired.");
|
|
1254
1382
|
this.v4AccessToken = null;
|
|
@@ -1265,7 +1393,8 @@ var SessionManagerCookie = class {
|
|
|
1265
1393
|
}
|
|
1266
1394
|
}
|
|
1267
1395
|
this.refreshing = true;
|
|
1268
|
-
const res = await this.authService.refreshSession(refreshToken, 4);
|
|
1396
|
+
const res = await this.authService.refreshSession(refreshToken, 4, signal);
|
|
1397
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1269
1398
|
if (!res.ok) {
|
|
1270
1399
|
this.logger.error(`Failed to refresh session: ${res.error.message}`);
|
|
1271
1400
|
const terminal = res.error.name === "InvalidTokenError" || res.error.name === "AccountBlacklistedError" || res.error.name === "VerificationLockedError" || res.error.name === "SessionExpiredError";
|
|
@@ -1277,6 +1406,7 @@ var SessionManagerCookie = class {
|
|
|
1277
1406
|
}
|
|
1278
1407
|
this.refreshing = false;
|
|
1279
1408
|
if (terminal) await this.refreshTokenStore.remove();
|
|
1409
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1280
1410
|
return {
|
|
1281
1411
|
ok: false,
|
|
1282
1412
|
error: res.error
|
|
@@ -1286,8 +1416,13 @@ var SessionManagerCookie = class {
|
|
|
1286
1416
|
this.logger.success("Session refreshed!");
|
|
1287
1417
|
this.invalidReason = null;
|
|
1288
1418
|
if (res.data.refreshToken) {
|
|
1289
|
-
await this.
|
|
1419
|
+
await this.mutations.run(async () => {
|
|
1420
|
+
if (!signal.aborted && res.data.refreshToken) {
|
|
1421
|
+
await this.refreshTokenStore.set(res.data.refreshToken);
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1290
1424
|
}
|
|
1425
|
+
if (signal.aborted) return { ok: true, data: null };
|
|
1291
1426
|
const now = /* @__PURE__ */ new Date();
|
|
1292
1427
|
this.v4AccessToken = res.data.accessToken;
|
|
1293
1428
|
this.v4AccessTokenExpiresAt = addMinutes(now, 5).getTime();
|
|
@@ -1305,26 +1440,53 @@ var SessionManagerCookie = class {
|
|
|
1305
1440
|
this.logger.warn("'client cookies' is not available on the server.");
|
|
1306
1441
|
return;
|
|
1307
1442
|
}
|
|
1308
|
-
let version = 1;
|
|
1443
|
+
let version = this.v4AccessToken ? 4 : 1;
|
|
1444
|
+
let accessToken = this.v4AccessToken ?? void 0;
|
|
1445
|
+
let accessTokenExpiresAt = this.v4AccessTokenExpiresAt;
|
|
1446
|
+
let refreshToken;
|
|
1309
1447
|
const val = cookies.get(this.storageKey);
|
|
1310
1448
|
if (val) {
|
|
1311
1449
|
try {
|
|
1312
1450
|
const stored = JSON.parse(val);
|
|
1313
1451
|
version = stored.version ?? 1;
|
|
1452
|
+
accessToken = stored.version === 4 ? this.v4AccessToken ?? void 0 : stored.accessToken;
|
|
1453
|
+
accessTokenExpiresAt = stored.version === 4 ? this.v4AccessTokenExpiresAt : stored.accessTokenExpiresAt;
|
|
1454
|
+
if (stored.version !== 4) refreshToken = stored.refreshToken;
|
|
1314
1455
|
} catch {
|
|
1315
1456
|
}
|
|
1316
1457
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
}
|
|
1458
|
+
this.lifecycle.logout();
|
|
1459
|
+
this.refreshing = false;
|
|
1460
|
+
this.v4RefreshPromise = null;
|
|
1321
1461
|
this.v4AccessToken = null;
|
|
1322
1462
|
this.v4AccessTokenExpiresAt = null;
|
|
1323
1463
|
this.invalidReason = null;
|
|
1324
|
-
await this.refreshTokenStore.remove();
|
|
1325
1464
|
cookies.remove(this.storageKey);
|
|
1465
|
+
await this.mutations.run(async () => {
|
|
1466
|
+
try {
|
|
1467
|
+
if (val && (!accessToken || !accessTokenExpiresAt || Date.now() > accessTokenExpiresAt)) {
|
|
1468
|
+
if (version === 4 && isIOSPlatform()) {
|
|
1469
|
+
refreshToken = await this.refreshTokenStore.get() ?? void 0;
|
|
1470
|
+
}
|
|
1471
|
+
if (refreshToken || version === 4 && !isIOSPlatform()) {
|
|
1472
|
+
accessToken = void 0;
|
|
1473
|
+
const res = await this.authService.refreshSession(
|
|
1474
|
+
refreshToken,
|
|
1475
|
+
version
|
|
1476
|
+
);
|
|
1477
|
+
if (res.ok) accessToken = res.data.accessToken;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
if (accessToken) {
|
|
1481
|
+
await this.authService.destroySession(accessToken, version);
|
|
1482
|
+
}
|
|
1483
|
+
} finally {
|
|
1484
|
+
if (version === 4) await this.refreshTokenStore.remove();
|
|
1485
|
+
}
|
|
1486
|
+
});
|
|
1326
1487
|
}
|
|
1327
1488
|
async verify() {
|
|
1489
|
+
const signal = this.lifecycle.signal;
|
|
1328
1490
|
if (this.isServer) {
|
|
1329
1491
|
this.logger.warn("'client cookies' is not available on the server.");
|
|
1330
1492
|
return { valid: true };
|
|
@@ -1337,7 +1499,8 @@ var SessionManagerCookie = class {
|
|
|
1337
1499
|
try {
|
|
1338
1500
|
const stored = JSON.parse(val);
|
|
1339
1501
|
if (stored.version === 4) {
|
|
1340
|
-
const res = await this.verifyV4(stored.session);
|
|
1502
|
+
const res = await this.verifyV4(stored.session, signal);
|
|
1503
|
+
if (signal.aborted) return { valid: true };
|
|
1341
1504
|
if (!res.valid) cookies.remove(this.storageKey);
|
|
1342
1505
|
return res;
|
|
1343
1506
|
}
|
|
@@ -1345,32 +1508,37 @@ var SessionManagerCookie = class {
|
|
|
1345
1508
|
}
|
|
1346
1509
|
}
|
|
1347
1510
|
const s = await this.get();
|
|
1511
|
+
if (signal.aborted) return { valid: true };
|
|
1348
1512
|
if (s.error?.name === "InvalidTokenError" || s.error?.name === "SessionExpiredError" || s.error?.name === "AccountBlacklistedError") {
|
|
1349
1513
|
this.invalidReason = "INVALID_SESSION";
|
|
1350
1514
|
return { valid: false, reason: "INVALID_SESSION" };
|
|
1351
1515
|
}
|
|
1352
1516
|
if (!s.data) return { valid: true };
|
|
1353
|
-
const v = await this.authService.verifySession(s.data.accessToken);
|
|
1517
|
+
const v = await this.authService.verifySession(s.data.accessToken, signal);
|
|
1518
|
+
if (signal.aborted) return { valid: true };
|
|
1354
1519
|
if (!v) {
|
|
1355
1520
|
this.invalidReason = "INVALID_SESSION";
|
|
1356
1521
|
cookies.remove(this.storageKey);
|
|
1357
1522
|
}
|
|
1358
1523
|
return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
|
|
1359
1524
|
}
|
|
1360
|
-
async verifyV4(session) {
|
|
1525
|
+
async verifyV4(session, signal) {
|
|
1361
1526
|
if (!this.v4AccessToken || !this.v4AccessTokenExpiresAt || isAfter(/* @__PURE__ */ new Date(), new Date(this.v4AccessTokenExpiresAt))) {
|
|
1362
1527
|
const res = await this.refreshV4(session);
|
|
1528
|
+
if (signal.aborted) return { valid: true };
|
|
1363
1529
|
if (res.ok) return { valid: true };
|
|
1364
1530
|
if (!this.invalidReason) return { valid: true };
|
|
1365
1531
|
return { valid: false, reason: this.invalidReason };
|
|
1366
1532
|
}
|
|
1367
|
-
const v = await this.authService.verifySession(this.v4AccessToken);
|
|
1533
|
+
const v = await this.authService.verifySession(this.v4AccessToken, signal);
|
|
1534
|
+
if (signal.aborted) return { valid: true };
|
|
1368
1535
|
if (!v) {
|
|
1369
1536
|
cookies.remove(this.storageKey);
|
|
1370
1537
|
this.v4AccessToken = null;
|
|
1371
1538
|
this.v4AccessTokenExpiresAt = null;
|
|
1372
1539
|
this.invalidReason = "INVALID_SESSION";
|
|
1373
1540
|
await this.refreshTokenStore.remove();
|
|
1541
|
+
if (signal.aborted) return { valid: true };
|
|
1374
1542
|
}
|
|
1375
1543
|
return v ? { valid: true } : { valid: false, reason: "INVALID_SESSION" };
|
|
1376
1544
|
}
|