astro-tokenkit 1.0.19 → 1.0.21
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 +14 -0
- package/dist/auth/manager.js +44 -16
- package/dist/client/client.js +19 -7
- package/dist/index.cjs +69 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.js +69 -30
- package/dist/index.js.map +1 -1
- package/dist/integration.js +1 -1
- package/dist/middleware.cjs +50 -22
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.js +50 -22
- package/dist/middleware.js.map +1 -1
- package/dist/types.d.ts +14 -0
- package/dist/utils/logger.d.ts +2 -2
- package/dist/utils/logger.js +4 -4
- package/package.json +4 -2
package/dist/index.d.ts
CHANGED
|
@@ -106,6 +106,14 @@ interface LoginOptions extends AuthOptions {
|
|
|
106
106
|
/** Callback after failed login */
|
|
107
107
|
onError?: OnErrorCallback;
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* OnRefresh callback
|
|
111
|
+
*/
|
|
112
|
+
type OnRefreshCallback = (bundle: TokenBundle, ctx: TokenKitContext) => void | Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* OnRefreshError callback
|
|
115
|
+
*/
|
|
116
|
+
type OnRefreshErrorCallback = (error: AuthError, ctx: TokenKitContext) => void | Promise<void>;
|
|
109
117
|
/**
|
|
110
118
|
* Auth configuration
|
|
111
119
|
*/
|
|
@@ -144,6 +152,12 @@ interface AuthConfig {
|
|
|
144
152
|
fetch?: typeof fetch;
|
|
145
153
|
/** Dangerously ignore certificate errors (bypass SSL validation) */
|
|
146
154
|
dangerouslyIgnoreCertificateErrors?: boolean;
|
|
155
|
+
/** Enable debug logging for auth operations */
|
|
156
|
+
debug?: boolean;
|
|
157
|
+
/** Callback after successful refresh */
|
|
158
|
+
onRefresh?: OnRefreshCallback;
|
|
159
|
+
/** Callback after failed refresh */
|
|
160
|
+
onRefreshError?: OnRefreshErrorCallback;
|
|
147
161
|
}
|
|
148
162
|
/**
|
|
149
163
|
* Refresh policy
|
package/dist/index.js
CHANGED
|
@@ -506,13 +506,13 @@ catch (e) {
|
|
|
506
506
|
* Logger utility that respects the debug flag in the configuration
|
|
507
507
|
*/
|
|
508
508
|
const logger = {
|
|
509
|
-
debug: (message, ...args) => {
|
|
510
|
-
if (getConfig().debug) {
|
|
509
|
+
debug: (message, force, ...args) => {
|
|
510
|
+
if (force || getConfig().debug) {
|
|
511
511
|
console.debug(message, ...args);
|
|
512
512
|
}
|
|
513
513
|
},
|
|
514
|
-
info: (message, ...args) => {
|
|
515
|
-
if (getConfig().debug) {
|
|
514
|
+
info: (message, force, ...args) => {
|
|
515
|
+
if (force || getConfig().debug) {
|
|
516
516
|
console.log(message, ...args);
|
|
517
517
|
}
|
|
518
518
|
},
|
|
@@ -638,11 +638,27 @@ class TokenManager {
|
|
|
638
638
|
*/
|
|
639
639
|
refresh(ctx, refreshToken, options, headers) {
|
|
640
640
|
return __awaiter(this, void 0, void 0, function* () {
|
|
641
|
+
logger.debug('[TokenKit] Starting token refresh', !!this.config.debug);
|
|
641
642
|
try {
|
|
642
|
-
|
|
643
|
+
const bundle = yield this.performRefresh(ctx, refreshToken, options, headers);
|
|
644
|
+
if (bundle) {
|
|
645
|
+
if (this.config.onRefresh) {
|
|
646
|
+
yield this.config.onRefresh(bundle, ctx);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
logger.debug('[TokenKit] Token refresh returned no bundle (invalid or expired)', !!this.config.debug);
|
|
651
|
+
if (this.config.onRefreshError) {
|
|
652
|
+
yield this.config.onRefreshError(new AuthError('Refresh token invalid or expired', 401), ctx);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return bundle;
|
|
643
656
|
}
|
|
644
657
|
catch (error) {
|
|
645
|
-
|
|
658
|
+
logger.debug(`[TokenKit] Token refresh failed: ${error.message}`, !!this.config.debug);
|
|
659
|
+
if (this.config.onRefreshError) {
|
|
660
|
+
yield this.config.onRefreshError(error, ctx);
|
|
661
|
+
}
|
|
646
662
|
throw error;
|
|
647
663
|
}
|
|
648
664
|
});
|
|
@@ -721,14 +737,19 @@ class TokenManager {
|
|
|
721
737
|
const tokens = retrieveTokens(ctx, this.config.cookies);
|
|
722
738
|
// No tokens
|
|
723
739
|
if (!tokens.accessToken || !tokens.refreshToken || !tokens.expiresAt) {
|
|
740
|
+
logger.debug('[TokenKit] No valid session found, refresh impossible', !!this.config.debug);
|
|
724
741
|
return null;
|
|
725
742
|
}
|
|
726
743
|
// Token expired or force refresh
|
|
727
|
-
|
|
744
|
+
const expired = isExpired(tokens.expiresAt, now, this.config.policy);
|
|
745
|
+
if (force || expired) {
|
|
746
|
+
logger.debug(`[TokenKit] Token ${force ? 'force refresh' : 'expired'}, refreshing...`, !!this.config.debug);
|
|
728
747
|
const flightKey = this.createFlightKey(tokens.refreshToken);
|
|
729
748
|
const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
|
|
730
|
-
if (!bundle)
|
|
749
|
+
if (!bundle) {
|
|
750
|
+
logger.debug('[TokenKit] Refresh returned no bundle, session lost', !!this.config.debug);
|
|
731
751
|
return null;
|
|
752
|
+
}
|
|
732
753
|
// Ensure tokens are stored in the current context (in case of shared flight)
|
|
733
754
|
storeTokens(ctx, bundle, this.config.cookies);
|
|
734
755
|
return {
|
|
@@ -740,19 +761,26 @@ class TokenManager {
|
|
|
740
761
|
}
|
|
741
762
|
// Proactive refresh
|
|
742
763
|
if (shouldRefresh(tokens.expiresAt, now, tokens.lastRefreshAt, this.config.policy)) {
|
|
764
|
+
logger.debug('[TokenKit] Token near expiration, performing proactive refresh', !!this.config.debug);
|
|
743
765
|
const flightKey = this.createFlightKey(tokens.refreshToken);
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
766
|
+
try {
|
|
767
|
+
const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
|
|
768
|
+
if (bundle) {
|
|
769
|
+
logger.debug('[TokenKit] Proactive refresh successful', !!this.config.debug);
|
|
770
|
+
// Ensure tokens are stored in the current context (in case of shared flight)
|
|
771
|
+
storeTokens(ctx, bundle, this.config.cookies);
|
|
772
|
+
return {
|
|
773
|
+
accessToken: bundle.accessToken,
|
|
774
|
+
expiresAt: bundle.accessExpiresAt,
|
|
775
|
+
tokenType: bundle.tokenType,
|
|
776
|
+
payload: (_d = (_c = bundle.sessionPayload) !== null && _c !== void 0 ? _c : parseJWTPayload(bundle.accessToken)) !== null && _d !== void 0 ? _d : undefined,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
754
779
|
}
|
|
755
|
-
|
|
780
|
+
catch (error) {
|
|
781
|
+
logger.debug(`[TokenKit] Proactive refresh failed: ${error.message}. Continuing with current token.`, !!this.config.debug);
|
|
782
|
+
}
|
|
783
|
+
// Refresh failed or returned no bundle, check if tokens still exist
|
|
756
784
|
const currentTokens = retrieveTokens(ctx, this.config.cookies);
|
|
757
785
|
if (!currentTokens.accessToken) {
|
|
758
786
|
return null;
|
|
@@ -794,7 +822,7 @@ class TokenManager {
|
|
|
794
822
|
}
|
|
795
823
|
catch (error) {
|
|
796
824
|
// Ignore logout endpoint errors
|
|
797
|
-
logger.debug('[TokenKit] Logout endpoint failed:', error);
|
|
825
|
+
logger.debug('[TokenKit] Logout endpoint failed:', !!this.config.debug, error);
|
|
798
826
|
}
|
|
799
827
|
finally {
|
|
800
828
|
clearTimeout(timeoutId);
|
|
@@ -939,7 +967,7 @@ function createMiddleware() {
|
|
|
939
967
|
else if (config.context) {
|
|
940
968
|
contextStrategy = 'custom (external AsyncLocalStorage)';
|
|
941
969
|
}
|
|
942
|
-
logger.debug(`[TokenKit] Middleware initialized (auth: ${authStatus}, context: ${contextStrategy})
|
|
970
|
+
logger.debug(`[TokenKit] Middleware initialized (auth: ${authStatus}, context: ${contextStrategy})`, !!config.debug);
|
|
943
971
|
globalStorage[LOGGED_KEY] = true;
|
|
944
972
|
}
|
|
945
973
|
const runLogic = () => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -951,7 +979,7 @@ function createMiddleware() {
|
|
|
951
979
|
}
|
|
952
980
|
catch (error) {
|
|
953
981
|
// Log only the message to avoid leaking sensitive data in the error object
|
|
954
|
-
logger.debug('[TokenKit] Automatic token rotation failed:', error.message || error);
|
|
982
|
+
logger.debug('[TokenKit] Automatic token rotation failed:', !!config.debug, error.message || error);
|
|
955
983
|
}
|
|
956
984
|
}
|
|
957
985
|
return next();
|
|
@@ -996,7 +1024,7 @@ class APIClient {
|
|
|
996
1024
|
* Get token manager
|
|
997
1025
|
*/
|
|
998
1026
|
get tokenManager() {
|
|
999
|
-
var _a, _b;
|
|
1027
|
+
var _a, _b, _c;
|
|
1000
1028
|
const config = this.config;
|
|
1001
1029
|
if (!config.auth)
|
|
1002
1030
|
return undefined;
|
|
@@ -1012,8 +1040,8 @@ class APIClient {
|
|
|
1012
1040
|
if (!this._localTokenManager ||
|
|
1013
1041
|
this._lastUsedAuth !== config.auth ||
|
|
1014
1042
|
this._lastUsedBaseURL !== config.baseURL) {
|
|
1015
|
-
// Merge client-level fetch and
|
|
1016
|
-
const authConfig = Object.assign(Object.assign({}, config.auth), { fetch: (_a = config.auth.fetch) !== null && _a !== void 0 ? _a : config.fetch, dangerouslyIgnoreCertificateErrors: (_b = config.auth.dangerouslyIgnoreCertificateErrors) !== null && _b !== void 0 ? _b : config.dangerouslyIgnoreCertificateErrors });
|
|
1043
|
+
// Merge client-level fetch, SSL and debug settings into auth config
|
|
1044
|
+
const authConfig = Object.assign(Object.assign({}, config.auth), { fetch: (_a = config.auth.fetch) !== null && _a !== void 0 ? _a : config.fetch, dangerouslyIgnoreCertificateErrors: (_b = config.auth.dangerouslyIgnoreCertificateErrors) !== null && _b !== void 0 ? _b : config.dangerouslyIgnoreCertificateErrors, debug: (_c = config.auth.debug) !== null && _c !== void 0 ? _c : config.debug });
|
|
1017
1045
|
this._localTokenManager = new TokenManager(authConfig, config.baseURL);
|
|
1018
1046
|
this._lastUsedAuth = config.auth;
|
|
1019
1047
|
this._lastUsedBaseURL = config.baseURL;
|
|
@@ -1101,8 +1129,11 @@ class APIClient {
|
|
|
1101
1129
|
executeRequest(config, ctx, attempt) {
|
|
1102
1130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1103
1131
|
var _a, _b, _c, _d, _e;
|
|
1132
|
+
const method = config.method.toUpperCase();
|
|
1133
|
+
const debug = this.config.debug;
|
|
1104
1134
|
// Ensure valid session (if auth is enabled)
|
|
1105
1135
|
if (this.tokenManager && !config.skipAuth) {
|
|
1136
|
+
logger.debug(`[TokenKit] Ensuring valid session for ${method} ${config.url}`, !!debug);
|
|
1106
1137
|
yield this.tokenManager.ensure(ctx, config.auth, config.headers);
|
|
1107
1138
|
}
|
|
1108
1139
|
// Build full URL
|
|
@@ -1111,13 +1142,18 @@ class APIClient {
|
|
|
1111
1142
|
const headers = this.buildHeaders(config, ctx, fullURL);
|
|
1112
1143
|
// Build request init
|
|
1113
1144
|
const init = {
|
|
1114
|
-
method
|
|
1145
|
+
method,
|
|
1115
1146
|
headers,
|
|
1116
1147
|
signal: config.signal,
|
|
1117
1148
|
};
|
|
1118
|
-
// Add body for
|
|
1119
|
-
|
|
1149
|
+
// Add body for appropriate methods
|
|
1150
|
+
const methodsWithNoBody = ['GET', 'HEAD', 'DELETE'];
|
|
1151
|
+
if (config.data && !methodsWithNoBody.includes(method)) {
|
|
1120
1152
|
init.body = JSON.stringify(config.data);
|
|
1153
|
+
// Add Content-Type if not already present
|
|
1154
|
+
if (!headers['Content-Type'] && !headers['content-type']) {
|
|
1155
|
+
headers['Content-Type'] = 'application/json';
|
|
1156
|
+
}
|
|
1121
1157
|
}
|
|
1122
1158
|
// Apply request interceptors
|
|
1123
1159
|
let requestConfig = Object.assign({}, config);
|
|
@@ -1135,12 +1171,15 @@ class APIClient {
|
|
|
1135
1171
|
clearTimeout(timeoutId);
|
|
1136
1172
|
// Handle 401 (try refresh and retry once)
|
|
1137
1173
|
if (response.status === 401 && this.tokenManager && !config.skipAuth && attempt === 1) {
|
|
1174
|
+
logger.debug('[TokenKit] Received 401, attempting force refresh and retry...', !!debug);
|
|
1138
1175
|
// Clear and try fresh session (force refresh)
|
|
1139
1176
|
const session = yield this.tokenManager.ensure(ctx, config.auth, config.headers, true);
|
|
1140
1177
|
if (session) {
|
|
1178
|
+
logger.debug('[TokenKit] Force refresh successful, retrying request...', !!debug);
|
|
1141
1179
|
// Retry with new token
|
|
1142
1180
|
return this.executeRequest(config, ctx, attempt + 1);
|
|
1143
1181
|
}
|
|
1182
|
+
logger.debug('[TokenKit] Force refresh failed or returned no session', !!debug);
|
|
1144
1183
|
}
|
|
1145
1184
|
// Parse response
|
|
1146
1185
|
const apiResponse = yield this.parseResponse(response, fullURL);
|
|
@@ -1229,7 +1268,7 @@ class APIClient {
|
|
|
1229
1268
|
*/
|
|
1230
1269
|
buildHeaders(config, ctx, targetURL) {
|
|
1231
1270
|
var _a, _b;
|
|
1232
|
-
const headers = Object.assign(Object.assign({
|
|
1271
|
+
const headers = Object.assign(Object.assign({}, this.config.headers), config.headers);
|
|
1233
1272
|
// Add auth token if available (only for safe URLs)
|
|
1234
1273
|
if (this.tokenManager && !config.skipAuth && this.isSafeURL(targetURL)) {
|
|
1235
1274
|
const session = this.tokenManager.getSession(ctx);
|
|
@@ -1378,7 +1417,7 @@ function tokenKit(config) {
|
|
|
1378
1417
|
}
|
|
1379
1418
|
// Always inject the client-side script for idle monitoring
|
|
1380
1419
|
injectScript('page', `import 'astro-tokenkit/client-init';`);
|
|
1381
|
-
logger.debug('[TokenKit] Integration initialized');
|
|
1420
|
+
logger.debug('[TokenKit] Integration initialized', !!config.debug);
|
|
1382
1421
|
},
|
|
1383
1422
|
},
|
|
1384
1423
|
};
|