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/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
- return yield this.performRefresh(ctx, refreshToken, options, headers);
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
- clearTokens(ctx, this.config.cookies);
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
- if (force || isExpired(tokens.expiresAt, now, this.config.policy)) {
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
- const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
745
- if (bundle) {
746
- // Ensure tokens are stored in the current context (in case of shared flight)
747
- storeTokens(ctx, bundle, this.config.cookies);
748
- return {
749
- accessToken: bundle.accessToken,
750
- expiresAt: bundle.accessExpiresAt,
751
- tokenType: bundle.tokenType,
752
- payload: (_d = (_c = bundle.sessionPayload) !== null && _c !== void 0 ? _c : parseJWTPayload(bundle.accessToken)) !== null && _d !== void 0 ? _d : undefined,
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
- // Refresh failed, check if tokens still exist
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 SSL settings into auth config
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: config.method,
1145
+ method,
1115
1146
  headers,
1116
1147
  signal: config.signal,
1117
1148
  };
1118
- // Add body for non-GET requests
1119
- if (config.data && config.method !== 'GET') {
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({ 'Content-Type': 'application/json' }, this.config.headers), config.headers);
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
  };