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 +24 -3
- package/dist/auth/manager.d.ts +4 -4
- package/dist/auth/manager.js +34 -13
- package/dist/client/client.d.ts +5 -5
- package/dist/client/client.js +11 -21
- package/dist/client/context-shared.d.ts +1 -1
- package/dist/client/context-shared.js +2 -8
- package/dist/client/context.d.ts +2 -2
- package/dist/client/context.js +6 -9
- package/dist/index.cjs +51 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +39 -13
- package/dist/index.js +50 -42
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +22 -5
- package/package.json +1 -1
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
|
|
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
|
-
|
|
168
|
+
import { runWithContext } from 'astro-tokenkit';
|
|
169
|
+
|
|
170
|
+
const data = await runWithContext(Astro, () => api.get('/data'));
|
|
150
171
|
```
|
|
151
172
|
|
|
152
173
|
### Interceptors
|
package/dist/auth/manager.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TokenBundle, Session, AuthConfig, TokenKitContext,
|
|
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,
|
|
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
|
*/
|
package/dist/auth/manager.js
CHANGED
|
@@ -52,13 +52,23 @@ export class TokenManager {
|
|
|
52
52
|
/**
|
|
53
53
|
* Perform login
|
|
54
54
|
*/
|
|
55
|
-
login(ctx, credentials,
|
|
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
|
|
61
|
-
body:
|
|
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
|
|
111
|
-
body:
|
|
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,
|
package/dist/client/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientConfig, RequestConfig, RequestOptions, Session,
|
|
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
|
|
68
|
+
login(credentials: any, options?: LoginOptions): Promise<void>;
|
|
69
69
|
/**
|
|
70
70
|
* Logout
|
|
71
71
|
*/
|
|
72
|
-
logout(
|
|
72
|
+
logout(): Promise<void>;
|
|
73
73
|
/**
|
|
74
74
|
* Check if authenticated
|
|
75
75
|
*/
|
|
76
|
-
isAuthenticated(
|
|
76
|
+
isAuthenticated(): boolean;
|
|
77
77
|
/**
|
|
78
78
|
* Get current session
|
|
79
79
|
*/
|
|
80
|
-
getSession(
|
|
80
|
+
getSession(): Session | null;
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
83
83
|
* Global API client instance.
|
package/dist/client/client.js
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
292
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
310
|
+
isAuthenticated() {
|
|
321
311
|
if (!this.tokenManager)
|
|
322
312
|
return false;
|
|
323
|
-
const context = getContextStore(
|
|
313
|
+
const context = getContextStore();
|
|
324
314
|
return this.tokenManager.isAuthenticated(context);
|
|
325
315
|
}
|
|
326
316
|
/**
|
|
327
317
|
* Get current session
|
|
328
318
|
*/
|
|
329
|
-
getSession(
|
|
319
|
+
getSession() {
|
|
330
320
|
if (!this.tokenManager)
|
|
331
321
|
return null;
|
|
332
|
-
const context = getContextStore(
|
|
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(
|
|
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(
|
|
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.
|
|
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)
|
package/dist/client/context.d.ts
CHANGED
|
@@ -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(
|
|
9
|
+
export declare function getContextStore(): TokenKitContext;
|
|
10
10
|
/**
|
|
11
11
|
* Check if context is available
|
|
12
12
|
*/
|
|
13
|
-
export declare function hasContext(
|
|
13
|
+
export declare function hasContext(): boolean;
|
package/dist/client/context.js
CHANGED
|
@@ -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(
|
|
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
|
-
|
|
30
|
-
|
|
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
|
|
32
|
+
return store;
|
|
36
33
|
}
|
|
37
34
|
/**
|
|
38
35
|
* Check if context is available
|
|
39
36
|
*/
|
|
40
|
-
export function hasContext(
|
|
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 !!
|
|
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,
|
|
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
|
|
424
|
-
body:
|
|
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
|
|
474
|
-
body:
|
|
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(
|
|
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
|
-
|
|
680
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
1046
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
1082
|
+
isAuthenticated() {
|
|
1075
1083
|
if (!this.tokenManager)
|
|
1076
1084
|
return false;
|
|
1077
|
-
const context = getContextStore(
|
|
1085
|
+
const context = getContextStore();
|
|
1078
1086
|
return this.tokenManager.isAuthenticated(context);
|
|
1079
1087
|
}
|
|
1080
1088
|
/**
|
|
1081
1089
|
* Get current session
|
|
1082
1090
|
*/
|
|
1083
|
-
getSession(
|
|
1091
|
+
getSession() {
|
|
1084
1092
|
if (!this.tokenManager)
|
|
1085
1093
|
return null;
|
|
1086
|
-
const context = getContextStore(
|
|
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;
|