astro-tokenkit 1.0.9 → 1.0.11

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
@@ -31,8 +31,6 @@ interface Session {
31
31
  * Request options
32
32
  */
33
33
  interface RequestOptions {
34
- /** Astro context (optional if middleware binds it) */
35
- ctx?: TokenKitContext;
36
34
  /** Additional headers */
37
35
  headers?: Record<string, string>;
38
36
  /** Request timeout in ms */
@@ -43,6 +41,8 @@ interface RequestOptions {
43
41
  skipAuth?: boolean;
44
42
  /** Custom signal for cancellation */
45
43
  signal?: AbortSignal;
44
+ /** Auth override options for automatic refresh if triggered */
45
+ auth?: AuthOptions;
46
46
  }
47
47
  /**
48
48
  * Request configuration
@@ -76,12 +76,19 @@ interface FieldMapping {
76
76
  * Callback after successful login
77
77
  */
78
78
  type OnLoginCallback = (bundle: TokenBundle, body: any, ctx: TokenKitContext) => void | Promise<void>;
79
+ /**
80
+ * Auth override options
81
+ */
82
+ interface AuthOptions {
83
+ /** Extra data for this specific auth request (login/refresh) */
84
+ data?: Record<string, any>;
85
+ }
79
86
  /**
80
87
  * Login options
81
88
  */
82
- interface LoginOptions {
83
- /** Astro context (optional if middleware binds it) */
84
- ctx?: TokenKitContext;
89
+ interface LoginOptions extends AuthOptions {
90
+ /** Extra headers for this specific login request */
91
+ headers?: Record<string, string>;
85
92
  /** Callback after successful login */
86
93
  onLogin?: OnLoginCallback;
87
94
  }
@@ -95,6 +102,16 @@ interface AuthConfig {
95
102
  refresh: string;
96
103
  /** Logout endpoint (optional, relative to baseURL) */
97
104
  logout?: string;
105
+ /** Content type for auth requests (default: 'application/json') */
106
+ contentType?: 'application/json' | 'application/x-www-form-urlencoded';
107
+ /** Extra headers for login/refresh requests */
108
+ headers?: Record<string, string>;
109
+ /** Extra data for login request */
110
+ loginData?: Record<string, any>;
111
+ /** Extra data for refresh request */
112
+ refreshData?: Record<string, any>;
113
+ /** Field name for refresh token in refresh request (default: 'refreshToken') */
114
+ refreshRequestField?: string;
98
115
  /** Field mapping (auto-detected if not provided) */
99
116
  fields?: FieldMapping;
100
117
  /** Custom login response parser */
@@ -185,6 +202,8 @@ interface ClientConfig {
185
202
  context?: AsyncLocalStorage<any>;
186
203
  /** Custom context store getter */
187
204
  getContextStore?: () => TokenKitContext | undefined | null;
205
+ /** Custom context store setter */
206
+ setContextStore?: (ctx: TokenKitContext) => void;
188
207
  /** Custom context runner */
189
208
  runWithContext?: <T>(ctx: TokenKitContext, fn: () => T) => T;
190
209
  }
@@ -232,11 +251,11 @@ declare class TokenManager {
232
251
  /**
233
252
  * Perform login
234
253
  */
235
- login(ctx: TokenKitContext, credentials: any, onLogin?: OnLoginCallback): Promise<TokenBundle>;
254
+ login(ctx: TokenKitContext, credentials: any, options?: LoginOptions): Promise<TokenBundle>;
236
255
  /**
237
256
  * Perform token refresh
238
257
  */
239
- refresh(ctx: TokenKitContext, refreshToken: string): Promise<TokenBundle | null>;
258
+ refresh(ctx: TokenKitContext, refreshToken: string, options?: AuthOptions, headers?: Record<string, string>): Promise<TokenBundle | null>;
240
259
  /**
241
260
  * Internal refresh implementation
242
261
  */
@@ -244,7 +263,7 @@ declare class TokenManager {
244
263
  /**
245
264
  * Ensure valid tokens (with automatic refresh)
246
265
  */
247
- ensure(ctx: TokenKitContext): Promise<Session | null>;
266
+ ensure(ctx: TokenKitContext, options?: AuthOptions, headers?: Record<string, string>): Promise<Session | null>;
248
267
  /**
249
268
  * Logout (clear tokens)
250
269
  */
@@ -328,19 +347,19 @@ declare class APIClient {
328
347
  /**
329
348
  * Login
330
349
  */
331
- login(credentials: any, options?: LoginOptions | TokenKitContext): Promise<void>;
350
+ login(credentials: any, options?: LoginOptions): Promise<void>;
332
351
  /**
333
352
  * Logout
334
353
  */
335
- logout(ctx?: TokenKitContext): Promise<void>;
354
+ logout(): Promise<void>;
336
355
  /**
337
356
  * Check if authenticated
338
357
  */
339
- isAuthenticated(ctx?: TokenKitContext): boolean;
358
+ isAuthenticated(): boolean;
340
359
  /**
341
360
  * Get current session
342
361
  */
343
- getSession(ctx?: TokenKitContext): Session | null;
362
+ getSession(): Session | null;
344
363
  }
345
364
  /**
346
365
  * Global API client instance.
@@ -413,6 +432,15 @@ declare function getTokenManager(): TokenManager | undefined;
413
432
  */
414
433
  declare function setTokenManager(manager: TokenManager | undefined): void;
415
434
 
435
+ /**
436
+ * Bind Astro context for the current async scope
437
+ */
438
+ declare function runWithContext<T>(ctx: TokenKitContext, fn: () => T): T;
439
+ /**
440
+ * Get current Astro context (from middleware binding or explicit)
441
+ */
442
+ declare function getContextStore(): TokenKitContext;
443
+
416
444
  /**
417
445
  * Parse time string to seconds
418
446
  * Supports: '5m', '30s', '1h', '2d'
@@ -423,5 +451,5 @@ declare function parseTime(input: string | number): number;
423
451
  */
424
452
  declare function formatTime(seconds: number): string;
425
453
 
426
- export { APIClient, APIError, AuthError, NetworkError, TimeoutError, api, createClient, createMiddleware, defineMiddleware, formatTime, getConfig, getTokenManager, parseTime, setConfig, setTokenManager, tokenKit };
454
+ export { APIClient, APIError, AuthError, NetworkError, TimeoutError, api, createClient, createMiddleware, defineMiddleware, formatTime, getConfig, getContextStore, getTokenManager, parseTime, runWithContext, setConfig, setTokenManager, tokenKit };
427
455
  export type { APIResponse, AuthConfig, ClientConfig, CookieConfig, ErrorInterceptor, FieldMapping, RefreshPolicy, RequestConfig, RequestInterceptor, RequestOptions, ResponseInterceptor, RetryConfig, Session, TokenBundle, TokenKitConfig, TokenKitContext };
package/dist/index.js CHANGED
@@ -413,13 +413,23 @@ class TokenManager {
413
413
  /**
414
414
  * Perform login
415
415
  */
416
- login(ctx, credentials, onLogin) {
416
+ login(ctx, credentials, options) {
417
417
  return __awaiter(this, void 0, void 0, function* () {
418
418
  const url = this.baseURL + this.config.login;
419
+ const contentType = this.config.contentType || 'application/json';
420
+ const headers = Object.assign(Object.assign({ 'Content-Type': contentType }, this.config.headers), options === null || options === void 0 ? void 0 : options.headers);
421
+ const data = Object.assign(Object.assign(Object.assign({}, this.config.loginData), options === null || options === void 0 ? void 0 : options.data), credentials);
422
+ let requestBody;
423
+ if (contentType === 'application/x-www-form-urlencoded') {
424
+ requestBody = new URLSearchParams(data).toString();
425
+ }
426
+ else {
427
+ requestBody = JSON.stringify(data);
428
+ }
419
429
  const response = yield fetch(url, {
420
430
  method: 'POST',
421
- headers: { 'Content-Type': 'application/json' },
422
- body: JSON.stringify(credentials),
431
+ headers,
432
+ body: requestBody,
423
433
  }).catch(error => {
424
434
  throw new AuthError(`Login request failed: ${error.message}`);
425
435
  });
@@ -440,8 +450,8 @@ class TokenManager {
440
450
  // Store in cookies
441
451
  storeTokens(ctx, bundle, this.config.cookies);
442
452
  // Call onLogin callback if provided
443
- if (onLogin) {
444
- yield onLogin(bundle, body, ctx);
453
+ if (options === null || options === void 0 ? void 0 : options.onLogin) {
454
+ yield options.onLogin(bundle, body, ctx);
445
455
  }
446
456
  return bundle;
447
457
  });
@@ -449,10 +459,10 @@ class TokenManager {
449
459
  /**
450
460
  * Perform token refresh
451
461
  */
452
- refresh(ctx, refreshToken) {
462
+ refresh(ctx, refreshToken, options, headers) {
453
463
  return __awaiter(this, void 0, void 0, function* () {
454
464
  try {
455
- return yield this.performRefresh(ctx, refreshToken);
465
+ return yield this.performRefresh(ctx, refreshToken, options, headers);
456
466
  }
457
467
  catch (error) {
458
468
  clearTokens(ctx, this.config.cookies);
@@ -463,13 +473,24 @@ class TokenManager {
463
473
  /**
464
474
  * Internal refresh implementation
465
475
  */
466
- performRefresh(ctx, refreshToken) {
476
+ performRefresh(ctx, refreshToken, options, extraHeaders) {
467
477
  return __awaiter(this, void 0, void 0, function* () {
468
478
  const url = this.baseURL + this.config.refresh;
479
+ const contentType = this.config.contentType || 'application/json';
480
+ const headers = Object.assign(Object.assign({ 'Content-Type': contentType }, this.config.headers), extraHeaders);
481
+ const refreshField = this.config.refreshRequestField || 'refreshToken';
482
+ const data = Object.assign(Object.assign(Object.assign({}, this.config.refreshData), options === null || options === void 0 ? void 0 : options.data), { [refreshField]: refreshToken });
483
+ let requestBody;
484
+ if (contentType === 'application/x-www-form-urlencoded') {
485
+ requestBody = new URLSearchParams(data).toString();
486
+ }
487
+ else {
488
+ requestBody = JSON.stringify(data);
489
+ }
469
490
  const response = yield fetch(url, {
470
491
  method: 'POST',
471
- headers: { 'Content-Type': 'application/json' },
472
- body: JSON.stringify({ refreshToken }),
492
+ headers,
493
+ body: requestBody,
473
494
  }).catch(error => {
474
495
  throw new AuthError(`Refresh request failed: ${error.message}`);
475
496
  });
@@ -504,7 +525,7 @@ class TokenManager {
504
525
  /**
505
526
  * Ensure valid tokens (with automatic refresh)
506
527
  */
507
- ensure(ctx) {
528
+ ensure(ctx, options, headers) {
508
529
  return __awaiter(this, void 0, void 0, function* () {
509
530
  var _a, _b, _c, _d, _e;
510
531
  const now = Math.floor(Date.now() / 1000);
@@ -516,7 +537,7 @@ class TokenManager {
516
537
  // Token expired
517
538
  if (isExpired(tokens.expiresAt, now, this.config.policy)) {
518
539
  const flightKey = this.createFlightKey(tokens.refreshToken);
519
- const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken));
540
+ const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
520
541
  if (!bundle)
521
542
  return null;
522
543
  return {
@@ -528,7 +549,7 @@ class TokenManager {
528
549
  // Proactive refresh
529
550
  if (shouldRefresh(tokens.expiresAt, now, tokens.lastRefreshAt, this.config.policy)) {
530
551
  const flightKey = this.createFlightKey(tokens.refreshToken);
531
- const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken));
552
+ const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
532
553
  if (bundle) {
533
554
  return {
534
555
  accessToken: bundle.accessToken,
@@ -609,6 +630,7 @@ class TokenManager {
609
630
  let config = {
610
631
  runWithContext: undefined,
611
632
  getContextStore: undefined,
633
+ setContextStore: undefined,
612
634
  baseURL: "",
613
635
  };
614
636
  let tokenManager;
@@ -616,8 +638,13 @@ let tokenManager;
616
638
  * Set configuration
617
639
  */
618
640
  function setConfig(userConfig) {
619
- // Store validated config
620
- config = Object.assign(Object.assign({}, config), userConfig);
641
+ const finalConfig = Object.assign(Object.assign({}, config), userConfig);
642
+ // Validate that getter and setter are defined together
643
+ if ((finalConfig.getContextStore && !finalConfig.setContextStore) ||
644
+ (!finalConfig.getContextStore && finalConfig.setContextStore)) {
645
+ throw new Error("[TokenKit] getContextStore and setContextStore must be defined together.");
646
+ }
647
+ config = finalConfig;
621
648
  // Re-initialize global token manager if auth changed
622
649
  if (config.auth) {
623
650
  tokenManager = new TokenManager(config.auth, config.baseURL);
@@ -661,20 +688,17 @@ function runWithContext(ctx, fn) {
661
688
  /**
662
689
  * Get current Astro context (from middleware binding or explicit)
663
690
  */
664
- function getContextStore(explicitCtx) {
691
+ function getContextStore() {
665
692
  const config = getConfig();
666
693
  const getStore = config.getContextStore;
667
694
  const context = config.context || als;
668
695
  const store = getStore
669
696
  ? getStore()
670
697
  : context.getStore();
671
- const ctx = explicitCtx || store;
672
- if (!ctx) {
673
- throw new Error('Astro context not found. Either:\n' +
674
- '1. Use api.middleware() to bind context automatically, or\n' +
675
- '2. Pass context explicitly: api.get("/path", { ctx: Astro })');
698
+ if (!store) {
699
+ throw new Error('Astro context not found. Make sure to use api.middleware() to bind context automatically.');
676
700
  }
677
- return ctx;
701
+ return store;
678
702
  }
679
703
 
680
704
  // packages/astro-tokenkit/src/utils/retry.ts
@@ -729,14 +753,14 @@ function createMiddleware() {
729
753
  const tokenManager = getTokenManager();
730
754
  const config = getConfig();
731
755
  const runLogic = () => __awaiter(this, void 0, void 0, function* () {
732
- // Proactively ensure valid session if auth is configured
756
+ // Proactively ensure a valid session if auth is configured
733
757
  if (tokenManager) {
734
758
  try {
735
759
  // This handles token rotation (refresh) if needed
736
760
  yield tokenManager.ensure(ctx);
737
761
  }
738
762
  catch (error) {
739
- // Log but don't block request if rotation fails
763
+ // Log but don't block a request if rotation fails
740
764
  console.error('[TokenKit] Automatic token rotation failed:', error);
741
765
  }
742
766
  }
@@ -746,13 +770,14 @@ function createMiddleware() {
746
770
  // We skip runWithContext to avoid nesting ALS.run() unnecessarily,
747
771
  // UNLESS a custom runWithContext is provided.
748
772
  if (config.getContextStore && !config.runWithContext) {
749
- const storage = config.getContextStore();
750
- if (storage) {
773
+ let storage = config.getContextStore();
774
+ if (storage)
775
+ // Update existing reference
751
776
  storage.cookies = ctx.cookies;
752
- }
753
- else {
754
- console.error("[TokenKit] getContextStore returned null or undefined");
755
- }
777
+ else if (config.setContextStore)
778
+ config.setContextStore({ cookies: ctx.cookies });
779
+ else
780
+ console.error("[TokenKit] getContextStore returned null or undefined and no setter was found");
756
781
  return runLogic();
757
782
  }
758
783
  const runner = (_a = config.runWithContext) !== null && _a !== void 0 ? _a : runWithContext;
@@ -860,7 +885,7 @@ class APIClient {
860
885
  */
861
886
  request(config) {
862
887
  return __awaiter(this, void 0, void 0, function* () {
863
- const ctx = getContextStore(config.ctx);
888
+ const ctx = getContextStore();
864
889
  let attempt = 0;
865
890
  while (true) {
866
891
  attempt++;
@@ -889,7 +914,7 @@ class APIClient {
889
914
  var _a, _b, _c, _d, _e;
890
915
  // Ensure valid session (if auth is enabled)
891
916
  if (this.tokenManager && !config.skipAuth) {
892
- yield this.tokenManager.ensure(ctx);
917
+ yield this.tokenManager.ensure(ctx, config.auth, config.headers);
893
918
  }
894
919
  // Build full URL
895
920
  const fullURL = this.buildURL(config.url, config.params);
@@ -922,7 +947,7 @@ class APIClient {
922
947
  // Handle 401 (try refresh and retry once)
923
948
  if (response.status === 401 && this.tokenManager && !config.skipAuth && attempt === 1) {
924
949
  // Clear and try fresh session
925
- const session = yield this.tokenManager.ensure(ctx);
950
+ const session = yield this.tokenManager.ensure(ctx, config.auth, config.headers);
926
951
  if (session) {
927
952
  // Retry with new token
928
953
  return this.executeRequest(config, ctx, attempt + 1);
@@ -1033,48 +1058,38 @@ class APIClient {
1033
1058
  if (!this.tokenManager) {
1034
1059
  throw new Error('Auth is not configured for this client');
1035
1060
  }
1036
- let ctx;
1037
- let onLogin;
1038
- if (options && 'cookies' in options) {
1039
- ctx = options;
1040
- }
1041
- else if (options) {
1042
- const opt = options;
1043
- ctx = opt.ctx;
1044
- onLogin = opt.onLogin;
1045
- }
1046
- const context = getContextStore(ctx);
1047
- yield this.tokenManager.login(context, credentials, onLogin);
1061
+ const context = getContextStore();
1062
+ yield this.tokenManager.login(context, credentials, options);
1048
1063
  });
1049
1064
  }
1050
1065
  /**
1051
1066
  * Logout
1052
1067
  */
1053
- logout(ctx) {
1068
+ logout() {
1054
1069
  return __awaiter(this, void 0, void 0, function* () {
1055
1070
  if (!this.tokenManager) {
1056
1071
  throw new Error('Auth is not configured for this client');
1057
1072
  }
1058
- const context = getContextStore(ctx);
1073
+ const context = getContextStore();
1059
1074
  yield this.tokenManager.logout(context);
1060
1075
  });
1061
1076
  }
1062
1077
  /**
1063
1078
  * Check if authenticated
1064
1079
  */
1065
- isAuthenticated(ctx) {
1080
+ isAuthenticated() {
1066
1081
  if (!this.tokenManager)
1067
1082
  return false;
1068
- const context = getContextStore(ctx);
1083
+ const context = getContextStore();
1069
1084
  return this.tokenManager.isAuthenticated(context);
1070
1085
  }
1071
1086
  /**
1072
1087
  * Get current session
1073
1088
  */
1074
- getSession(ctx) {
1089
+ getSession() {
1075
1090
  if (!this.tokenManager)
1076
1091
  return null;
1077
- const context = getContextStore(ctx);
1092
+ const context = getContextStore();
1078
1093
  return this.tokenManager.getSession(context);
1079
1094
  }
1080
1095
  }
@@ -1137,5 +1152,5 @@ function tokenKit(config) {
1137
1152
  */
1138
1153
  const defineMiddleware = () => createMiddleware();
1139
1154
 
1140
- export { APIClient, APIError, AuthError, NetworkError, TimeoutError, api, createClient, createMiddleware, defineMiddleware, formatTime, getConfig, getTokenManager, parseTime, setConfig, setTokenManager, tokenKit };
1155
+ export { APIClient, APIError, AuthError, NetworkError, TimeoutError, api, createClient, createMiddleware, defineMiddleware, formatTime, getConfig, getContextStore, getTokenManager, parseTime, runWithContext, setConfig, setTokenManager, tokenKit };
1141
1156
  //# sourceMappingURL=index.js.map