mitra-interactions-sdk 1.0.60-beta.27 → 1.0.60-beta.29
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/index.js +107 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +107 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -279,7 +279,15 @@ async function refreshTokenSilently(authUrl, _projectId) {
|
|
|
279
279
|
if (!refreshToken) {
|
|
280
280
|
throw new Error("refreshToken n\xE3o dispon\xEDvel para renova\xE7\xE3o. Fa\xE7a login novamente.");
|
|
281
281
|
}
|
|
282
|
+
if (!hasAppScope(refreshToken)) {
|
|
283
|
+
clearRefreshToken();
|
|
284
|
+
throw new Error("refreshToken sem escopo de app (sess\xE3o do console) \u2014 descartado. Fa\xE7a loginMitra({ projectId }) novamente.");
|
|
285
|
+
}
|
|
282
286
|
const data = await postBffAuth(buildBffAuthEndpoint(authUrl, "/refresh-token"), { refreshToken });
|
|
287
|
+
if (!hasAppScope(data.token)) {
|
|
288
|
+
clearRefreshToken();
|
|
289
|
+
throw new Error("refresh retornou token sem escopo de app \u2014 rejeitado. Fa\xE7a loginMitra({ projectId }) novamente.");
|
|
290
|
+
}
|
|
283
291
|
return {
|
|
284
292
|
token: data.token,
|
|
285
293
|
// Refresh não muda a base — mantém o authUrl (gateway).
|
|
@@ -346,20 +354,23 @@ async function handleResponse(response) {
|
|
|
346
354
|
}
|
|
347
355
|
return data;
|
|
348
356
|
}
|
|
357
|
+
function withFreshAuth(init) {
|
|
358
|
+
const config = getConfig();
|
|
359
|
+
const headers = { ...init.headers };
|
|
360
|
+
if (config.token) headers["Authorization"] = formatToken(config.token);
|
|
361
|
+
return { ...init, headers };
|
|
362
|
+
}
|
|
349
363
|
async function fetchWithRefresh(url, init) {
|
|
350
364
|
const fetchFn = getFetch2();
|
|
365
|
+
if (isTokenExpiring()) {
|
|
366
|
+
const refreshed = await tryRefreshToken();
|
|
367
|
+
if (refreshed) init = withFreshAuth(init);
|
|
368
|
+
}
|
|
351
369
|
const response = await fetchFn(url, init);
|
|
352
370
|
if (response.status === 401) {
|
|
353
371
|
const refreshed = await tryRefreshToken();
|
|
354
372
|
if (refreshed) {
|
|
355
|
-
const
|
|
356
|
-
const oldHeaders = init.headers;
|
|
357
|
-
if (oldHeaders) {
|
|
358
|
-
for (const [k, v] of Object.entries(oldHeaders)) {
|
|
359
|
-
if (k !== "Authorization") newHeaders[k] = v;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
const retryResponse = await fetchFn(url, { ...init, headers: newHeaders });
|
|
373
|
+
const retryResponse = await fetchFn(url, withFreshAuth(init));
|
|
363
374
|
return handleResponse(retryResponse);
|
|
364
375
|
}
|
|
365
376
|
}
|
|
@@ -650,8 +661,25 @@ var AgentTaskSession = class {
|
|
|
650
661
|
if (!this._taskId) {
|
|
651
662
|
return Promise.reject(new Error("AgentTaskSession: sem taskId \u2014 task ainda n\xE3o criada."));
|
|
652
663
|
}
|
|
653
|
-
|
|
654
|
-
|
|
664
|
+
this._wsConnectPromise = (async () => {
|
|
665
|
+
try {
|
|
666
|
+
if (isTokenExpiring()) await tryRefreshToken();
|
|
667
|
+
try {
|
|
668
|
+
return await this._connectWs(this._taskId);
|
|
669
|
+
} catch (err) {
|
|
670
|
+
const refreshed = await tryRefreshToken();
|
|
671
|
+
if (!refreshed) throw err;
|
|
672
|
+
return await this._connectWs(this._taskId);
|
|
673
|
+
}
|
|
674
|
+
} finally {
|
|
675
|
+
this._wsConnectPromise = null;
|
|
676
|
+
}
|
|
677
|
+
})();
|
|
678
|
+
return this._wsConnectPromise;
|
|
679
|
+
}
|
|
680
|
+
_connectWs(taskId) {
|
|
681
|
+
const url = getTaskWsUrl(taskId);
|
|
682
|
+
return new Promise((resolve, reject) => {
|
|
655
683
|
const socket = new WebSocket(url);
|
|
656
684
|
let opened = false;
|
|
657
685
|
const timer = setTimeout(() => {
|
|
@@ -660,7 +688,6 @@ var AgentTaskSession = class {
|
|
|
660
688
|
socket.close();
|
|
661
689
|
} catch (e) {
|
|
662
690
|
}
|
|
663
|
-
this._wsConnectPromise = null;
|
|
664
691
|
reject(new Error("Agent Chat: timeout ao conectar no WebSocket da task"));
|
|
665
692
|
}
|
|
666
693
|
}, 15e3);
|
|
@@ -668,13 +695,11 @@ var AgentTaskSession = class {
|
|
|
668
695
|
opened = true;
|
|
669
696
|
clearTimeout(timer);
|
|
670
697
|
this._ws = socket;
|
|
671
|
-
this._wsConnectPromise = null;
|
|
672
698
|
resolve(socket);
|
|
673
699
|
};
|
|
674
700
|
socket.onerror = () => {
|
|
675
701
|
if (!opened) {
|
|
676
702
|
clearTimeout(timer);
|
|
677
|
-
this._wsConnectPromise = null;
|
|
678
703
|
reject(new Error("Agent Chat: erro ao conectar no WebSocket da task"));
|
|
679
704
|
}
|
|
680
705
|
};
|
|
@@ -691,7 +716,6 @@ var AgentTaskSession = class {
|
|
|
691
716
|
this._handleWsEvent(msg);
|
|
692
717
|
};
|
|
693
718
|
});
|
|
694
|
-
return this._wsConnectPromise;
|
|
695
719
|
}
|
|
696
720
|
// ── Eventos do stream (WsOutboundMessage { type, payload, timestamp }) ──
|
|
697
721
|
_handleWsEvent(msg) {
|
|
@@ -810,8 +834,12 @@ function getGatewayOrigin() {
|
|
|
810
834
|
return new URL(config.baseURL).origin;
|
|
811
835
|
}
|
|
812
836
|
function getTaskWsUrl(taskId) {
|
|
837
|
+
const token = getRawToken();
|
|
838
|
+
if (!hasAppScope(token)) {
|
|
839
|
+
throw new Error("Agent Chat: o token configurado \xE9 uma sess\xE3o do console (sem app_id) \u2014 o WebSocket do copilot exige token de app. Fa\xE7a loginMitra({ projectId }).");
|
|
840
|
+
}
|
|
813
841
|
const origin = getGatewayOrigin().replace(/^http/, "ws");
|
|
814
|
-
return `${origin}/copilot/ws/tasks/${encodeURIComponent(taskId)}?token=${encodeURIComponent(
|
|
842
|
+
return `${origin}/copilot/ws/tasks/${encodeURIComponent(taskId)}?token=${encodeURIComponent(token)}`;
|
|
815
843
|
}
|
|
816
844
|
function getRawToken() {
|
|
817
845
|
const config = getConfig();
|
|
@@ -1051,20 +1079,22 @@ function createMitraInstance(initialConfig) {
|
|
|
1051
1079
|
return false;
|
|
1052
1080
|
}
|
|
1053
1081
|
}
|
|
1082
|
+
function withFreshAuth2(init) {
|
|
1083
|
+
const headers = { ...init.headers };
|
|
1084
|
+
if (_config.token) headers["Authorization"] = formatToken2(_config.token);
|
|
1085
|
+
return { ...init, headers };
|
|
1086
|
+
}
|
|
1054
1087
|
async function fetchWithRefresh2(url, init) {
|
|
1055
1088
|
const fetchFn = getFetch3();
|
|
1089
|
+
if (isTokenExpiring(_config.token)) {
|
|
1090
|
+
const refreshed = await tryRefreshToken2();
|
|
1091
|
+
if (refreshed) init = withFreshAuth2(init);
|
|
1092
|
+
}
|
|
1056
1093
|
const response = await fetchFn(url, init);
|
|
1057
1094
|
if (response.status === 401) {
|
|
1058
1095
|
const refreshed = await tryRefreshToken2();
|
|
1059
1096
|
if (refreshed) {
|
|
1060
|
-
const
|
|
1061
|
-
const oldHeaders = init.headers;
|
|
1062
|
-
if (oldHeaders) {
|
|
1063
|
-
for (const [k, v] of Object.entries(oldHeaders)) {
|
|
1064
|
-
if (k !== "Authorization") newHeaders[k] = v;
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
const retryResponse = await fetchFn(url, { ...init, headers: newHeaders });
|
|
1097
|
+
const retryResponse = await fetchFn(url, withFreshAuth2(init));
|
|
1068
1098
|
return handleResponse2(retryResponse);
|
|
1069
1099
|
}
|
|
1070
1100
|
}
|
|
@@ -1251,6 +1281,50 @@ function persistRefreshToken(refreshToken) {
|
|
|
1251
1281
|
} catch (e) {
|
|
1252
1282
|
}
|
|
1253
1283
|
}
|
|
1284
|
+
function removePersistedRefreshToken() {
|
|
1285
|
+
const ls = safeLocalStorage();
|
|
1286
|
+
if (!ls) return;
|
|
1287
|
+
try {
|
|
1288
|
+
const raw = ls.getItem(SESSION_STORE_KEY);
|
|
1289
|
+
if (!raw) return;
|
|
1290
|
+
const obj = JSON.parse(raw);
|
|
1291
|
+
delete obj.refreshToken;
|
|
1292
|
+
ls.setItem(SESSION_STORE_KEY, JSON.stringify(obj));
|
|
1293
|
+
} catch (e) {
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
function decodeJwtPayload(token) {
|
|
1297
|
+
try {
|
|
1298
|
+
const part = stripBearer(token).split(".")[1];
|
|
1299
|
+
if (!part) return null;
|
|
1300
|
+
const b64 = part.replace(/-/g, "+").replace(/_/g, "/");
|
|
1301
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
1302
|
+
const json = typeof atob === "function" ? atob(padded) : Buffer.from(padded, "base64").toString("utf8");
|
|
1303
|
+
return JSON.parse(json);
|
|
1304
|
+
} catch (e) {
|
|
1305
|
+
return null;
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
function hasAppScope(token) {
|
|
1309
|
+
const payload = decodeJwtPayload(token);
|
|
1310
|
+
if (!payload) return true;
|
|
1311
|
+
return typeof payload.app_id === "string" && payload.app_id.length > 0;
|
|
1312
|
+
}
|
|
1313
|
+
function isTokenExpiring(token, skewMs = 3e4) {
|
|
1314
|
+
const t = token != null ? token : globalConfig == null ? void 0 : globalConfig.token;
|
|
1315
|
+
if (!t) return false;
|
|
1316
|
+
const payload = decodeJwtPayload(t);
|
|
1317
|
+
const exp = payload == null ? void 0 : payload.exp;
|
|
1318
|
+
if (typeof exp !== "number") return false;
|
|
1319
|
+
return exp * 1e3 - Date.now() < skewMs;
|
|
1320
|
+
}
|
|
1321
|
+
function clearRefreshToken() {
|
|
1322
|
+
if (globalConfig) {
|
|
1323
|
+
const { refreshToken: _drop, ...rest } = globalConfig;
|
|
1324
|
+
globalConfig = rest;
|
|
1325
|
+
}
|
|
1326
|
+
removePersistedRefreshToken();
|
|
1327
|
+
}
|
|
1254
1328
|
function readPersistedRefreshToken() {
|
|
1255
1329
|
const ls = safeLocalStorage();
|
|
1256
1330
|
if (!ls) return void 0;
|
|
@@ -1283,7 +1357,16 @@ function configureSdkMitra(config = {}) {
|
|
|
1283
1357
|
if (merged.token != null) merged.token = stripBearer(merged.token);
|
|
1284
1358
|
if (!merged.refreshToken) {
|
|
1285
1359
|
const persisted = readPersistedRefreshToken();
|
|
1286
|
-
if (persisted)
|
|
1360
|
+
if (persisted) {
|
|
1361
|
+
if (hasAppScope(persisted)) {
|
|
1362
|
+
merged.refreshToken = persisted;
|
|
1363
|
+
} else {
|
|
1364
|
+
removePersistedRefreshToken();
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
} else if (!hasAppScope(merged.refreshToken)) {
|
|
1368
|
+
delete merged.refreshToken;
|
|
1369
|
+
removePersistedRefreshToken();
|
|
1287
1370
|
} else {
|
|
1288
1371
|
persistRefreshToken(merged.refreshToken);
|
|
1289
1372
|
}
|