mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-17 04:12:17 +03:00
⭐5 — M365 Copilot (BizChat) individual/consumer path — 3 itens: (1) forma de invocação do #10718 derivou de novo (2026-08-21 capture): optionsSets 14→34, allowedMessageTypes 6→30, tone "magic"→"Magic", plugins []→[{BingWebSearch}], disconnectBehavior em todos os tiers, +8 keys de clientInfo; verificado contra conta real com round-trip WebSocket (ping-then-close → resposta real). (2) Aviso sobre o alias Antigravity gemini-3.1-pro-high ainda não publicado (3.8.49 pré-data). (3) Botão "Import .har file" no modal de credencial M365. Conflito resolvido em copilot-m365-frames.ts (board vs release tip): mantive o forwarding de opts.plugins/toolChoice/customInstructions do HEAD com os NOVOS defaults da captura (BingWebSearch builtin, tone "Magic"). Alinhei 3 testes pré-existentes que afirmavam o contrato antigo (m365-bizchat-frames-4042 clientInfo, m365-tone-model-variants tone, copilot-m365-tool-calls plugins) — propagação de contrato, não mascaramento. Rebaselinei AddApiKeyModal 1073→1080 (crescimento próprio da parte 3, ~Har import button) com anotação. Validação: typecheck limpo, 142/142 testes m365/copilot verdes, changelog-integrit/file-size/eslint OK.
79 lines
3.0 KiB
TypeScript
79 lines
3.0 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
extractM365CredentialFromHar,
|
|
describeHarImportExpiry,
|
|
M365_CHATHUB_WS_PREFIX,
|
|
} from "../../../src/shared/utils/m365HarImport.ts";
|
|
|
|
function fakeJwt(exp: number): string {
|
|
const b64 = (value: unknown) => Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
return `${b64({ alg: "none" })}.${b64({ exp })}.sig`;
|
|
}
|
|
|
|
function harWithUrl(url: string | null): string {
|
|
return JSON.stringify({
|
|
log: { entries: url ? [{ request: { url } }] : [] },
|
|
});
|
|
}
|
|
|
|
test("extracts access_token + chathubPath from a matching ChatHub WS entry", () => {
|
|
const exp = Math.floor(Date.now() / 1000) + 3600;
|
|
const token = fakeJwt(exp);
|
|
const url = `${M365_CHATHUB_WS_PREFIX}oid-123%40tenant-456?chatsessionid=abc&access_token=${token}`;
|
|
const result = extractM365CredentialFromHar(harWithUrl(url));
|
|
|
|
assert.equal(result.ok, true);
|
|
if (!result.ok) return;
|
|
assert.equal(result.chathubPath, "oid-123@tenant-456");
|
|
assert.equal(result.apiKey, `access_token=${token}; chathubPath=oid-123@tenant-456`);
|
|
assert.ok(result.expiresAt !== null && Math.abs(result.expiresAt - exp * 1000) < 1000);
|
|
});
|
|
|
|
test("picks the LAST matching entry when a HAR has multiple turns", () => {
|
|
const oldToken = fakeJwt(1000);
|
|
const freshToken = fakeJwt(9999999999);
|
|
const har = JSON.stringify({
|
|
log: {
|
|
entries: [
|
|
{ request: { url: `${M365_CHATHUB_WS_PREFIX}u%40t?access_token=${oldToken}` } },
|
|
{ request: { url: "https://unrelated.example/" } },
|
|
{ request: { url: `${M365_CHATHUB_WS_PREFIX}u%40t?access_token=${freshToken}` } },
|
|
],
|
|
},
|
|
});
|
|
const result = extractM365CredentialFromHar(har);
|
|
assert.equal(result.ok, true);
|
|
if (!result.ok) return;
|
|
assert.ok(result.apiKey.includes(freshToken));
|
|
});
|
|
|
|
test("returns notJson for malformed input", () => {
|
|
const result = extractM365CredentialFromHar("not json{{{");
|
|
assert.deepEqual(result, { ok: false, error: "notJson" });
|
|
});
|
|
|
|
test("returns noEntries when log.entries is missing/not an array", () => {
|
|
const result = extractM365CredentialFromHar(JSON.stringify({ log: {} }));
|
|
assert.deepEqual(result, { ok: false, error: "noEntries" });
|
|
});
|
|
|
|
test("returns noChathubUrl when no request matches the ChatHub prefix", () => {
|
|
const result = extractM365CredentialFromHar(harWithUrl("https://example.com/"));
|
|
assert.deepEqual(result, { ok: false, error: "noChathubUrl" });
|
|
});
|
|
|
|
test("returns missingFields when the URL matches but lacks access_token or chathubPath", () => {
|
|
const result = extractM365CredentialFromHar(harWithUrl(`${M365_CHATHUB_WS_PREFIX}`));
|
|
assert.equal(result.ok, false);
|
|
});
|
|
|
|
test("describeHarImportExpiry classifies ok/warn/bad/unknown", () => {
|
|
const now = Date.now();
|
|
assert.equal(describeHarImportExpiry(now + 30 * 60000, now).tone, "ok");
|
|
assert.equal(describeHarImportExpiry(now + 5 * 60000, now).tone, "warn");
|
|
assert.equal(describeHarImportExpiry(now - 60000, now).tone, "bad");
|
|
assert.equal(describeHarImportExpiry(null, now).tone, "unknown");
|
|
});
|