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.
@@ -4,6 +4,13 @@ import type { TokenKitConfig } from './types';
4
4
  * Astro integration for TokenKit
5
5
  *
6
6
  * This integration facilitates the setup of TokenKit in an Astro project.
7
+ * It performs the following:
8
+ * - Sets the global configuration for the API client.
9
+ * - Injects the configuration into the client-side via Vite's `define`.
10
+ * - Automatically registers the TokenKit middleware (unless `autoMiddleware` is set to `false`).
11
+ * - Injects a client-side script (`astro-tokenkit/client-init`) to handle idle session monitoring and automatic logout.
12
+ *
13
+ * @param config - TokenKit configuration options.
7
14
  *
8
15
  * @example
9
16
  * ```ts
@@ -17,6 +24,10 @@ import type { TokenKitConfig } from './types';
17
24
  * auth: {
18
25
  * login: '/auth/login',
19
26
  * refresh: '/auth/refresh',
27
+ * },
28
+ * idle: {
29
+ * timeout: 3600, // 1 hour
30
+ * alert: { title: 'Session Expired' }
20
31
  * }
21
32
  * })
22
33
  * ]
@@ -25,6 +36,17 @@ import type { TokenKitConfig } from './types';
25
36
  */
26
37
  export declare function tokenKit(config: TokenKitConfig): AstroIntegration;
27
38
  /**
28
- * Helper to define middleware in a separate file if needed
39
+ * Helper to create the TokenKit middleware.
40
+ *
41
+ * Use this if you have `autoMiddleware: false` in your integration configuration
42
+ * and want to manually register the middleware in your `src/middleware.ts` file.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * // src/middleware.ts
47
+ * import { defineMiddleware } from 'astro-tokenkit';
48
+ *
49
+ * export const onRequest = defineMiddleware();
50
+ * ```
29
51
  */
30
52
  export declare const defineMiddleware: () => import("astro").MiddlewareHandler;
@@ -1,10 +1,18 @@
1
1
  // packages/astro-tokenkit/src/integration.ts
2
2
  import { createMiddleware } from './middleware';
3
3
  import { setConfig } from './config';
4
+ import { logger } from './utils/logger';
4
5
  /**
5
6
  * Astro integration for TokenKit
6
7
  *
7
8
  * This integration facilitates the setup of TokenKit in an Astro project.
9
+ * It performs the following:
10
+ * - Sets the global configuration for the API client.
11
+ * - Injects the configuration into the client-side via Vite's `define`.
12
+ * - Automatically registers the TokenKit middleware (unless `autoMiddleware` is set to `false`).
13
+ * - Injects a client-side script (`astro-tokenkit/client-init`) to handle idle session monitoring and automatic logout.
14
+ *
15
+ * @param config - TokenKit configuration options.
8
16
  *
9
17
  * @example
10
18
  * ```ts
@@ -18,6 +26,10 @@ import { setConfig } from './config';
18
26
  * auth: {
19
27
  * login: '/auth/login',
20
28
  * refresh: '/auth/refresh',
29
+ * },
30
+ * idle: {
31
+ * timeout: 3600, // 1 hour
32
+ * alert: { title: 'Session Expired' }
21
33
  * }
22
34
  * })
23
35
  * ]
@@ -35,7 +47,7 @@ export function tokenKit(config) {
35
47
  return {
36
48
  name: 'astro-tokenkit',
37
49
  hooks: {
38
- 'astro:config:setup': ({ updateConfig, addMiddleware }) => {
50
+ 'astro:config:setup': ({ updateConfig, addMiddleware, injectScript }) => {
39
51
  updateConfig({
40
52
  vite: {
41
53
  define: {
@@ -50,12 +62,25 @@ export function tokenKit(config) {
50
62
  order: 'pre'
51
63
  });
52
64
  }
53
- console.log('[TokenKit] Integration initialized');
65
+ // Always inject the client-side script for idle monitoring
66
+ injectScript('page', `import 'astro-tokenkit/client-init';`);
67
+ logger.debug('[TokenKit] Integration initialized');
54
68
  },
55
69
  },
56
70
  };
57
71
  }
58
72
  /**
59
- * Helper to define middleware in a separate file if needed
73
+ * Helper to create the TokenKit middleware.
74
+ *
75
+ * Use this if you have `autoMiddleware: false` in your integration configuration
76
+ * and want to manually register the middleware in your `src/middleware.ts` file.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * // src/middleware.ts
81
+ * import { defineMiddleware } from 'astro-tokenkit';
82
+ *
83
+ * export const onRequest = defineMiddleware();
84
+ * ```
60
85
  */
61
86
  export const defineMiddleware = () => createMiddleware();
@@ -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
  }
@@ -366,6 +369,56 @@ function isExpired(expiresAt, now, policy = {}) {
366
369
  return now + clockSkew > expiresAt;
367
370
  }
368
371
 
372
+ // packages/astro-tokenkit/src/utils/fetch.ts
373
+ /**
374
+ * Perform a fetch request with optional certificate validation bypass
375
+ */
376
+ function safeFetch(url, init, config) {
377
+ return __awaiter(this, void 0, void 0, function* () {
378
+ const fetchFn = config.fetch || fetch;
379
+ const fetchOptions = Object.assign({}, init);
380
+ if (config.dangerouslyIgnoreCertificateErrors && typeof process !== 'undefined') {
381
+ // In Node.js environment
382
+ try {
383
+ // Try to use undici Agent if available (it is built-in in Node 18+)
384
+ // However, we might need to import it if we want to create an Agent.
385
+ // Since we don't want to depend on undici in package.json, we use dynamic import.
386
+ // But wait, undici's Agent is what we need.
387
+ // As a fallback and most reliable way for self-signed certs in Node without extra deps:
388
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
389
+ // NOTE: This affects the whole process. We should ideally only do this if it's not already 0.
390
+ // But for a dev tool / specialized library, it's often what's needed.
391
+ }
392
+ catch (e) {
393
+ // Ignore
394
+ }
395
+ }
396
+ return fetchFn(url, fetchOptions);
397
+ });
398
+ }
399
+
400
+ /**
401
+ * Logger utility that respects the debug flag in the configuration
402
+ */
403
+ const logger = {
404
+ debug: (message, ...args) => {
405
+ if (getConfig().debug) {
406
+ console.debug(message, ...args);
407
+ }
408
+ },
409
+ info: (message, ...args) => {
410
+ if (getConfig().debug) {
411
+ console.log(message, ...args);
412
+ }
413
+ },
414
+ warn: (message, ...args) => {
415
+ console.warn(message, ...args);
416
+ },
417
+ error: (message, ...args) => {
418
+ console.error(message, ...args);
419
+ }
420
+ };
421
+
369
422
  // packages/astro-tokenkit/src/auth/manager.ts
370
423
  /**
371
424
  * Single-flight refresh manager
@@ -422,14 +475,14 @@ class TokenManager {
422
475
  }
423
476
  let response;
424
477
  try {
425
- response = yield fetch(url, {
478
+ response = yield safeFetch(url, {
426
479
  method: 'POST',
427
480
  headers,
428
481
  body: requestBody,
429
- });
482
+ }, this.config);
430
483
  }
431
484
  catch (error) {
432
- const authError = new AuthError(`Login request failed: ${error.message}`);
485
+ const authError = new AuthError(`Login request failed: ${error.message}`, undefined, undefined, undefined, error);
433
486
  if (options === null || options === void 0 ? void 0 : options.onError)
434
487
  yield options.onError(authError, ctx);
435
488
  throw authError;
@@ -503,14 +556,14 @@ class TokenManager {
503
556
  }
504
557
  let response;
505
558
  try {
506
- response = yield fetch(url, {
559
+ response = yield safeFetch(url, {
507
560
  method: 'POST',
508
561
  headers,
509
562
  body: requestBody,
510
- });
563
+ }, this.config);
511
564
  }
512
565
  catch (error) {
513
- throw new AuthError(`Refresh request failed: ${error.message}`);
566
+ throw new AuthError(`Refresh request failed: ${error.message}`, undefined, undefined, undefined, error);
514
567
  }
515
568
  if (!response.ok) {
516
569
  // 401/403 = invalid refresh token
@@ -608,11 +661,11 @@ class TokenManager {
608
661
  const injectFn = (_a = this.config.injectToken) !== null && _a !== void 0 ? _a : ((token, type) => `${type !== null && type !== void 0 ? type : 'Bearer'} ${token}`);
609
662
  headers['Authorization'] = injectFn(session.accessToken, session.tokenType);
610
663
  }
611
- yield fetch(url, { method: 'POST', headers });
664
+ yield safeFetch(url, { method: 'POST', headers }, this.config);
612
665
  }
613
666
  catch (error) {
614
667
  // Ignore logout endpoint errors
615
- console.warn('[TokenKit] Logout endpoint failed:', error);
668
+ logger.debug('[TokenKit] Logout endpoint failed:', error);
616
669
  }
617
670
  }
618
671
  clearTokens(ctx, this.config.cookies);
@@ -669,12 +722,14 @@ if (!globalStorage[CONFIG_KEY]) {
669
722
  getContextStore: undefined,
670
723
  setContextStore: undefined,
671
724
  baseURL: "",
725
+ debug: false,
672
726
  };
673
727
  }
674
728
  /**
675
729
  * Set configuration
676
730
  */
677
731
  function setConfig(userConfig) {
732
+ var _a, _b;
678
733
  const currentConfig = globalStorage[CONFIG_KEY];
679
734
  const finalConfig = Object.assign(Object.assign({}, currentConfig), userConfig);
680
735
  // Validate that getter and setter are defined together
@@ -685,7 +740,8 @@ function setConfig(userConfig) {
685
740
  globalStorage[CONFIG_KEY] = finalConfig;
686
741
  // Re-initialize global token manager if auth changed
687
742
  if (finalConfig.auth) {
688
- globalStorage[MANAGER_KEY] = new TokenManager(finalConfig.auth, finalConfig.baseURL);
743
+ 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 });
744
+ globalStorage[MANAGER_KEY] = new TokenManager(authConfig, finalConfig.baseURL);
689
745
  }
690
746
  else {
691
747
  globalStorage[MANAGER_KEY] = undefined;
@@ -754,7 +810,7 @@ function createMiddleware() {
754
810
  else if (config.context) {
755
811
  contextStrategy = 'custom (external AsyncLocalStorage)';
756
812
  }
757
- console.log(`[TokenKit] Middleware initialized (auth: ${authStatus}, context: ${contextStrategy})`);
813
+ logger.debug(`[TokenKit] Middleware initialized (auth: ${authStatus}, context: ${contextStrategy})`);
758
814
  globalStorage[LOGGED_KEY] = true;
759
815
  }
760
816
  const runLogic = () => __awaiter(this, void 0, void 0, function* () {
@@ -766,7 +822,7 @@ function createMiddleware() {
766
822
  }
767
823
  catch (error) {
768
824
  // Log only the message to avoid leaking sensitive data in the error object
769
- console.error('[TokenKit] Automatic token rotation failed:', error.message || error);
825
+ logger.debug('[TokenKit] Automatic token rotation failed:', error.message || error);
770
826
  }
771
827
  }
772
828
  return next();