astro-tokenkit 1.0.16 → 1.0.18

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.cjs CHANGED
@@ -39,20 +39,23 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
39
39
  * API Error
40
40
  */
41
41
  class APIError extends Error {
42
- constructor(message, status, response, request) {
42
+ constructor(message, status, response, request, cause) {
43
43
  super(message);
44
44
  this.status = status;
45
45
  this.response = response;
46
46
  this.request = request;
47
+ this.cause = cause;
47
48
  this.name = 'APIError';
49
+ if (cause && !this.cause)
50
+ this.cause = cause;
48
51
  }
49
52
  }
50
53
  /**
51
54
  * Authentication Error
52
55
  */
53
56
  class AuthError extends APIError {
54
- constructor(message, status, response, request) {
55
- super(message, status, response, request);
57
+ constructor(message, status, response, request, cause) {
58
+ super(message, status, response, request, cause);
56
59
  this.name = 'AuthError';
57
60
  }
58
61
  }
@@ -60,8 +63,8 @@ class AuthError extends APIError {
60
63
  * Network Error
61
64
  */
62
65
  class NetworkError extends APIError {
63
- constructor(message, request) {
64
- super(message, undefined, undefined, request);
66
+ constructor(message, request, cause) {
67
+ super(message, undefined, undefined, request, cause);
65
68
  this.name = 'NetworkError';
66
69
  }
67
70
  }
@@ -69,8 +72,8 @@ class NetworkError extends APIError {
69
72
  * Timeout Error
70
73
  */
71
74
  class TimeoutError extends APIError {
72
- constructor(message, request) {
73
- super(message, undefined, undefined, request);
75
+ constructor(message, request, cause) {
76
+ super(message, undefined, undefined, request, cause);
74
77
  this.name = 'TimeoutError';
75
78
  }
76
79
  }
@@ -396,6 +399,122 @@ function isExpired(expiresAt, now, policy = {}) {
396
399
  return now + clockSkew > expiresAt;
397
400
  }
398
401
 
402
+ // packages/astro-tokenkit/src/utils/fetch.ts
403
+ /**
404
+ * Perform a fetch request with optional certificate validation bypass
405
+ */
406
+ function safeFetch(url, init, config) {
407
+ return __awaiter(this, void 0, void 0, function* () {
408
+ const fetchFn = config.fetch || fetch;
409
+ const fetchOptions = Object.assign({}, init);
410
+ if (config.dangerouslyIgnoreCertificateErrors && typeof process !== 'undefined') {
411
+ // In Node.js environment
412
+ try {
413
+ // Try to use undici Agent if available (it is built-in in Node 18+)
414
+ // However, we might need to import it if we want to create an Agent.
415
+ // Since we don't want to depend on undici in package.json, we use dynamic import.
416
+ // But wait, undici's Agent is what we need.
417
+ // As a fallback and most reliable way for self-signed certs in Node without extra deps:
418
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
419
+ // NOTE: This affects the whole process. We should ideally only do this if it's not already 0.
420
+ // But for a dev tool / specialized library, it's often what's needed.
421
+ }
422
+ catch (e) {
423
+ // Ignore
424
+ }
425
+ }
426
+ return fetchFn(url, fetchOptions);
427
+ });
428
+ }
429
+
430
+ // packages/astro-tokenkit/src/config.ts
431
+ const CONFIG_KEY = Symbol.for('astro-tokenkit.config');
432
+ const MANAGER_KEY = Symbol.for('astro-tokenkit.manager');
433
+ const globalStorage = globalThis;
434
+ // Initialize global storage if not present
435
+ if (!globalStorage[CONFIG_KEY]) {
436
+ globalStorage[CONFIG_KEY] = {
437
+ runWithContext: undefined,
438
+ getContextStore: undefined,
439
+ setContextStore: undefined,
440
+ baseURL: "",
441
+ debug: false,
442
+ };
443
+ }
444
+ /**
445
+ * Set configuration
446
+ */
447
+ function setConfig(userConfig) {
448
+ var _a, _b;
449
+ const currentConfig = globalStorage[CONFIG_KEY];
450
+ const finalConfig = Object.assign(Object.assign({}, currentConfig), userConfig);
451
+ // Validate that getter and setter are defined together
452
+ if ((finalConfig.getContextStore && !finalConfig.setContextStore) ||
453
+ (!finalConfig.getContextStore && finalConfig.setContextStore)) {
454
+ throw new Error("[TokenKit] getContextStore and setContextStore must be defined together.");
455
+ }
456
+ globalStorage[CONFIG_KEY] = finalConfig;
457
+ // Re-initialize global token manager if auth changed
458
+ if (finalConfig.auth) {
459
+ const authConfig = Object.assign(Object.assign({}, finalConfig.auth), { fetch: (_a = finalConfig.auth.fetch) !== null && _a !== void 0 ? _a : finalConfig.fetch, dangerouslyIgnoreCertificateErrors: (_b = finalConfig.auth.dangerouslyIgnoreCertificateErrors) !== null && _b !== void 0 ? _b : finalConfig.dangerouslyIgnoreCertificateErrors });
460
+ globalStorage[MANAGER_KEY] = new TokenManager(authConfig, finalConfig.baseURL);
461
+ }
462
+ else {
463
+ globalStorage[MANAGER_KEY] = undefined;
464
+ }
465
+ }
466
+ /**
467
+ * Get current configuration
468
+ */
469
+ function getConfig() {
470
+ return globalStorage[CONFIG_KEY];
471
+ }
472
+ /**
473
+ * Get global token manager
474
+ */
475
+ function getTokenManager() {
476
+ return globalStorage[MANAGER_KEY];
477
+ }
478
+ /**
479
+ * Set global token manager (mainly for testing)
480
+ */
481
+ function setTokenManager(manager) {
482
+ globalStorage[MANAGER_KEY] = manager;
483
+ }
484
+ // Handle injected configuration from Astro integration
485
+ try {
486
+ // @ts-ignore
487
+ const injectedConfig = typeof __TOKENKIT_CONFIG__ !== 'undefined' ? __TOKENKIT_CONFIG__ : undefined;
488
+ if (injectedConfig) {
489
+ setConfig(injectedConfig);
490
+ }
491
+ }
492
+ catch (e) {
493
+ // Ignore errors in environments where __TOKENKIT_CONFIG__ might be restricted
494
+ }
495
+
496
+ /**
497
+ * Logger utility that respects the debug flag in the configuration
498
+ */
499
+ const logger = {
500
+ debug: (message, ...args) => {
501
+ if (getConfig().debug) {
502
+ console.debug(message, ...args);
503
+ }
504
+ },
505
+ info: (message, ...args) => {
506
+ if (getConfig().debug) {
507
+ console.log(message, ...args);
508
+ }
509
+ },
510
+ warn: (message, ...args) => {
511
+ console.warn(message, ...args);
512
+ },
513
+ error: (message, ...args) => {
514
+ console.error(message, ...args);
515
+ }
516
+ };
517
+
399
518
  // packages/astro-tokenkit/src/auth/manager.ts
400
519
  /**
401
520
  * Single-flight refresh manager
@@ -452,14 +571,14 @@ class TokenManager {
452
571
  }
453
572
  let response;
454
573
  try {
455
- response = yield fetch(url, {
574
+ response = yield safeFetch(url, {
456
575
  method: 'POST',
457
576
  headers,
458
577
  body: requestBody,
459
- });
578
+ }, this.config);
460
579
  }
461
580
  catch (error) {
462
- const authError = new AuthError(`Login request failed: ${error.message}`);
581
+ const authError = new AuthError(`Login request failed: ${error.message}`, undefined, undefined, undefined, error);
463
582
  if (options === null || options === void 0 ? void 0 : options.onError)
464
583
  yield options.onError(authError, ctx);
465
584
  throw authError;
@@ -533,14 +652,14 @@ class TokenManager {
533
652
  }
534
653
  let response;
535
654
  try {
536
- response = yield fetch(url, {
655
+ response = yield safeFetch(url, {
537
656
  method: 'POST',
538
657
  headers,
539
658
  body: requestBody,
540
- });
659
+ }, this.config);
541
660
  }
542
661
  catch (error) {
543
- throw new AuthError(`Refresh request failed: ${error.message}`);
662
+ throw new AuthError(`Refresh request failed: ${error.message}`, undefined, undefined, undefined, error);
544
663
  }
545
664
  if (!response.ok) {
546
665
  // 401/403 = invalid refresh token
@@ -638,11 +757,11 @@ class TokenManager {
638
757
  const injectFn = (_a = this.config.injectToken) !== null && _a !== void 0 ? _a : ((token, type) => `${type !== null && type !== void 0 ? type : 'Bearer'} ${token}`);
639
758
  headers['Authorization'] = injectFn(session.accessToken, session.tokenType);
640
759
  }
641
- yield fetch(url, { method: 'POST', headers });
760
+ yield safeFetch(url, { method: 'POST', headers }, this.config);
642
761
  }
643
762
  catch (error) {
644
763
  // Ignore logout endpoint errors
645
- console.warn('[TokenKit] Logout endpoint failed:', error);
764
+ logger.debug('[TokenKit] Logout endpoint failed:', error);
646
765
  }
647
766
  }
648
767
  clearTokens(ctx, this.config.cookies);
@@ -688,69 +807,6 @@ class TokenManager {
688
807
  }
689
808
  }
690
809
 
691
- // packages/astro-tokenkit/src/config.ts
692
- const CONFIG_KEY = Symbol.for('astro-tokenkit.config');
693
- const MANAGER_KEY = Symbol.for('astro-tokenkit.manager');
694
- const globalStorage = globalThis;
695
- // Initialize global storage if not present
696
- if (!globalStorage[CONFIG_KEY]) {
697
- globalStorage[CONFIG_KEY] = {
698
- runWithContext: undefined,
699
- getContextStore: undefined,
700
- setContextStore: undefined,
701
- baseURL: "",
702
- };
703
- }
704
- /**
705
- * Set configuration
706
- */
707
- function setConfig(userConfig) {
708
- const currentConfig = globalStorage[CONFIG_KEY];
709
- const finalConfig = Object.assign(Object.assign({}, currentConfig), userConfig);
710
- // Validate that getter and setter are defined together
711
- if ((finalConfig.getContextStore && !finalConfig.setContextStore) ||
712
- (!finalConfig.getContextStore && finalConfig.setContextStore)) {
713
- throw new Error("[TokenKit] getContextStore and setContextStore must be defined together.");
714
- }
715
- globalStorage[CONFIG_KEY] = finalConfig;
716
- // Re-initialize global token manager if auth changed
717
- if (finalConfig.auth) {
718
- globalStorage[MANAGER_KEY] = new TokenManager(finalConfig.auth, finalConfig.baseURL);
719
- }
720
- else {
721
- globalStorage[MANAGER_KEY] = undefined;
722
- }
723
- }
724
- /**
725
- * Get current configuration
726
- */
727
- function getConfig() {
728
- return globalStorage[CONFIG_KEY];
729
- }
730
- /**
731
- * Get global token manager
732
- */
733
- function getTokenManager() {
734
- return globalStorage[MANAGER_KEY];
735
- }
736
- /**
737
- * Set global token manager (mainly for testing)
738
- */
739
- function setTokenManager(manager) {
740
- globalStorage[MANAGER_KEY] = manager;
741
- }
742
- // Handle injected configuration from Astro integration
743
- try {
744
- // @ts-ignore
745
- const injectedConfig = typeof __TOKENKIT_CONFIG__ !== 'undefined' ? __TOKENKIT_CONFIG__ : undefined;
746
- if (injectedConfig) {
747
- setConfig(injectedConfig);
748
- }
749
- }
750
- catch (e) {
751
- // Ignore errors in environments where __TOKENKIT_CONFIG__ might be restricted
752
- }
753
-
754
810
  // packages/astro-tokenkit/src/client/context.ts
755
811
  /**
756
812
  * Async local storage for Astro context
@@ -847,7 +903,7 @@ function createMiddleware() {
847
903
  else if (config.context) {
848
904
  contextStrategy = 'custom (external AsyncLocalStorage)';
849
905
  }
850
- console.log(`[TokenKit] Middleware initialized (auth: ${authStatus}, context: ${contextStrategy})`);
906
+ logger.debug(`[TokenKit] Middleware initialized (auth: ${authStatus}, context: ${contextStrategy})`);
851
907
  globalStorage[LOGGED_KEY] = true;
852
908
  }
853
909
  const runLogic = () => __awaiter(this, void 0, void 0, function* () {
@@ -859,7 +915,7 @@ function createMiddleware() {
859
915
  }
860
916
  catch (error) {
861
917
  // Log only the message to avoid leaking sensitive data in the error object
862
- console.error('[TokenKit] Automatic token rotation failed:', error.message || error);
918
+ logger.debug('[TokenKit] Automatic token rotation failed:', error.message || error);
863
919
  }
864
920
  }
865
921
  return next();
@@ -904,6 +960,7 @@ class APIClient {
904
960
  * Get token manager
905
961
  */
906
962
  get tokenManager() {
963
+ var _a, _b;
907
964
  const config = this.config;
908
965
  if (!config.auth)
909
966
  return undefined;
@@ -919,7 +976,9 @@ class APIClient {
919
976
  if (!this._localTokenManager ||
920
977
  this._lastUsedAuth !== config.auth ||
921
978
  this._lastUsedBaseURL !== config.baseURL) {
922
- this._localTokenManager = new TokenManager(config.auth, config.baseURL);
979
+ // Merge client-level fetch and SSL settings into auth config
980
+ 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 });
981
+ this._localTokenManager = new TokenManager(authConfig, config.baseURL);
923
982
  this._lastUsedAuth = config.auth;
924
983
  this._lastUsedBaseURL = config.baseURL;
925
984
  }
@@ -1036,7 +1095,7 @@ class APIClient {
1036
1095
  const controller = new AbortController();
1037
1096
  const timeoutId = setTimeout(() => controller.abort(), timeout);
1038
1097
  try {
1039
- const response = yield fetch(fullURL, Object.assign(Object.assign({}, init), { signal: controller.signal }));
1098
+ const response = yield safeFetch(fullURL, Object.assign(Object.assign({}, init), { signal: controller.signal }), this.config);
1040
1099
  clearTimeout(timeoutId);
1041
1100
  // Handle 401 (try refresh and retry once)
1042
1101
  if (response.status === 401 && this.tokenManager && !config.skipAuth && attempt === 1) {
@@ -1069,12 +1128,12 @@ class APIClient {
1069
1128
  }
1070
1129
  // Transform errors
1071
1130
  if (error instanceof Error && error.name === 'AbortError') {
1072
- throw new TimeoutError(`Request timeout after ${timeout}ms`, requestConfig);
1131
+ throw new TimeoutError(`Request timeout after ${timeout}ms`, requestConfig, error);
1073
1132
  }
1074
1133
  if (error instanceof APIError) {
1075
1134
  throw error;
1076
1135
  }
1077
- throw new NetworkError(error.message, requestConfig);
1136
+ throw new NetworkError(error.message, requestConfig, error);
1078
1137
  }
1079
1138
  });
1080
1139
  }
@@ -1168,7 +1227,7 @@ class APIClient {
1168
1227
  throw new Error('Auth is not configured for this client');
1169
1228
  }
1170
1229
  const context = getContextStore();
1171
- return this.tokenManager.login(context, credentials, options);
1230
+ return yield this.tokenManager.login(context, credentials, options);
1172
1231
  });
1173
1232
  }
1174
1233
  /**
@@ -1225,6 +1284,13 @@ function createClient(config) {
1225
1284
  * Astro integration for TokenKit
1226
1285
  *
1227
1286
  * This integration facilitates the setup of TokenKit in an Astro project.
1287
+ * It performs the following:
1288
+ * - Sets the global configuration for the API client.
1289
+ * - Injects the configuration into the client-side via Vite's `define`.
1290
+ * - Automatically registers the TokenKit middleware (unless `autoMiddleware` is set to `false`).
1291
+ * - Injects a client-side script (`astro-tokenkit/client-init`) to handle idle session monitoring and automatic logout.
1292
+ *
1293
+ * @param config - TokenKit configuration options.
1228
1294
  *
1229
1295
  * @example
1230
1296
  * ```ts
@@ -1238,6 +1304,10 @@ function createClient(config) {
1238
1304
  * auth: {
1239
1305
  * login: '/auth/login',
1240
1306
  * refresh: '/auth/refresh',
1307
+ * },
1308
+ * idle: {
1309
+ * timeout: 3600, // 1 hour
1310
+ * alert: { title: 'Session Expired' }
1241
1311
  * }
1242
1312
  * })
1243
1313
  * ]
@@ -1255,7 +1325,7 @@ function tokenKit(config) {
1255
1325
  return {
1256
1326
  name: 'astro-tokenkit',
1257
1327
  hooks: {
1258
- 'astro:config:setup': ({ updateConfig, addMiddleware }) => {
1328
+ 'astro:config:setup': ({ updateConfig, addMiddleware, injectScript }) => {
1259
1329
  updateConfig({
1260
1330
  vite: {
1261
1331
  define: {
@@ -1270,13 +1340,26 @@ function tokenKit(config) {
1270
1340
  order: 'pre'
1271
1341
  });
1272
1342
  }
1273
- console.log('[TokenKit] Integration initialized');
1343
+ // Always inject the client-side script for idle monitoring
1344
+ injectScript('page', `import 'astro-tokenkit/client-init';`);
1345
+ logger.debug('[TokenKit] Integration initialized');
1274
1346
  },
1275
1347
  },
1276
1348
  };
1277
1349
  }
1278
1350
  /**
1279
- * Helper to define middleware in a separate file if needed
1351
+ * Helper to create the TokenKit middleware.
1352
+ *
1353
+ * Use this if you have `autoMiddleware: false` in your integration configuration
1354
+ * and want to manually register the middleware in your `src/middleware.ts` file.
1355
+ *
1356
+ * @example
1357
+ * ```ts
1358
+ * // src/middleware.ts
1359
+ * import { defineMiddleware } from 'astro-tokenkit';
1360
+ *
1361
+ * export const onRequest = defineMiddleware();
1362
+ * ```
1280
1363
  */
1281
1364
  const defineMiddleware = () => createMiddleware();
1282
1365