astro-tokenkit 1.0.16 → 1.0.17
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/auth/manager.js +10 -8
- package/dist/client/client.js +8 -4
- package/dist/config.js +4 -1
- package/dist/index.cjs +144 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +15 -4
- package/dist/index.js +144 -85
- package/dist/index.js.map +1 -1
- package/dist/integration.js +2 -1
- package/dist/middleware.cjs +70 -14
- package/dist/middleware.cjs.map +1 -1
- package/dist/middleware.js +70 -14
- package/dist/middleware.js.map +1 -1
- package/dist/types.d.ts +15 -4
- package/dist/types.js +10 -7
- package/dist/utils/fetch.d.ts +5 -0
- package/dist/utils/fetch.js +36 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.js +22 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -134,6 +134,10 @@ interface AuthConfig {
|
|
|
134
134
|
policy?: RefreshPolicy;
|
|
135
135
|
/** Cookie configuration */
|
|
136
136
|
cookies?: CookieConfig;
|
|
137
|
+
/** Custom fetch implementation */
|
|
138
|
+
fetch?: typeof fetch;
|
|
139
|
+
/** Dangerously ignore certificate errors (bypass SSL validation) */
|
|
140
|
+
dangerouslyIgnoreCertificateErrors?: boolean;
|
|
137
141
|
}
|
|
138
142
|
/**
|
|
139
143
|
* Refresh policy
|
|
@@ -216,6 +220,12 @@ interface ClientConfig {
|
|
|
216
220
|
setContextStore?: (ctx: TokenKitContext) => void;
|
|
217
221
|
/** Custom context runner */
|
|
218
222
|
runWithContext?: <T>(ctx: TokenKitContext, fn: () => T) => T;
|
|
223
|
+
/** Custom fetch implementation */
|
|
224
|
+
fetch?: typeof fetch;
|
|
225
|
+
/** Enable debug logging */
|
|
226
|
+
debug?: boolean;
|
|
227
|
+
/** Dangerously ignore certificate errors (bypass SSL validation) */
|
|
228
|
+
dangerouslyIgnoreCertificateErrors?: boolean;
|
|
219
229
|
}
|
|
220
230
|
/**
|
|
221
231
|
* TokenKit Global Configuration
|
|
@@ -234,25 +244,26 @@ declare class APIError extends Error {
|
|
|
234
244
|
status?: number | undefined;
|
|
235
245
|
response?: any | undefined;
|
|
236
246
|
request?: RequestConfig | undefined;
|
|
237
|
-
|
|
247
|
+
cause?: any | undefined;
|
|
248
|
+
constructor(message: string, status?: number | undefined, response?: any | undefined, request?: RequestConfig | undefined, cause?: any | undefined);
|
|
238
249
|
}
|
|
239
250
|
/**
|
|
240
251
|
* Authentication Error
|
|
241
252
|
*/
|
|
242
253
|
declare class AuthError extends APIError {
|
|
243
|
-
constructor(message: string, status?: number, response?: any, request?: RequestConfig);
|
|
254
|
+
constructor(message: string, status?: number, response?: any, request?: RequestConfig, cause?: any);
|
|
244
255
|
}
|
|
245
256
|
/**
|
|
246
257
|
* Network Error
|
|
247
258
|
*/
|
|
248
259
|
declare class NetworkError extends APIError {
|
|
249
|
-
constructor(message: string, request?: RequestConfig);
|
|
260
|
+
constructor(message: string, request?: RequestConfig, cause?: any);
|
|
250
261
|
}
|
|
251
262
|
/**
|
|
252
263
|
* Timeout Error
|
|
253
264
|
*/
|
|
254
265
|
declare class TimeoutError extends APIError {
|
|
255
|
-
constructor(message: string, request?: RequestConfig);
|
|
266
|
+
constructor(message: string, request?: RequestConfig, cause?: any);
|
|
256
267
|
}
|
|
257
268
|
|
|
258
269
|
/**
|
package/dist/index.js
CHANGED
|
@@ -37,20 +37,23 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
37
37
|
* API Error
|
|
38
38
|
*/
|
|
39
39
|
class APIError extends Error {
|
|
40
|
-
constructor(message, status, response, request) {
|
|
40
|
+
constructor(message, status, response, request, cause) {
|
|
41
41
|
super(message);
|
|
42
42
|
this.status = status;
|
|
43
43
|
this.response = response;
|
|
44
44
|
this.request = request;
|
|
45
|
+
this.cause = cause;
|
|
45
46
|
this.name = 'APIError';
|
|
47
|
+
if (cause && !this.cause)
|
|
48
|
+
this.cause = cause;
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
/**
|
|
49
52
|
* Authentication Error
|
|
50
53
|
*/
|
|
51
54
|
class AuthError extends APIError {
|
|
52
|
-
constructor(message, status, response, request) {
|
|
53
|
-
super(message, status, response, request);
|
|
55
|
+
constructor(message, status, response, request, cause) {
|
|
56
|
+
super(message, status, response, request, cause);
|
|
54
57
|
this.name = 'AuthError';
|
|
55
58
|
}
|
|
56
59
|
}
|
|
@@ -58,8 +61,8 @@ class AuthError extends APIError {
|
|
|
58
61
|
* Network Error
|
|
59
62
|
*/
|
|
60
63
|
class NetworkError extends APIError {
|
|
61
|
-
constructor(message, request) {
|
|
62
|
-
super(message, undefined, undefined, request);
|
|
64
|
+
constructor(message, request, cause) {
|
|
65
|
+
super(message, undefined, undefined, request, cause);
|
|
63
66
|
this.name = 'NetworkError';
|
|
64
67
|
}
|
|
65
68
|
}
|
|
@@ -67,8 +70,8 @@ class NetworkError extends APIError {
|
|
|
67
70
|
* Timeout Error
|
|
68
71
|
*/
|
|
69
72
|
class TimeoutError extends APIError {
|
|
70
|
-
constructor(message, request) {
|
|
71
|
-
super(message, undefined, undefined, request);
|
|
73
|
+
constructor(message, request, cause) {
|
|
74
|
+
super(message, undefined, undefined, request, cause);
|
|
72
75
|
this.name = 'TimeoutError';
|
|
73
76
|
}
|
|
74
77
|
}
|
|
@@ -394,6 +397,122 @@ function isExpired(expiresAt, now, policy = {}) {
|
|
|
394
397
|
return now + clockSkew > expiresAt;
|
|
395
398
|
}
|
|
396
399
|
|
|
400
|
+
// packages/astro-tokenkit/src/utils/fetch.ts
|
|
401
|
+
/**
|
|
402
|
+
* Perform a fetch request with optional certificate validation bypass
|
|
403
|
+
*/
|
|
404
|
+
function safeFetch(url, init, config) {
|
|
405
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
406
|
+
const fetchFn = config.fetch || fetch;
|
|
407
|
+
const fetchOptions = Object.assign({}, init);
|
|
408
|
+
if (config.dangerouslyIgnoreCertificateErrors && typeof process !== 'undefined') {
|
|
409
|
+
// In Node.js environment
|
|
410
|
+
try {
|
|
411
|
+
// Try to use undici Agent if available (it is built-in in Node 18+)
|
|
412
|
+
// However, we might need to import it if we want to create an Agent.
|
|
413
|
+
// Since we don't want to depend on undici in package.json, we use dynamic import.
|
|
414
|
+
// But wait, undici's Agent is what we need.
|
|
415
|
+
// As a fallback and most reliable way for self-signed certs in Node without extra deps:
|
|
416
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
417
|
+
// NOTE: This affects the whole process. We should ideally only do this if it's not already 0.
|
|
418
|
+
// But for a dev tool / specialized library, it's often what's needed.
|
|
419
|
+
}
|
|
420
|
+
catch (e) {
|
|
421
|
+
// Ignore
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return fetchFn(url, fetchOptions);
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// packages/astro-tokenkit/src/config.ts
|
|
429
|
+
const CONFIG_KEY = Symbol.for('astro-tokenkit.config');
|
|
430
|
+
const MANAGER_KEY = Symbol.for('astro-tokenkit.manager');
|
|
431
|
+
const globalStorage = globalThis;
|
|
432
|
+
// Initialize global storage if not present
|
|
433
|
+
if (!globalStorage[CONFIG_KEY]) {
|
|
434
|
+
globalStorage[CONFIG_KEY] = {
|
|
435
|
+
runWithContext: undefined,
|
|
436
|
+
getContextStore: undefined,
|
|
437
|
+
setContextStore: undefined,
|
|
438
|
+
baseURL: "",
|
|
439
|
+
debug: false,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Set configuration
|
|
444
|
+
*/
|
|
445
|
+
function setConfig(userConfig) {
|
|
446
|
+
var _a, _b;
|
|
447
|
+
const currentConfig = globalStorage[CONFIG_KEY];
|
|
448
|
+
const finalConfig = Object.assign(Object.assign({}, currentConfig), userConfig);
|
|
449
|
+
// Validate that getter and setter are defined together
|
|
450
|
+
if ((finalConfig.getContextStore && !finalConfig.setContextStore) ||
|
|
451
|
+
(!finalConfig.getContextStore && finalConfig.setContextStore)) {
|
|
452
|
+
throw new Error("[TokenKit] getContextStore and setContextStore must be defined together.");
|
|
453
|
+
}
|
|
454
|
+
globalStorage[CONFIG_KEY] = finalConfig;
|
|
455
|
+
// Re-initialize global token manager if auth changed
|
|
456
|
+
if (finalConfig.auth) {
|
|
457
|
+
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 });
|
|
458
|
+
globalStorage[MANAGER_KEY] = new TokenManager(authConfig, finalConfig.baseURL);
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
globalStorage[MANAGER_KEY] = undefined;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Get current configuration
|
|
466
|
+
*/
|
|
467
|
+
function getConfig() {
|
|
468
|
+
return globalStorage[CONFIG_KEY];
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Get global token manager
|
|
472
|
+
*/
|
|
473
|
+
function getTokenManager() {
|
|
474
|
+
return globalStorage[MANAGER_KEY];
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Set global token manager (mainly for testing)
|
|
478
|
+
*/
|
|
479
|
+
function setTokenManager(manager) {
|
|
480
|
+
globalStorage[MANAGER_KEY] = manager;
|
|
481
|
+
}
|
|
482
|
+
// Handle injected configuration from Astro integration
|
|
483
|
+
try {
|
|
484
|
+
// @ts-ignore
|
|
485
|
+
const injectedConfig = typeof __TOKENKIT_CONFIG__ !== 'undefined' ? __TOKENKIT_CONFIG__ : undefined;
|
|
486
|
+
if (injectedConfig) {
|
|
487
|
+
setConfig(injectedConfig);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
catch (e) {
|
|
491
|
+
// Ignore errors in environments where __TOKENKIT_CONFIG__ might be restricted
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Logger utility that respects the debug flag in the configuration
|
|
496
|
+
*/
|
|
497
|
+
const logger = {
|
|
498
|
+
debug: (message, ...args) => {
|
|
499
|
+
if (getConfig().debug) {
|
|
500
|
+
console.debug(message, ...args);
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
info: (message, ...args) => {
|
|
504
|
+
if (getConfig().debug) {
|
|
505
|
+
console.log(message, ...args);
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
warn: (message, ...args) => {
|
|
509
|
+
console.warn(message, ...args);
|
|
510
|
+
},
|
|
511
|
+
error: (message, ...args) => {
|
|
512
|
+
console.error(message, ...args);
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
|
|
397
516
|
// packages/astro-tokenkit/src/auth/manager.ts
|
|
398
517
|
/**
|
|
399
518
|
* Single-flight refresh manager
|
|
@@ -450,14 +569,14 @@ class TokenManager {
|
|
|
450
569
|
}
|
|
451
570
|
let response;
|
|
452
571
|
try {
|
|
453
|
-
response = yield
|
|
572
|
+
response = yield safeFetch(url, {
|
|
454
573
|
method: 'POST',
|
|
455
574
|
headers,
|
|
456
575
|
body: requestBody,
|
|
457
|
-
});
|
|
576
|
+
}, this.config);
|
|
458
577
|
}
|
|
459
578
|
catch (error) {
|
|
460
|
-
const authError = new AuthError(`Login request failed: ${error.message}
|
|
579
|
+
const authError = new AuthError(`Login request failed: ${error.message}`, undefined, undefined, undefined, error);
|
|
461
580
|
if (options === null || options === void 0 ? void 0 : options.onError)
|
|
462
581
|
yield options.onError(authError, ctx);
|
|
463
582
|
throw authError;
|
|
@@ -531,14 +650,14 @@ class TokenManager {
|
|
|
531
650
|
}
|
|
532
651
|
let response;
|
|
533
652
|
try {
|
|
534
|
-
response = yield
|
|
653
|
+
response = yield safeFetch(url, {
|
|
535
654
|
method: 'POST',
|
|
536
655
|
headers,
|
|
537
656
|
body: requestBody,
|
|
538
|
-
});
|
|
657
|
+
}, this.config);
|
|
539
658
|
}
|
|
540
659
|
catch (error) {
|
|
541
|
-
throw new AuthError(`Refresh request failed: ${error.message}
|
|
660
|
+
throw new AuthError(`Refresh request failed: ${error.message}`, undefined, undefined, undefined, error);
|
|
542
661
|
}
|
|
543
662
|
if (!response.ok) {
|
|
544
663
|
// 401/403 = invalid refresh token
|
|
@@ -636,11 +755,11 @@ class TokenManager {
|
|
|
636
755
|
const injectFn = (_a = this.config.injectToken) !== null && _a !== void 0 ? _a : ((token, type) => `${type !== null && type !== void 0 ? type : 'Bearer'} ${token}`);
|
|
637
756
|
headers['Authorization'] = injectFn(session.accessToken, session.tokenType);
|
|
638
757
|
}
|
|
639
|
-
yield
|
|
758
|
+
yield safeFetch(url, { method: 'POST', headers }, this.config);
|
|
640
759
|
}
|
|
641
760
|
catch (error) {
|
|
642
761
|
// Ignore logout endpoint errors
|
|
643
|
-
|
|
762
|
+
logger.debug('[TokenKit] Logout endpoint failed:', error);
|
|
644
763
|
}
|
|
645
764
|
}
|
|
646
765
|
clearTokens(ctx, this.config.cookies);
|
|
@@ -686,69 +805,6 @@ class TokenManager {
|
|
|
686
805
|
}
|
|
687
806
|
}
|
|
688
807
|
|
|
689
|
-
// packages/astro-tokenkit/src/config.ts
|
|
690
|
-
const CONFIG_KEY = Symbol.for('astro-tokenkit.config');
|
|
691
|
-
const MANAGER_KEY = Symbol.for('astro-tokenkit.manager');
|
|
692
|
-
const globalStorage = globalThis;
|
|
693
|
-
// Initialize global storage if not present
|
|
694
|
-
if (!globalStorage[CONFIG_KEY]) {
|
|
695
|
-
globalStorage[CONFIG_KEY] = {
|
|
696
|
-
runWithContext: undefined,
|
|
697
|
-
getContextStore: undefined,
|
|
698
|
-
setContextStore: undefined,
|
|
699
|
-
baseURL: "",
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Set configuration
|
|
704
|
-
*/
|
|
705
|
-
function setConfig(userConfig) {
|
|
706
|
-
const currentConfig = globalStorage[CONFIG_KEY];
|
|
707
|
-
const finalConfig = Object.assign(Object.assign({}, currentConfig), userConfig);
|
|
708
|
-
// Validate that getter and setter are defined together
|
|
709
|
-
if ((finalConfig.getContextStore && !finalConfig.setContextStore) ||
|
|
710
|
-
(!finalConfig.getContextStore && finalConfig.setContextStore)) {
|
|
711
|
-
throw new Error("[TokenKit] getContextStore and setContextStore must be defined together.");
|
|
712
|
-
}
|
|
713
|
-
globalStorage[CONFIG_KEY] = finalConfig;
|
|
714
|
-
// Re-initialize global token manager if auth changed
|
|
715
|
-
if (finalConfig.auth) {
|
|
716
|
-
globalStorage[MANAGER_KEY] = new TokenManager(finalConfig.auth, finalConfig.baseURL);
|
|
717
|
-
}
|
|
718
|
-
else {
|
|
719
|
-
globalStorage[MANAGER_KEY] = undefined;
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
/**
|
|
723
|
-
* Get current configuration
|
|
724
|
-
*/
|
|
725
|
-
function getConfig() {
|
|
726
|
-
return globalStorage[CONFIG_KEY];
|
|
727
|
-
}
|
|
728
|
-
/**
|
|
729
|
-
* Get global token manager
|
|
730
|
-
*/
|
|
731
|
-
function getTokenManager() {
|
|
732
|
-
return globalStorage[MANAGER_KEY];
|
|
733
|
-
}
|
|
734
|
-
/**
|
|
735
|
-
* Set global token manager (mainly for testing)
|
|
736
|
-
*/
|
|
737
|
-
function setTokenManager(manager) {
|
|
738
|
-
globalStorage[MANAGER_KEY] = manager;
|
|
739
|
-
}
|
|
740
|
-
// Handle injected configuration from Astro integration
|
|
741
|
-
try {
|
|
742
|
-
// @ts-ignore
|
|
743
|
-
const injectedConfig = typeof __TOKENKIT_CONFIG__ !== 'undefined' ? __TOKENKIT_CONFIG__ : undefined;
|
|
744
|
-
if (injectedConfig) {
|
|
745
|
-
setConfig(injectedConfig);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
catch (e) {
|
|
749
|
-
// Ignore errors in environments where __TOKENKIT_CONFIG__ might be restricted
|
|
750
|
-
}
|
|
751
|
-
|
|
752
808
|
// packages/astro-tokenkit/src/client/context.ts
|
|
753
809
|
/**
|
|
754
810
|
* Async local storage for Astro context
|
|
@@ -845,7 +901,7 @@ function createMiddleware() {
|
|
|
845
901
|
else if (config.context) {
|
|
846
902
|
contextStrategy = 'custom (external AsyncLocalStorage)';
|
|
847
903
|
}
|
|
848
|
-
|
|
904
|
+
logger.debug(`[TokenKit] Middleware initialized (auth: ${authStatus}, context: ${contextStrategy})`);
|
|
849
905
|
globalStorage[LOGGED_KEY] = true;
|
|
850
906
|
}
|
|
851
907
|
const runLogic = () => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -857,7 +913,7 @@ function createMiddleware() {
|
|
|
857
913
|
}
|
|
858
914
|
catch (error) {
|
|
859
915
|
// Log only the message to avoid leaking sensitive data in the error object
|
|
860
|
-
|
|
916
|
+
logger.debug('[TokenKit] Automatic token rotation failed:', error.message || error);
|
|
861
917
|
}
|
|
862
918
|
}
|
|
863
919
|
return next();
|
|
@@ -902,6 +958,7 @@ class APIClient {
|
|
|
902
958
|
* Get token manager
|
|
903
959
|
*/
|
|
904
960
|
get tokenManager() {
|
|
961
|
+
var _a, _b;
|
|
905
962
|
const config = this.config;
|
|
906
963
|
if (!config.auth)
|
|
907
964
|
return undefined;
|
|
@@ -917,7 +974,9 @@ class APIClient {
|
|
|
917
974
|
if (!this._localTokenManager ||
|
|
918
975
|
this._lastUsedAuth !== config.auth ||
|
|
919
976
|
this._lastUsedBaseURL !== config.baseURL) {
|
|
920
|
-
|
|
977
|
+
// Merge client-level fetch and SSL settings into auth config
|
|
978
|
+
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 });
|
|
979
|
+
this._localTokenManager = new TokenManager(authConfig, config.baseURL);
|
|
921
980
|
this._lastUsedAuth = config.auth;
|
|
922
981
|
this._lastUsedBaseURL = config.baseURL;
|
|
923
982
|
}
|
|
@@ -1034,7 +1093,7 @@ class APIClient {
|
|
|
1034
1093
|
const controller = new AbortController();
|
|
1035
1094
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
1036
1095
|
try {
|
|
1037
|
-
const response = yield
|
|
1096
|
+
const response = yield safeFetch(fullURL, Object.assign(Object.assign({}, init), { signal: controller.signal }), this.config);
|
|
1038
1097
|
clearTimeout(timeoutId);
|
|
1039
1098
|
// Handle 401 (try refresh and retry once)
|
|
1040
1099
|
if (response.status === 401 && this.tokenManager && !config.skipAuth && attempt === 1) {
|
|
@@ -1067,12 +1126,12 @@ class APIClient {
|
|
|
1067
1126
|
}
|
|
1068
1127
|
// Transform errors
|
|
1069
1128
|
if (error instanceof Error && error.name === 'AbortError') {
|
|
1070
|
-
throw new TimeoutError(`Request timeout after ${timeout}ms`, requestConfig);
|
|
1129
|
+
throw new TimeoutError(`Request timeout after ${timeout}ms`, requestConfig, error);
|
|
1071
1130
|
}
|
|
1072
1131
|
if (error instanceof APIError) {
|
|
1073
1132
|
throw error;
|
|
1074
1133
|
}
|
|
1075
|
-
throw new NetworkError(error.message, requestConfig);
|
|
1134
|
+
throw new NetworkError(error.message, requestConfig, error);
|
|
1076
1135
|
}
|
|
1077
1136
|
});
|
|
1078
1137
|
}
|
|
@@ -1268,7 +1327,7 @@ function tokenKit(config) {
|
|
|
1268
1327
|
order: 'pre'
|
|
1269
1328
|
});
|
|
1270
1329
|
}
|
|
1271
|
-
|
|
1330
|
+
logger.debug('[TokenKit] Integration initialized');
|
|
1272
1331
|
},
|
|
1273
1332
|
},
|
|
1274
1333
|
};
|