next-finance-mcp 0.6.2 → 0.6.3

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.
Files changed (2) hide show
  1. package/dist/client.js +32 -5
  2. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -70,14 +70,19 @@ const BASE_HEADERS = {
70
70
  "Accept-Language": "pt-BR,pt;q=0.9,en;q=0.8",
71
71
  };
72
72
  /** GET para páginas web (login, seleção de carteira) */
73
- async function webGet(path) {
73
+ async function webGet(path, checkSession = false) {
74
74
  const res = await fetch(`${WEB_BASE}${path}`, {
75
75
  headers: { ...BASE_HEADERS, Cookie: getCookieHeader("finance.net.br"),
76
76
  Accept: "text/html,application/xhtml+xml,application/json,*/*;q=0.8" },
77
77
  redirect: "follow",
78
78
  });
79
79
  storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
80
- return { status: res.status, text: await res.text(), headers: res.headers };
80
+ const text = await res.text();
81
+ if (checkSession && (res.status === 401 || res.status === 403 ||
82
+ (res.url?.includes("/Login") && !path.includes("/Login")))) {
83
+ throwSessionExpired();
84
+ }
85
+ return { status: res.status, text, headers: res.headers };
81
86
  }
82
87
  /** POST form-urlencoded para fluxo de login/seleção de carteira */
83
88
  async function webPost(path, body, contentType, followRedirect = true) {
@@ -92,15 +97,33 @@ async function webPost(path, body, contentType, followRedirect = true) {
92
97
  storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
93
98
  return { status: res.status, text: await res.text(), location: res.headers.get("location") ?? undefined };
94
99
  }
100
+ /** Detecta se o servidor está sinalizando sessão expirada */
101
+ function isSessionExpired(status, text) {
102
+ if (status === 401 || status === 403)
103
+ return true;
104
+ // O servidor pode retornar 200 com redirect HTML para /Login
105
+ if (status === 200 && text.includes("/Login"))
106
+ return true;
107
+ return false;
108
+ }
109
+ function throwSessionExpired() {
110
+ _loggedIn = false;
111
+ _selectedWallet = null;
112
+ clearCookies();
113
+ throw new Error("Sessão expirada. Use a ferramenta `login` para autenticar novamente.");
114
+ }
95
115
  /** GET para a API REST — usa api.finance.net.br com o mesmo cookie de sessão */
96
116
  async function apiGet(path) {
97
117
  const res = await fetch(`${API_BASE}${path}`, {
98
118
  headers: { ...BASE_HEADERS, Cookie: getCookieHeader("finance.net.br"), Accept: "application/json" },
99
119
  });
100
120
  storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
121
+ const text = await res.text();
122
+ if (isSessionExpired(res.status, text))
123
+ throwSessionExpired();
101
124
  if (!res.ok)
102
125
  throw new Error(`API GET ${path}: ${res.status}`);
103
- return res.json();
126
+ return JSON.parse(text);
104
127
  }
105
128
  /** POST JSON para a API REST — usa api.finance.net.br com o mesmo cookie de sessão */
106
129
  async function apiPost(path, body) {
@@ -111,9 +134,12 @@ async function apiPost(path, body) {
111
134
  body: JSON.stringify(body),
112
135
  });
113
136
  storeCookies(res.headers.getSetCookie?.() ?? [], "finance.net.br");
137
+ const text = await res.text();
138
+ if (isSessionExpired(res.status, text))
139
+ throwSessionExpired();
114
140
  if (!res.ok)
115
141
  throw new Error(`API POST ${path}: ${res.status}`);
116
- return res.json();
142
+ return JSON.parse(text);
117
143
  }
118
144
  function extractCsrf(html) {
119
145
  return html.match(/name="__RequestVerificationToken"[^>]+value="([^"]+)"/)?.[1] ?? "";
@@ -502,7 +528,8 @@ export async function buscarLancamentos(opts) {
502
528
  .find(c => String(c["Nome"] ?? c["NomeConta"] ?? "").toLowerCase().includes(termo));
503
529
  if (!encontrada)
504
530
  throw new Error(`Conta "${opts.nomeConta}" não encontrada entre as contas ativas. Use listar_contas para ver as contas disponíveis.`);
505
- idContaResolvido = String(encontrada["Id"] ?? encontrada["IdConta"] ?? "");
531
+ // Tenta todos os nomes possíveis de campo ID na resposta da API
532
+ idContaResolvido = String(encontrada["Id"] ?? encontrada["IdConta"] ?? encontrada["id"] ?? encontrada["idConta"] ?? "");
506
533
  }
507
534
  let lancamentos;
508
535
  // Tenta API REST primeiro; cai no endpoint legado se falhar
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-finance-mcp",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "mcpName": "io.github.paivapiovesan/next-finance",
5
5
  "description": "MCP Server para o NEXT Finance (finance.net.br) — login via browser, listagem de carteiras, contas e lançamentos",
6
6
  "type": "module",