@adonis-agora/authkit-client 0.18.1 → 0.18.2
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.
|
@@ -23,6 +23,8 @@ function readParked(value) {
|
|
|
23
23
|
export class AuthkitClientManager {
|
|
24
24
|
config;
|
|
25
25
|
#resolverCache;
|
|
26
|
+
/** Mapa de promessas de refresh in-flight por sessionId (dedup thundering herd). */
|
|
27
|
+
#refreshPromises = new Map();
|
|
26
28
|
constructor(config) {
|
|
27
29
|
this.config = config;
|
|
28
30
|
}
|
|
@@ -72,15 +74,28 @@ export class AuthkitClientManager {
|
|
|
72
74
|
// Sem expiresAt conhecido, não renova proativamente (evita refresh a cada request).
|
|
73
75
|
if (!tokenSet.expiresAt || tokenSet.expiresAt - now() > REFRESH_SKEW_MS)
|
|
74
76
|
return;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
// Dedup: se já há um refresh in-flight pra esta sessão, espera ele ao invés de
|
|
78
|
+
// disparar outro. O refresh token ROTACIONA — N requests concorrentes chegando
|
|
79
|
+
// juntos fariam N refreshes + N-1 falhas com refresh token já inválido.
|
|
80
|
+
const sessionId = session.sessionId;
|
|
81
|
+
if (sessionId) {
|
|
82
|
+
const pending = this.#refreshPromises.get(sessionId);
|
|
83
|
+
if (pending) {
|
|
84
|
+
await pending.catch(() => { });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Promise que SEMPRE resolve — o catch silencioso mantém o TokenSet original
|
|
89
|
+
// em caso de falha, igual ao comportamento do maybeRefresh original.
|
|
90
|
+
const promise = refreshTokens({
|
|
91
|
+
issuer: this.config.issuer,
|
|
92
|
+
clientId: this.config.clientId,
|
|
93
|
+
clientSecret: this.config.clientSecret,
|
|
94
|
+
refreshToken: tokenSet.refreshToken,
|
|
95
|
+
fetchImpl: deps.fetchImpl,
|
|
96
|
+
resilience: this.config.resilience,
|
|
97
|
+
})
|
|
98
|
+
.then((next) => {
|
|
84
99
|
session.put(this.config.sessionKey, {
|
|
85
100
|
idToken: next.idToken || tokenSet.idToken,
|
|
86
101
|
accessToken: next.accessToken,
|
|
@@ -88,10 +103,15 @@ export class AuthkitClientManager {
|
|
|
88
103
|
expiresAt: next.expiresAt,
|
|
89
104
|
impersonationBinding: tokenSet.impersonationBinding,
|
|
90
105
|
});
|
|
91
|
-
}
|
|
92
|
-
|
|
106
|
+
})
|
|
107
|
+
.catch(() => {
|
|
93
108
|
// Renovação falhou — deixa o TokenSet como está; o resolver decide a sessão.
|
|
94
|
-
}
|
|
109
|
+
});
|
|
110
|
+
if (sessionId)
|
|
111
|
+
this.#refreshPromises.set(sessionId, promise);
|
|
112
|
+
await promise;
|
|
113
|
+
if (sessionId)
|
|
114
|
+
this.#refreshPromises.delete(sessionId);
|
|
95
115
|
}
|
|
96
116
|
/**
|
|
97
117
|
* Recebe o POST `application/x-www-form-urlencoded` de OIDC Back-Channel Logout. Lê o
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adonis-agora/authkit-client",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.2",
|
|
4
4
|
"description": "AdonisJS OIDC/OAuth2 relying-party (client) toolkit: session-based authentication against an OpenID Connect identity provider, with JWT/PAT user resolvers and OpenTelemetry metrics.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "dudousxd",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"ioredis-mock": "8.13.1",
|
|
97
97
|
"@types/node": "25.9.1",
|
|
98
98
|
"typescript": "6.0.3",
|
|
99
|
-
"@adonis-agora/authkit-server": "0.61.
|
|
99
|
+
"@adonis-agora/authkit-server": "0.61.3"
|
|
100
100
|
},
|
|
101
101
|
"scripts": {
|
|
102
102
|
"build": "tsc && node -e \"require('node:fs').cpSync('stubs','build/stubs',{recursive:true,filter:(s)=>!s.endsWith('.ts')})\"",
|