astro-tokenkit 1.0.24 → 1.0.26
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/auth/manager.js +47 -25
- package/dist/client/idle-manager.d.ts +1 -0
- package/dist/client/idle-manager.js +16 -0
- package/dist/index.cjs +47 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +47 -25
- package/dist/index.js.map +1 -1
- package/dist/middleware.cjs +47 -25
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.js +47 -25
- package/dist/middleware.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/package.json +5 -5
package/dist/auth/manager.js
CHANGED
|
@@ -20,18 +20,39 @@ import { logger } from '../utils/logger';
|
|
|
20
20
|
class SingleFlight {
|
|
21
21
|
constructor() {
|
|
22
22
|
this.inFlight = new Map();
|
|
23
|
+
this.recent = new Map();
|
|
24
|
+
this.GRACE_PERIOD = 5000; // 5 seconds grace period for race conditions
|
|
23
25
|
}
|
|
24
26
|
execute(key, fn) {
|
|
25
27
|
return __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
// 1. Check in-flight
|
|
26
29
|
const existing = this.inFlight.get(key);
|
|
27
30
|
if (existing)
|
|
28
31
|
return existing;
|
|
32
|
+
// 2. Check recent (grace period)
|
|
33
|
+
const cached = this.recent.get(key);
|
|
34
|
+
if (cached && (Date.now() - cached.time < this.GRACE_PERIOD)) {
|
|
35
|
+
return cached.bundle;
|
|
36
|
+
}
|
|
37
|
+
// 3. Execute new flight
|
|
29
38
|
const promise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
30
39
|
try {
|
|
31
|
-
|
|
40
|
+
const bundle = yield fn();
|
|
41
|
+
// Store in recent on success
|
|
42
|
+
if (bundle) {
|
|
43
|
+
this.recent.set(key, { bundle, time: Date.now() });
|
|
44
|
+
}
|
|
45
|
+
return bundle;
|
|
32
46
|
}
|
|
33
47
|
finally {
|
|
34
48
|
this.inFlight.delete(key);
|
|
49
|
+
// Cleanup old entries
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
for (const [k, v] of this.recent.entries()) {
|
|
52
|
+
if (now - v.time > this.GRACE_PERIOD) {
|
|
53
|
+
this.recent.delete(k);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
35
56
|
}
|
|
36
57
|
}))();
|
|
37
58
|
this.inFlight.set(key, promise);
|
|
@@ -127,29 +148,32 @@ export class TokenManager {
|
|
|
127
148
|
*/
|
|
128
149
|
refresh(ctx, refreshToken, options, headers) {
|
|
129
150
|
return __awaiter(this, void 0, void 0, function* () {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
151
|
+
const flightKey = this.createFlightKey(refreshToken);
|
|
152
|
+
return this.singleFlight.execute(flightKey, () => __awaiter(this, void 0, void 0, function* () {
|
|
153
|
+
logger.debug('[TokenKit] Starting token refresh', !!this.config.debug);
|
|
154
|
+
try {
|
|
155
|
+
const bundle = yield this.performRefresh(ctx, refreshToken, options, headers);
|
|
156
|
+
if (bundle) {
|
|
157
|
+
if (this.config.onRefresh) {
|
|
158
|
+
yield this.config.onRefresh(bundle, ctx);
|
|
159
|
+
}
|
|
136
160
|
}
|
|
161
|
+
else {
|
|
162
|
+
logger.debug('[TokenKit] Token refresh returned no bundle (invalid or expired)', !!this.config.debug);
|
|
163
|
+
if (this.config.onRefreshError) {
|
|
164
|
+
yield this.config.onRefreshError(new AuthError('Refresh token invalid or expired', 401), ctx);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return bundle;
|
|
137
168
|
}
|
|
138
|
-
|
|
139
|
-
logger.debug(
|
|
169
|
+
catch (error) {
|
|
170
|
+
logger.debug(`[TokenKit] Token refresh failed: ${error.message}`, !!this.config.debug);
|
|
140
171
|
if (this.config.onRefreshError) {
|
|
141
|
-
yield this.config.onRefreshError(
|
|
172
|
+
yield this.config.onRefreshError(error, ctx);
|
|
142
173
|
}
|
|
174
|
+
throw error;
|
|
143
175
|
}
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
catch (error) {
|
|
147
|
-
logger.debug(`[TokenKit] Token refresh failed: ${error.message}`, !!this.config.debug);
|
|
148
|
-
if (this.config.onRefreshError) {
|
|
149
|
-
yield this.config.onRefreshError(error, ctx);
|
|
150
|
-
}
|
|
151
|
-
throw error;
|
|
152
|
-
}
|
|
176
|
+
}));
|
|
153
177
|
});
|
|
154
178
|
}
|
|
155
179
|
/**
|
|
@@ -189,8 +213,8 @@ export class TokenManager {
|
|
|
189
213
|
clearTimeout(timeoutId);
|
|
190
214
|
}
|
|
191
215
|
if (!response.ok) {
|
|
192
|
-
// 401
|
|
193
|
-
if (response.status === 401 || response.status === 403) {
|
|
216
|
+
// 400 (Bad Request), 401 (Unauthorized) or 403 (Forbidden) = invalid refresh token
|
|
217
|
+
if (response.status === 400 || response.status === 401 || response.status === 403) {
|
|
194
218
|
clearTokens(ctx, this.config.cookies);
|
|
195
219
|
return null;
|
|
196
220
|
}
|
|
@@ -233,8 +257,7 @@ export class TokenManager {
|
|
|
233
257
|
const expired = isExpired(tokens.expiresAt, now, this.config.policy);
|
|
234
258
|
if (force || expired) {
|
|
235
259
|
logger.debug(`[TokenKit] Token ${force ? 'force refresh' : 'expired'}, refreshing...`, !!this.config.debug);
|
|
236
|
-
const
|
|
237
|
-
const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
|
|
260
|
+
const bundle = yield this.refresh(ctx, tokens.refreshToken, options, headers);
|
|
238
261
|
if (!bundle) {
|
|
239
262
|
logger.debug('[TokenKit] Refresh returned no bundle, session lost', !!this.config.debug);
|
|
240
263
|
return null;
|
|
@@ -251,9 +274,8 @@ export class TokenManager {
|
|
|
251
274
|
// Proactive refresh
|
|
252
275
|
if (shouldRefresh(tokens.expiresAt, now, tokens.lastRefreshAt, this.config.policy)) {
|
|
253
276
|
logger.debug('[TokenKit] Token near expiration, performing proactive refresh', !!this.config.debug);
|
|
254
|
-
const flightKey = this.createFlightKey(tokens.refreshToken);
|
|
255
277
|
try {
|
|
256
|
-
const bundle = yield this.
|
|
278
|
+
const bundle = yield this.refresh(ctx, tokens.refreshToken, options, headers);
|
|
257
279
|
if (bundle) {
|
|
258
280
|
logger.debug('[TokenKit] Proactive refresh successful', !!this.config.debug);
|
|
259
281
|
// Ensure tokens are stored in the current context (in case of shared flight)
|
|
@@ -52,6 +52,9 @@ export class IdleManager {
|
|
|
52
52
|
start() {
|
|
53
53
|
if (typeof window === 'undefined')
|
|
54
54
|
return;
|
|
55
|
+
if (this.isExcluded()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
55
58
|
this.updateExpiredTimeLocal();
|
|
56
59
|
this.setupEventListeners();
|
|
57
60
|
this.loop();
|
|
@@ -129,6 +132,10 @@ export class IdleManager {
|
|
|
129
132
|
triggerIdle() {
|
|
130
133
|
if (this.isIdle)
|
|
131
134
|
return;
|
|
135
|
+
if (this.isExcluded()) {
|
|
136
|
+
this.updateExpiredTimeLocal();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
132
139
|
this.isIdle = true;
|
|
133
140
|
if (typeof window !== 'undefined') {
|
|
134
141
|
window.dispatchEvent(new CustomEvent('tk:idle', { detail: this.config }));
|
|
@@ -136,6 +143,15 @@ export class IdleManager {
|
|
|
136
143
|
this.cleanup();
|
|
137
144
|
this.onIdle();
|
|
138
145
|
}
|
|
146
|
+
isExcluded() {
|
|
147
|
+
if (this.config.excludePaths && this.config.excludePaths.length > 0) {
|
|
148
|
+
if (typeof window !== 'undefined') {
|
|
149
|
+
const currentPath = window.location.pathname;
|
|
150
|
+
return this.config.excludePaths.some(path => currentPath.startsWith(path));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
139
155
|
cleanup() {
|
|
140
156
|
if (this.rafId) {
|
|
141
157
|
cancelAnimationFrame(this.rafId);
|
package/dist/index.cjs
CHANGED
|
@@ -533,18 +533,39 @@ const logger = {
|
|
|
533
533
|
class SingleFlight {
|
|
534
534
|
constructor() {
|
|
535
535
|
this.inFlight = new Map();
|
|
536
|
+
this.recent = new Map();
|
|
537
|
+
this.GRACE_PERIOD = 5000; // 5 seconds grace period for race conditions
|
|
536
538
|
}
|
|
537
539
|
execute(key, fn) {
|
|
538
540
|
return __awaiter(this, void 0, void 0, function* () {
|
|
541
|
+
// 1. Check in-flight
|
|
539
542
|
const existing = this.inFlight.get(key);
|
|
540
543
|
if (existing)
|
|
541
544
|
return existing;
|
|
545
|
+
// 2. Check recent (grace period)
|
|
546
|
+
const cached = this.recent.get(key);
|
|
547
|
+
if (cached && (Date.now() - cached.time < this.GRACE_PERIOD)) {
|
|
548
|
+
return cached.bundle;
|
|
549
|
+
}
|
|
550
|
+
// 3. Execute new flight
|
|
542
551
|
const promise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
543
552
|
try {
|
|
544
|
-
|
|
553
|
+
const bundle = yield fn();
|
|
554
|
+
// Store in recent on success
|
|
555
|
+
if (bundle) {
|
|
556
|
+
this.recent.set(key, { bundle, time: Date.now() });
|
|
557
|
+
}
|
|
558
|
+
return bundle;
|
|
545
559
|
}
|
|
546
560
|
finally {
|
|
547
561
|
this.inFlight.delete(key);
|
|
562
|
+
// Cleanup old entries
|
|
563
|
+
const now = Date.now();
|
|
564
|
+
for (const [k, v] of this.recent.entries()) {
|
|
565
|
+
if (now - v.time > this.GRACE_PERIOD) {
|
|
566
|
+
this.recent.delete(k);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
548
569
|
}
|
|
549
570
|
}))();
|
|
550
571
|
this.inFlight.set(key, promise);
|
|
@@ -640,29 +661,32 @@ class TokenManager {
|
|
|
640
661
|
*/
|
|
641
662
|
refresh(ctx, refreshToken, options, headers) {
|
|
642
663
|
return __awaiter(this, void 0, void 0, function* () {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
664
|
+
const flightKey = this.createFlightKey(refreshToken);
|
|
665
|
+
return this.singleFlight.execute(flightKey, () => __awaiter(this, void 0, void 0, function* () {
|
|
666
|
+
logger.debug('[TokenKit] Starting token refresh', !!this.config.debug);
|
|
667
|
+
try {
|
|
668
|
+
const bundle = yield this.performRefresh(ctx, refreshToken, options, headers);
|
|
669
|
+
if (bundle) {
|
|
670
|
+
if (this.config.onRefresh) {
|
|
671
|
+
yield this.config.onRefresh(bundle, ctx);
|
|
672
|
+
}
|
|
649
673
|
}
|
|
674
|
+
else {
|
|
675
|
+
logger.debug('[TokenKit] Token refresh returned no bundle (invalid or expired)', !!this.config.debug);
|
|
676
|
+
if (this.config.onRefreshError) {
|
|
677
|
+
yield this.config.onRefreshError(new AuthError('Refresh token invalid or expired', 401), ctx);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return bundle;
|
|
650
681
|
}
|
|
651
|
-
|
|
652
|
-
logger.debug(
|
|
682
|
+
catch (error) {
|
|
683
|
+
logger.debug(`[TokenKit] Token refresh failed: ${error.message}`, !!this.config.debug);
|
|
653
684
|
if (this.config.onRefreshError) {
|
|
654
|
-
yield this.config.onRefreshError(
|
|
685
|
+
yield this.config.onRefreshError(error, ctx);
|
|
655
686
|
}
|
|
687
|
+
throw error;
|
|
656
688
|
}
|
|
657
|
-
|
|
658
|
-
}
|
|
659
|
-
catch (error) {
|
|
660
|
-
logger.debug(`[TokenKit] Token refresh failed: ${error.message}`, !!this.config.debug);
|
|
661
|
-
if (this.config.onRefreshError) {
|
|
662
|
-
yield this.config.onRefreshError(error, ctx);
|
|
663
|
-
}
|
|
664
|
-
throw error;
|
|
665
|
-
}
|
|
689
|
+
}));
|
|
666
690
|
});
|
|
667
691
|
}
|
|
668
692
|
/**
|
|
@@ -702,8 +726,8 @@ class TokenManager {
|
|
|
702
726
|
clearTimeout(timeoutId);
|
|
703
727
|
}
|
|
704
728
|
if (!response.ok) {
|
|
705
|
-
// 401
|
|
706
|
-
if (response.status === 401 || response.status === 403) {
|
|
729
|
+
// 400 (Bad Request), 401 (Unauthorized) or 403 (Forbidden) = invalid refresh token
|
|
730
|
+
if (response.status === 400 || response.status === 401 || response.status === 403) {
|
|
707
731
|
clearTokens(ctx, this.config.cookies);
|
|
708
732
|
return null;
|
|
709
733
|
}
|
|
@@ -746,8 +770,7 @@ class TokenManager {
|
|
|
746
770
|
const expired = isExpired(tokens.expiresAt, now, this.config.policy);
|
|
747
771
|
if (force || expired) {
|
|
748
772
|
logger.debug(`[TokenKit] Token ${force ? 'force refresh' : 'expired'}, refreshing...`, !!this.config.debug);
|
|
749
|
-
const
|
|
750
|
-
const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
|
|
773
|
+
const bundle = yield this.refresh(ctx, tokens.refreshToken, options, headers);
|
|
751
774
|
if (!bundle) {
|
|
752
775
|
logger.debug('[TokenKit] Refresh returned no bundle, session lost', !!this.config.debug);
|
|
753
776
|
return null;
|
|
@@ -764,9 +787,8 @@ class TokenManager {
|
|
|
764
787
|
// Proactive refresh
|
|
765
788
|
if (shouldRefresh(tokens.expiresAt, now, tokens.lastRefreshAt, this.config.policy)) {
|
|
766
789
|
logger.debug('[TokenKit] Token near expiration, performing proactive refresh', !!this.config.debug);
|
|
767
|
-
const flightKey = this.createFlightKey(tokens.refreshToken);
|
|
768
790
|
try {
|
|
769
|
-
const bundle = yield this.
|
|
791
|
+
const bundle = yield this.refresh(ctx, tokens.refreshToken, options, headers);
|
|
770
792
|
if (bundle) {
|
|
771
793
|
logger.debug('[TokenKit] Proactive refresh successful', !!this.config.debug);
|
|
772
794
|
// Ensure tokens are stored in the current context (in case of shared flight)
|