astro-tokenkit 1.0.10 → 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/README.md CHANGED
@@ -125,6 +125,11 @@ const specializedClient = createClient({
125
125
  | `login` | `string` | Endpoint path for login (POST). |
126
126
  | `refresh` | `string` | Endpoint path for token refresh (POST). |
127
127
  | `logout` | `string` | Endpoint path for logout (POST). |
128
+ | `contentType` | `'application/json' \| 'application/x-www-form-urlencoded'` | Content type for auth requests (default: `application/json`). |
129
+ | `headers` | `Record<string, string>` | Extra headers for login/refresh requests. |
130
+ | `loginData` | `Record<string, any>` | Extra data to be sent with login request. |
131
+ | `refreshData` | `Record<string, any>` | Extra data to be sent with refresh request. |
132
+ | `refreshRequestField` | `string` | Field name for the refresh token in the refresh request (default: `refreshToken`). |
128
133
  | `fields` | `FieldMapping` | Custom mapping for token fields in API responses. |
129
134
  | `parseLogin` | `Function` | Custom parser for login response: `(body: any) => TokenBundle`. |
130
135
  | `parseRefresh`| `Function` | Custom parser for refresh response: `(body: any) => TokenBundle`. |
@@ -136,17 +141,33 @@ const specializedClient = createClient({
136
141
 
137
142
  | Property | Type | Description |
138
143
  | :--- | :--- | :--- |
139
- | `ctx` | `TokenKitContext` | Optional Astro context. |
140
144
  | `onLogin` | `Function` | Callback after successful login: `(bundle, body, ctx) => void`. |
145
+ | `headers` | `Record<string, string>` | Extra headers for this specific login request. |
146
+ | `data` | `Record<string, any>` | Extra data for this specific login request. |
147
+
148
+ ### Request Auth Overrides
149
+
150
+ When calling `api.get()`, `api.post()`, etc., you can override auth configuration (e.g., for multi-tenancy). Headers provided in the request options are automatically propagated to any automatic token refresh operations:
151
+
152
+ ```typescript
153
+ await api.get('/data', {
154
+ headers: { 'x-tenant-name': 'lynx' },
155
+ auth: {
156
+ data: { extra_refresh_param: 'value' }
157
+ }
158
+ });
159
+ ```
141
160
 
142
161
  ## Advanced Usage
143
162
 
144
163
  ### Manual Context
145
164
 
146
- If you prefer not to use middleware, you can pass the Astro context explicitly to any request:
165
+ If you prefer not to use middleware, you can bind the Astro context manually for a specific scope:
147
166
 
148
167
  ```typescript
149
- const data = await api.get('/data', { ctx: Astro });
168
+ import { runWithContext } from 'astro-tokenkit';
169
+
170
+ const data = await runWithContext(Astro, () => api.get('/data'));
150
171
  ```
151
172
 
152
173
  ### Interceptors
@@ -1,4 +1,4 @@
1
- import type { TokenBundle, Session, AuthConfig, TokenKitContext, OnLoginCallback } from '../types';
1
+ import type { TokenBundle, Session, AuthConfig, TokenKitContext, AuthOptions, LoginOptions } from '../types';
2
2
  /**
3
3
  * Token Manager handles all token operations
4
4
  */
@@ -10,11 +10,11 @@ export declare class TokenManager {
10
10
  /**
11
11
  * Perform login
12
12
  */
13
- login(ctx: TokenKitContext, credentials: any, onLogin?: OnLoginCallback): Promise<TokenBundle>;
13
+ login(ctx: TokenKitContext, credentials: any, options?: LoginOptions): Promise<TokenBundle>;
14
14
  /**
15
15
  * Perform token refresh
16
16
  */
17
- refresh(ctx: TokenKitContext, refreshToken: string): Promise<TokenBundle | null>;
17
+ refresh(ctx: TokenKitContext, refreshToken: string, options?: AuthOptions, headers?: Record<string, string>): Promise<TokenBundle | null>;
18
18
  /**
19
19
  * Internal refresh implementation
20
20
  */
@@ -22,7 +22,7 @@ export declare class TokenManager {
22
22
  /**
23
23
  * Ensure valid tokens (with automatic refresh)
24
24
  */
25
- ensure(ctx: TokenKitContext): Promise<Session | null>;
25
+ ensure(ctx: TokenKitContext, options?: AuthOptions, headers?: Record<string, string>): Promise<Session | null>;
26
26
  /**
27
27
  * Logout (clear tokens)
28
28
  */
@@ -52,13 +52,23 @@ export class TokenManager {
52
52
  /**
53
53
  * Perform login
54
54
  */
55
- login(ctx, credentials, onLogin) {
55
+ login(ctx, credentials, options) {
56
56
  return __awaiter(this, void 0, void 0, function* () {
57
57
  const url = this.baseURL + this.config.login;
58
+ const contentType = this.config.contentType || 'application/json';
59
+ const headers = Object.assign(Object.assign({ 'Content-Type': contentType }, this.config.headers), options === null || options === void 0 ? void 0 : options.headers);
60
+ const data = Object.assign(Object.assign(Object.assign({}, this.config.loginData), options === null || options === void 0 ? void 0 : options.data), credentials);
61
+ let requestBody;
62
+ if (contentType === 'application/x-www-form-urlencoded') {
63
+ requestBody = new URLSearchParams(data).toString();
64
+ }
65
+ else {
66
+ requestBody = JSON.stringify(data);
67
+ }
58
68
  const response = yield fetch(url, {
59
69
  method: 'POST',
60
- headers: { 'Content-Type': 'application/json' },
61
- body: JSON.stringify(credentials),
70
+ headers,
71
+ body: requestBody,
62
72
  }).catch(error => {
63
73
  throw new AuthError(`Login request failed: ${error.message}`);
64
74
  });
@@ -79,8 +89,8 @@ export class TokenManager {
79
89
  // Store in cookies
80
90
  storeTokens(ctx, bundle, this.config.cookies);
81
91
  // Call onLogin callback if provided
82
- if (onLogin) {
83
- yield onLogin(bundle, body, ctx);
92
+ if (options === null || options === void 0 ? void 0 : options.onLogin) {
93
+ yield options.onLogin(bundle, body, ctx);
84
94
  }
85
95
  return bundle;
86
96
  });
@@ -88,10 +98,10 @@ export class TokenManager {
88
98
  /**
89
99
  * Perform token refresh
90
100
  */
91
- refresh(ctx, refreshToken) {
101
+ refresh(ctx, refreshToken, options, headers) {
92
102
  return __awaiter(this, void 0, void 0, function* () {
93
103
  try {
94
- return yield this.performRefresh(ctx, refreshToken);
104
+ return yield this.performRefresh(ctx, refreshToken, options, headers);
95
105
  }
96
106
  catch (error) {
97
107
  clearTokens(ctx, this.config.cookies);
@@ -102,13 +112,24 @@ export class TokenManager {
102
112
  /**
103
113
  * Internal refresh implementation
104
114
  */
105
- performRefresh(ctx, refreshToken) {
115
+ performRefresh(ctx, refreshToken, options, extraHeaders) {
106
116
  return __awaiter(this, void 0, void 0, function* () {
107
117
  const url = this.baseURL + this.config.refresh;
118
+ const contentType = this.config.contentType || 'application/json';
119
+ const headers = Object.assign(Object.assign({ 'Content-Type': contentType }, this.config.headers), extraHeaders);
120
+ const refreshField = this.config.refreshRequestField || 'refreshToken';
121
+ const data = Object.assign(Object.assign(Object.assign({}, this.config.refreshData), options === null || options === void 0 ? void 0 : options.data), { [refreshField]: refreshToken });
122
+ let requestBody;
123
+ if (contentType === 'application/x-www-form-urlencoded') {
124
+ requestBody = new URLSearchParams(data).toString();
125
+ }
126
+ else {
127
+ requestBody = JSON.stringify(data);
128
+ }
108
129
  const response = yield fetch(url, {
109
130
  method: 'POST',
110
- headers: { 'Content-Type': 'application/json' },
111
- body: JSON.stringify({ refreshToken }),
131
+ headers,
132
+ body: requestBody,
112
133
  }).catch(error => {
113
134
  throw new AuthError(`Refresh request failed: ${error.message}`);
114
135
  });
@@ -143,7 +164,7 @@ export class TokenManager {
143
164
  /**
144
165
  * Ensure valid tokens (with automatic refresh)
145
166
  */
146
- ensure(ctx) {
167
+ ensure(ctx, options, headers) {
147
168
  return __awaiter(this, void 0, void 0, function* () {
148
169
  var _a, _b, _c, _d, _e;
149
170
  const now = Math.floor(Date.now() / 1000);
@@ -155,7 +176,7 @@ export class TokenManager {
155
176
  // Token expired
156
177
  if (isExpired(tokens.expiresAt, now, this.config.policy)) {
157
178
  const flightKey = this.createFlightKey(tokens.refreshToken);
158
- const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken));
179
+ const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
159
180
  if (!bundle)
160
181
  return null;
161
182
  return {
@@ -167,7 +188,7 @@ export class TokenManager {
167
188
  // Proactive refresh
168
189
  if (shouldRefresh(tokens.expiresAt, now, tokens.lastRefreshAt, this.config.policy)) {
169
190
  const flightKey = this.createFlightKey(tokens.refreshToken);
170
- const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken));
191
+ const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
171
192
  if (bundle) {
172
193
  return {
173
194
  accessToken: bundle.accessToken,
@@ -1,4 +1,4 @@
1
- import type { ClientConfig, RequestConfig, RequestOptions, Session, TokenKitContext, TokenKitConfig, LoginOptions } from '../types';
1
+ import type { ClientConfig, RequestConfig, RequestOptions, Session, TokenKitConfig, LoginOptions } from '../types';
2
2
  import { TokenManager } from '../auth/manager';
3
3
  /**
4
4
  * API Client
@@ -65,19 +65,19 @@ export declare class APIClient {
65
65
  /**
66
66
  * Login
67
67
  */
68
- login(credentials: any, options?: LoginOptions | TokenKitContext): Promise<void>;
68
+ login(credentials: any, options?: LoginOptions): Promise<void>;
69
69
  /**
70
70
  * Logout
71
71
  */
72
- logout(ctx?: TokenKitContext): Promise<void>;
72
+ logout(): Promise<void>;
73
73
  /**
74
74
  * Check if authenticated
75
75
  */
76
- isAuthenticated(ctx?: TokenKitContext): boolean;
76
+ isAuthenticated(): boolean;
77
77
  /**
78
78
  * Get current session
79
79
  */
80
- getSession(ctx?: TokenKitContext): Session | null;
80
+ getSession(): Session | null;
81
81
  }
82
82
  /**
83
83
  * Global API client instance.
@@ -113,7 +113,7 @@ export class APIClient {
113
113
  */
114
114
  request(config) {
115
115
  return __awaiter(this, void 0, void 0, function* () {
116
- const ctx = getContextStore(config.ctx);
116
+ const ctx = getContextStore();
117
117
  let attempt = 0;
118
118
  let lastError;
119
119
  while (true) {
@@ -144,7 +144,7 @@ export class APIClient {
144
144
  var _a, _b, _c, _d, _e;
145
145
  // Ensure valid session (if auth is enabled)
146
146
  if (this.tokenManager && !config.skipAuth) {
147
- yield this.tokenManager.ensure(ctx);
147
+ yield this.tokenManager.ensure(ctx, config.auth, config.headers);
148
148
  }
149
149
  // Build full URL
150
150
  const fullURL = this.buildURL(config.url, config.params);
@@ -177,7 +177,7 @@ export class APIClient {
177
177
  // Handle 401 (try refresh and retry once)
178
178
  if (response.status === 401 && this.tokenManager && !config.skipAuth && attempt === 1) {
179
179
  // Clear and try fresh session
180
- const session = yield this.tokenManager.ensure(ctx);
180
+ const session = yield this.tokenManager.ensure(ctx, config.auth, config.headers);
181
181
  if (session) {
182
182
  // Retry with new token
183
183
  return this.executeRequest(config, ctx, attempt + 1);
@@ -288,48 +288,38 @@ export class APIClient {
288
288
  if (!this.tokenManager) {
289
289
  throw new Error('Auth is not configured for this client');
290
290
  }
291
- let ctx;
292
- let onLogin;
293
- if (options && 'cookies' in options) {
294
- ctx = options;
295
- }
296
- else if (options) {
297
- const opt = options;
298
- ctx = opt.ctx;
299
- onLogin = opt.onLogin;
300
- }
301
- const context = getContextStore(ctx);
302
- yield this.tokenManager.login(context, credentials, onLogin);
291
+ const context = getContextStore();
292
+ yield this.tokenManager.login(context, credentials, options);
303
293
  });
304
294
  }
305
295
  /**
306
296
  * Logout
307
297
  */
308
- logout(ctx) {
298
+ logout() {
309
299
  return __awaiter(this, void 0, void 0, function* () {
310
300
  if (!this.tokenManager) {
311
301
  throw new Error('Auth is not configured for this client');
312
302
  }
313
- const context = getContextStore(ctx);
303
+ const context = getContextStore();
314
304
  yield this.tokenManager.logout(context);
315
305
  });
316
306
  }
317
307
  /**
318
308
  * Check if authenticated
319
309
  */
320
- isAuthenticated(ctx) {
310
+ isAuthenticated() {
321
311
  if (!this.tokenManager)
322
312
  return false;
323
- const context = getContextStore(ctx);
313
+ const context = getContextStore();
324
314
  return this.tokenManager.isAuthenticated(context);
325
315
  }
326
316
  /**
327
317
  * Get current session
328
318
  */
329
- getSession(ctx) {
319
+ getSession() {
330
320
  if (!this.tokenManager)
331
321
  return null;
332
- const context = getContextStore(ctx);
322
+ const context = getContextStore();
333
323
  return this.tokenManager.getSession(context);
334
324
  }
335
325
  }
@@ -10,7 +10,7 @@ export declare function setSharedContextStorage(storage: AsyncLocalStorage<any>,
10
10
  /**
11
11
  * Get context from shared storage
12
12
  */
13
- export declare function getContextStore(explicitCtx?: TokenKitContext): TokenKitContext;
13
+ export declare function getContextStore(): TokenKitContext;
14
14
  /**
15
15
  * Bind context (only needed if not using shared storage)
16
16
  */
@@ -33,10 +33,7 @@ export function setSharedContextStorage(storage, key = 'astro') {
33
33
  /**
34
34
  * Get context from shared storage
35
35
  */
36
- export function getContextStore(explicitCtx) {
37
- if (explicitCtx) {
38
- return explicitCtx;
39
- }
36
+ export function getContextStore() {
40
37
  const config = getConfig();
41
38
  const getStore = config.getContextStore;
42
39
  if (getStore) {
@@ -51,10 +48,7 @@ export function getContextStore(explicitCtx) {
51
48
  return ctx;
52
49
  }
53
50
  }
54
- throw new Error('Astro context not found. Either:\n' +
55
- '1. Use api.middleware() to bind context automatically, or\n' +
56
- '2. Pass context explicitly: api.get("/path", { ctx: Astro })\n' +
57
- '3. Configure shared storage: setSharedContextStorage(storage, "key")');
51
+ throw new Error('Astro context not found. Make sure to use api.middleware() to bind context automatically.');
58
52
  }
59
53
  /**
60
54
  * Bind context (only needed if not using shared storage)
@@ -6,8 +6,8 @@ export declare function runWithContext<T>(ctx: TokenKitContext, fn: () => T): T;
6
6
  /**
7
7
  * Get current Astro context (from middleware binding or explicit)
8
8
  */
9
- export declare function getContextStore(explicitCtx?: TokenKitContext): TokenKitContext;
9
+ export declare function getContextStore(): TokenKitContext;
10
10
  /**
11
11
  * Check if context is available
12
12
  */
13
- export declare function hasContext(explicitCtx?: TokenKitContext): boolean;
13
+ export declare function hasContext(): boolean;
@@ -19,30 +19,27 @@ export function runWithContext(ctx, fn) {
19
19
  /**
20
20
  * Get current Astro context (from middleware binding or explicit)
21
21
  */
22
- export function getContextStore(explicitCtx) {
22
+ export function getContextStore() {
23
23
  const config = getConfig();
24
24
  const getStore = config.getContextStore;
25
25
  const context = config.context || als;
26
26
  const store = getStore
27
27
  ? getStore()
28
28
  : context.getStore();
29
- const ctx = explicitCtx || store;
30
- if (!ctx) {
31
- throw new Error('Astro context not found. Either:\n' +
32
- '1. Use api.middleware() to bind context automatically, or\n' +
33
- '2. Pass context explicitly: api.get("/path", { ctx: Astro })');
29
+ if (!store) {
30
+ throw new Error('Astro context not found. Make sure to use api.middleware() to bind context automatically.');
34
31
  }
35
- return ctx;
32
+ return store;
36
33
  }
37
34
  /**
38
35
  * Check if context is available
39
36
  */
40
- export function hasContext(explicitCtx) {
37
+ export function hasContext() {
41
38
  const config = getConfig();
42
39
  const getStore = config.getContextStore;
43
40
  const context = config.context || als;
44
41
  const store = getStore
45
42
  ? getStore()
46
43
  : context.getStore();
47
- return !!(explicitCtx || store);
44
+ return !!store;
48
45
  }
package/dist/index.cjs CHANGED
@@ -415,13 +415,23 @@ class TokenManager {
415
415
  /**
416
416
  * Perform login
417
417
  */
418
- login(ctx, credentials, onLogin) {
418
+ login(ctx, credentials, options) {
419
419
  return __awaiter(this, void 0, void 0, function* () {
420
420
  const url = this.baseURL + this.config.login;
421
+ const contentType = this.config.contentType || 'application/json';
422
+ const headers = Object.assign(Object.assign({ 'Content-Type': contentType }, this.config.headers), options === null || options === void 0 ? void 0 : options.headers);
423
+ const data = Object.assign(Object.assign(Object.assign({}, this.config.loginData), options === null || options === void 0 ? void 0 : options.data), credentials);
424
+ let requestBody;
425
+ if (contentType === 'application/x-www-form-urlencoded') {
426
+ requestBody = new URLSearchParams(data).toString();
427
+ }
428
+ else {
429
+ requestBody = JSON.stringify(data);
430
+ }
421
431
  const response = yield fetch(url, {
422
432
  method: 'POST',
423
- headers: { 'Content-Type': 'application/json' },
424
- body: JSON.stringify(credentials),
433
+ headers,
434
+ body: requestBody,
425
435
  }).catch(error => {
426
436
  throw new AuthError(`Login request failed: ${error.message}`);
427
437
  });
@@ -442,8 +452,8 @@ class TokenManager {
442
452
  // Store in cookies
443
453
  storeTokens(ctx, bundle, this.config.cookies);
444
454
  // Call onLogin callback if provided
445
- if (onLogin) {
446
- yield onLogin(bundle, body, ctx);
455
+ if (options === null || options === void 0 ? void 0 : options.onLogin) {
456
+ yield options.onLogin(bundle, body, ctx);
447
457
  }
448
458
  return bundle;
449
459
  });
@@ -451,10 +461,10 @@ class TokenManager {
451
461
  /**
452
462
  * Perform token refresh
453
463
  */
454
- refresh(ctx, refreshToken) {
464
+ refresh(ctx, refreshToken, options, headers) {
455
465
  return __awaiter(this, void 0, void 0, function* () {
456
466
  try {
457
- return yield this.performRefresh(ctx, refreshToken);
467
+ return yield this.performRefresh(ctx, refreshToken, options, headers);
458
468
  }
459
469
  catch (error) {
460
470
  clearTokens(ctx, this.config.cookies);
@@ -465,13 +475,24 @@ class TokenManager {
465
475
  /**
466
476
  * Internal refresh implementation
467
477
  */
468
- performRefresh(ctx, refreshToken) {
478
+ performRefresh(ctx, refreshToken, options, extraHeaders) {
469
479
  return __awaiter(this, void 0, void 0, function* () {
470
480
  const url = this.baseURL + this.config.refresh;
481
+ const contentType = this.config.contentType || 'application/json';
482
+ const headers = Object.assign(Object.assign({ 'Content-Type': contentType }, this.config.headers), extraHeaders);
483
+ const refreshField = this.config.refreshRequestField || 'refreshToken';
484
+ const data = Object.assign(Object.assign(Object.assign({}, this.config.refreshData), options === null || options === void 0 ? void 0 : options.data), { [refreshField]: refreshToken });
485
+ let requestBody;
486
+ if (contentType === 'application/x-www-form-urlencoded') {
487
+ requestBody = new URLSearchParams(data).toString();
488
+ }
489
+ else {
490
+ requestBody = JSON.stringify(data);
491
+ }
471
492
  const response = yield fetch(url, {
472
493
  method: 'POST',
473
- headers: { 'Content-Type': 'application/json' },
474
- body: JSON.stringify({ refreshToken }),
494
+ headers,
495
+ body: requestBody,
475
496
  }).catch(error => {
476
497
  throw new AuthError(`Refresh request failed: ${error.message}`);
477
498
  });
@@ -506,7 +527,7 @@ class TokenManager {
506
527
  /**
507
528
  * Ensure valid tokens (with automatic refresh)
508
529
  */
509
- ensure(ctx) {
530
+ ensure(ctx, options, headers) {
510
531
  return __awaiter(this, void 0, void 0, function* () {
511
532
  var _a, _b, _c, _d, _e;
512
533
  const now = Math.floor(Date.now() / 1000);
@@ -518,7 +539,7 @@ class TokenManager {
518
539
  // Token expired
519
540
  if (isExpired(tokens.expiresAt, now, this.config.policy)) {
520
541
  const flightKey = this.createFlightKey(tokens.refreshToken);
521
- const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken));
542
+ const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
522
543
  if (!bundle)
523
544
  return null;
524
545
  return {
@@ -530,7 +551,7 @@ class TokenManager {
530
551
  // Proactive refresh
531
552
  if (shouldRefresh(tokens.expiresAt, now, tokens.lastRefreshAt, this.config.policy)) {
532
553
  const flightKey = this.createFlightKey(tokens.refreshToken);
533
- const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken));
554
+ const bundle = yield this.singleFlight.execute(flightKey, () => this.refresh(ctx, tokens.refreshToken, options, headers));
534
555
  if (bundle) {
535
556
  return {
536
557
  accessToken: bundle.accessToken,
@@ -669,20 +690,17 @@ function runWithContext(ctx, fn) {
669
690
  /**
670
691
  * Get current Astro context (from middleware binding or explicit)
671
692
  */
672
- function getContextStore(explicitCtx) {
693
+ function getContextStore() {
673
694
  const config = getConfig();
674
695
  const getStore = config.getContextStore;
675
696
  const context = config.context || als;
676
697
  const store = getStore
677
698
  ? getStore()
678
699
  : context.getStore();
679
- const ctx = explicitCtx || store;
680
- if (!ctx) {
681
- throw new Error('Astro context not found. Either:\n' +
682
- '1. Use api.middleware() to bind context automatically, or\n' +
683
- '2. Pass context explicitly: api.get("/path", { ctx: Astro })');
700
+ if (!store) {
701
+ throw new Error('Astro context not found. Make sure to use api.middleware() to bind context automatically.');
684
702
  }
685
- return ctx;
703
+ return store;
686
704
  }
687
705
 
688
706
  // packages/astro-tokenkit/src/utils/retry.ts
@@ -869,7 +887,7 @@ class APIClient {
869
887
  */
870
888
  request(config) {
871
889
  return __awaiter(this, void 0, void 0, function* () {
872
- const ctx = getContextStore(config.ctx);
890
+ const ctx = getContextStore();
873
891
  let attempt = 0;
874
892
  while (true) {
875
893
  attempt++;
@@ -898,7 +916,7 @@ class APIClient {
898
916
  var _a, _b, _c, _d, _e;
899
917
  // Ensure valid session (if auth is enabled)
900
918
  if (this.tokenManager && !config.skipAuth) {
901
- yield this.tokenManager.ensure(ctx);
919
+ yield this.tokenManager.ensure(ctx, config.auth, config.headers);
902
920
  }
903
921
  // Build full URL
904
922
  const fullURL = this.buildURL(config.url, config.params);
@@ -931,7 +949,7 @@ class APIClient {
931
949
  // Handle 401 (try refresh and retry once)
932
950
  if (response.status === 401 && this.tokenManager && !config.skipAuth && attempt === 1) {
933
951
  // Clear and try fresh session
934
- const session = yield this.tokenManager.ensure(ctx);
952
+ const session = yield this.tokenManager.ensure(ctx, config.auth, config.headers);
935
953
  if (session) {
936
954
  // Retry with new token
937
955
  return this.executeRequest(config, ctx, attempt + 1);
@@ -1042,48 +1060,38 @@ class APIClient {
1042
1060
  if (!this.tokenManager) {
1043
1061
  throw new Error('Auth is not configured for this client');
1044
1062
  }
1045
- let ctx;
1046
- let onLogin;
1047
- if (options && 'cookies' in options) {
1048
- ctx = options;
1049
- }
1050
- else if (options) {
1051
- const opt = options;
1052
- ctx = opt.ctx;
1053
- onLogin = opt.onLogin;
1054
- }
1055
- const context = getContextStore(ctx);
1056
- yield this.tokenManager.login(context, credentials, onLogin);
1063
+ const context = getContextStore();
1064
+ yield this.tokenManager.login(context, credentials, options);
1057
1065
  });
1058
1066
  }
1059
1067
  /**
1060
1068
  * Logout
1061
1069
  */
1062
- logout(ctx) {
1070
+ logout() {
1063
1071
  return __awaiter(this, void 0, void 0, function* () {
1064
1072
  if (!this.tokenManager) {
1065
1073
  throw new Error('Auth is not configured for this client');
1066
1074
  }
1067
- const context = getContextStore(ctx);
1075
+ const context = getContextStore();
1068
1076
  yield this.tokenManager.logout(context);
1069
1077
  });
1070
1078
  }
1071
1079
  /**
1072
1080
  * Check if authenticated
1073
1081
  */
1074
- isAuthenticated(ctx) {
1082
+ isAuthenticated() {
1075
1083
  if (!this.tokenManager)
1076
1084
  return false;
1077
- const context = getContextStore(ctx);
1085
+ const context = getContextStore();
1078
1086
  return this.tokenManager.isAuthenticated(context);
1079
1087
  }
1080
1088
  /**
1081
1089
  * Get current session
1082
1090
  */
1083
- getSession(ctx) {
1091
+ getSession() {
1084
1092
  if (!this.tokenManager)
1085
1093
  return null;
1086
- const context = getContextStore(ctx);
1094
+ const context = getContextStore();
1087
1095
  return this.tokenManager.getSession(context);
1088
1096
  }
1089
1097
  }
@@ -1157,8 +1165,10 @@ exports.createMiddleware = createMiddleware;
1157
1165
  exports.defineMiddleware = defineMiddleware;
1158
1166
  exports.formatTime = formatTime;
1159
1167
  exports.getConfig = getConfig;
1168
+ exports.getContextStore = getContextStore;
1160
1169
  exports.getTokenManager = getTokenManager;
1161
1170
  exports.parseTime = parseTime;
1171
+ exports.runWithContext = runWithContext;
1162
1172
  exports.setConfig = setConfig;
1163
1173
  exports.setTokenManager = setTokenManager;
1164
1174
  exports.tokenKit = tokenKit;