@hubex/mcp 0.6.20260910 → 0.8.0

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/CONNECTING.md CHANGED
@@ -92,6 +92,8 @@ npm run build
92
92
  > покажут поле ввода; остальным нужно вызвать инструмент `hubex_set_token` и
93
93
  > передать токен в него. По токену запрашивается refresh, дальше сессия
94
94
  > продлевается сама; после перезапуска сервера токен спрашивается заново.
95
+ > Если HubEx отверг токен (ошибка 401), следующий запрос получит новый — по
96
+ > refresh, а если не выйдет, сервер снова попросит токен.
95
97
 
96
98
  > Сервисный токен выпускается один раз администратором:
97
99
  > `POST /fsm/AUTHZ/ServiceTokens` с Bearer и полномочием `ServiceTokenAdd`, тело — массив id
package/dist/auth.js CHANGED
@@ -51,6 +51,11 @@ class RefreshingAuth {
51
51
  prompter;
52
52
  accessToken;
53
53
  accessExp; // seconds since epoch
54
+ /**
55
+ * Set by `invalidate`. The rejected token is kept rather than dropped: `renew`
56
+ * still has to send it as `accessJwt` to preserve the token lifetime.
57
+ */
58
+ accessRejected = false;
54
59
  refreshToken;
55
60
  refreshExp; // seconds since epoch
56
61
  tenantId;
@@ -74,8 +79,12 @@ class RefreshingAuth {
74
79
  this.absorb({ access_token: trimmed });
75
80
  await this.acquireRefreshToken();
76
81
  }
82
+ invalidate(token) {
83
+ if (token === this.accessToken)
84
+ this.accessRejected = true;
85
+ }
77
86
  async getAccessToken() {
78
- if (this.accessToken && !isExpired(this.accessExp)) {
87
+ if (this.accessToken && !this.accessRejected && !isExpired(this.accessExp)) {
79
88
  return this.accessToken;
80
89
  }
81
90
  // De-duplicate concurrent acquisitions.
@@ -175,7 +184,12 @@ class RefreshingAuth {
175
184
  }
176
185
  /**
177
186
  * A service-token login never carries a refresh token, so ask for one.
178
- * Best-effort: without it we simply re-authenticate when the access token expires.
187
+ * Best-effort for "service"/"login": credentials were already proven by the
188
+ * preceding login call, so a failure here just means retrying at expiry.
189
+ * Fatal for "token": the user-typed token is otherwise never round-tripped
190
+ * against the server, so this request is the only thing that can catch a
191
+ * token issued for the wrong environment (dev/stg/prod) — swallowing it
192
+ * would report success on a token that doesn't actually work.
179
193
  */
180
194
  async acquireRefreshToken() {
181
195
  try {
@@ -186,6 +200,8 @@ class RefreshingAuth {
186
200
  this.absorb(result);
187
201
  }
188
202
  catch (err) {
203
+ if (this.config.authMode === "token")
204
+ throw err;
189
205
  console.error("[hubex-mcp] could not obtain a refresh token; will re-authenticate on expiry: " +
190
206
  `${err.message}`);
191
207
  }
@@ -201,7 +217,13 @@ class RefreshingAuth {
201
217
  const res = await fetch(url, init);
202
218
  if (!res.ok) {
203
219
  const body = await res.text().catch(() => "");
204
- throw new Error(`${init.method ?? "GET"} ${url} failed (HTTP ${res.status}): ${body.slice(0, 500)}`);
220
+ let message = `${init.method ?? "GET"} ${url} failed (HTTP ${res.status}): ${body.slice(0, 500)}`;
221
+ if (res.status === 401 || res.status === 403) {
222
+ message +=
223
+ ` Сейчас выбрано окружение HUBEX_ENV=${this.config.env}. Если токен получен в другом ` +
224
+ `окружении (dev/stg/prod), авторизация не пройдёт — проверь, что токен именно из ${this.config.env}.`;
225
+ }
226
+ throw new Error(message);
205
227
  }
206
228
  return (await res.json());
207
229
  }
@@ -209,6 +231,7 @@ class RefreshingAuth {
209
231
  absorb(result) {
210
232
  if (result.access_token) {
211
233
  this.accessToken = result.access_token;
234
+ this.accessRejected = false;
212
235
  const claims = decodeJwt(result.access_token);
213
236
  this.accessExp = claims?.exp;
214
237
  if (!this.tenantId)