@lionchat/mcp-server 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 LionChat Crm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,313 @@
1
+ # @lionchat/mcp-server
2
+
3
+ MCP server que conecta agentes de IA a plataforma LionChat. Expoe mais de 540 ferramentas para gerenciar contatos, conversas, kanban, funis, mensagens, automacoes e muito mais.
4
+
5
+ ## O que e MCP?
6
+
7
+ MCP (Model Context Protocol) e um protocolo aberto que permite agentes de IA interagirem com servicos externos. Com este servidor, qualquer agente compativel (Claude Code, n8n, agentes customizados) pode executar acoes no LionChat por linguagem natural.
8
+
9
+ **Sem MCP:** Voce le a documentacao, copia endpoints, configura manualmente.
10
+ **Com MCP:** Voce diz "crie um funil com 4 etapas" e o agente faz tudo.
11
+
12
+ ---
13
+
14
+ ## Inicio Rapido
15
+
16
+ ### 1. Obtenha seu token
17
+
18
+ 1. Faca login no LionChat
19
+ 2. Va em **Configuracoes > Perfil**
20
+ 3. Copie o **Access Token**
21
+
22
+ ### 2. Descubra seu Account ID
23
+
24
+ O account_id aparece na URL quando voce esta logado:
25
+
26
+ ```
27
+ app.lionchat.com.br/app/accounts/ACCOUNT_ID/dashboard
28
+ ```
29
+
30
+ ### 3. Conecte ao Claude Code
31
+
32
+ ```bash
33
+ claude mcp add lionchat \
34
+ -e LIONCHAT_API_TOKEN=seu_token \
35
+ -e LIONCHAT_ACCOUNT_ID=123 \
36
+ -- npx @lionchat/mcp-server
37
+ ```
38
+
39
+ Pronto. Agora voce pode pedir ao Claude Code para fazer qualquer coisa no LionChat.
40
+
41
+ ### Instalacao alternativa (variaveis de ambiente)
42
+
43
+ ```bash
44
+ export LIONCHAT_API_TOKEN=seu_token
45
+ export LIONCHAT_ACCOUNT_ID=123
46
+ npx @lionchat/mcp-server
47
+ ```
48
+
49
+ ### Instancia self-hosted / white-label
50
+
51
+ ```bash
52
+ export LIONCHAT_BASE_URL=https://sua-instancia.com
53
+ npx @lionchat/mcp-server
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Configuracao
59
+
60
+ | Variavel | CLI | Obrigatorio | Padrao |
61
+ |----------|-----|-------------|--------|
62
+ | `LIONCHAT_API_TOKEN` | `--token` | Sim | -- |
63
+ | `LIONCHAT_ACCOUNT_ID` | `--account` | Sim | -- |
64
+ | `LIONCHAT_BASE_URL` | `--base-url` | Nao | `https://app.lionchat.com.br` |
65
+ | `LIONCHAT_CATEGORIES` | `--categories` | Nao | todas |
66
+ | `LIONCHAT_INCLUDE_PUBLIC_API` | `--include-public-api` | Nao | false |
67
+
68
+ **Prioridade:** argumentos CLI > variaveis de ambiente > valores padrao.
69
+
70
+ ---
71
+
72
+ ## Filtro por Categoria
73
+
74
+ Para melhor performance do agente, carregue apenas as ferramentas que precisa:
75
+
76
+ ```bash
77
+ npx @lionchat/mcp-server --categories=contacts,conversations,kanban_items
78
+ ```
79
+
80
+ ### Perfis Sugeridos
81
+
82
+ | Perfil | Categorias | Uso |
83
+ |--------|-----------|-----|
84
+ | **Vendas** | `contacts,conversations,messages,kanban_items,funnels,offers` | CRM e automacao de vendas |
85
+ | **Suporte** | `contacts,conversations,messages,canned_responses,teams,labels` | Atendimento ao cliente |
86
+ | **Marketing** | `contacts,automation_rules,labels,scheduled_messages` | Campanhas e automacao |
87
+ | **Completo** | _(sem filtro)_ | Cobertura total da API (541 ferramentas) |
88
+
89
+ ### Categorias Disponiveis
90
+
91
+ | Slug | Descricao | Tools |
92
+ |------|-----------|-------|
93
+ | `account` | Detalhes da conta | 3 |
94
+ | `agents` | Agentes/operadores | 2 |
95
+ | `agent_availability` | Disponibilidade dos agentes | 4 |
96
+ | `announcements` | Anuncios internos | 4 |
97
+ | `assignment_policies` | Politicas de atribuicao | 11 |
98
+ | `automation_rules` | Regras de automacao | 7 |
99
+ | `booking_event_types` | Tipos de evento (agenda) | 8 |
100
+ | `canned_responses` | Respostas rapidas | 6 |
101
+ | `capacity_policies` | Politicas de capacidade | 11 |
102
+ | `captain_assistants` | Assistentes IA | 33 |
103
+ | `captain_documents` | Base de conhecimento IA | 4 |
104
+ | `contacts` | Contatos | 25 |
105
+ | `conversations` | Conversas | 30 |
106
+ | `copilot_prompts` | Prompts salvos do Copilot | 4 |
107
+ | `csat` | Pesquisas de satisfacao | 3 |
108
+ | `csat_template` | Template CSAT por inbox | 2 |
109
+ | `custom_attributes` | Atributos personalizados | 5 |
110
+ | `custom_filters` | Filtros personalizados | 5 |
111
+ | `custom_roles` | Roles personalizados | 5 |
112
+ | `dashboard_apps` | Apps no dashboard | 5 |
113
+ | `ecommerce_webhooks` | Integracoes e-commerce (Guru, Hotmart, Kiwify, Ticto, Eduzz, Monetizze) | 55 |
114
+ | `flows` | FlowBuilder (automacoes visuais) | 10 |
115
+ | `flow_sessions` | Sessoes do FlowBuilder | 3 |
116
+ | `funnels` | Funis de vendas | 10 |
117
+ | `google_calendar` | Google Calendar | 13 |
118
+ | `inbox_members` | Membros das inboxes | 4 |
119
+ | `inbox_migration` | Migracao entre inboxes | 3 |
120
+ | `inboxes` | Caixas de entrada | 4 |
121
+ | `kanban_agents` | Agentes do Kanban | 3 |
122
+ | `kanban_bulk` | Operacoes em massa (Kanban) | 4 |
123
+ | `kanban_checklist` | Checklist dos cards | 5 |
124
+ | `kanban_config` | Configuracao do Kanban | 5 |
125
+ | `kanban_items` | Cards do Kanban | 21 |
126
+ | `kanban_notes` | Notas dos cards | 4 |
127
+ | `kanban_v2` | Kanban V2 (items, funis, etapas, automacoes) | 25 |
128
+ | `labels` | Labels/etiquetas | 5 |
129
+ | `macros` | Macros | 6 |
130
+ | `messages` | Mensagens | 8 |
131
+ | `meta_lead` | Meta Lead Ads (Facebook/Instagram) | 10 |
132
+ | `notification_settings` | Config de notificacoes | 2 |
133
+ | `notifications` | Notificacoes | 8 |
134
+ | `offers` | Ofertas | 6 |
135
+ | `portals` | Portais e base de conhecimento | 20 |
136
+ | `public_booking` | Agendamento publico | 5 |
137
+ | `public_contacts` | API publica: contatos | 3 |
138
+ | `public_conversations` | API publica: conversas | 5 |
139
+ | `public_csat` | API publica: CSAT | 1 |
140
+ | `public_messages` | API publica: mensagens | 3 |
141
+ | `reports` | Relatorios V2 | 19 |
142
+ | `scheduled_messages` | Mensagens agendadas | 8 |
143
+ | `search` | Busca global | 4 |
144
+ | `sla` | SLA (Service Level Agreement) | 8 |
145
+ | `support_access` | Acesso de suporte | 3 |
146
+ | `tasks` | Agenda / Tarefas | 14 |
147
+ | `teams` | Times | 7 |
148
+ | `upload` | Upload de arquivos | 1 |
149
+ | `voip_calls` | Ligacoes VoIP (Zenvia) | 20 |
150
+ | `waha_groups` | Grupos WhatsApp | 14 |
151
+ | `webhooks` | Webhooks | 4 |
152
+ | `whatsapp_templates` | Templates WhatsApp | 5 |
153
+ | `account_variables` | Variaveis da conta | 4 |
154
+
155
+ ---
156
+
157
+ ## Exemplos de Uso
158
+
159
+ ### No Claude Code
160
+
161
+ Depois de conectar, basta pedir em linguagem natural:
162
+
163
+ ```
164
+ "Liste meus ultimos 10 contatos"
165
+ → lionchat_contacts_list
166
+
167
+ "Crie um funil chamado 'Vendas Q2' com etapas Prospeccao, Qualificacao, Proposta, Fechado"
168
+ → lionchat_funnels_create
169
+
170
+ "Mova o card 42 para a etapa 'Proposta'"
171
+ → lionchat_kanban_items_move_to_stage
172
+
173
+ "Envie 'Ola!' na conversa 15"
174
+ → lionchat_conversations_messages_create
175
+
176
+ "Quais conversas estao abertas no time de suporte?"
177
+ → lionchat_conversations_list (com filtro por time)
178
+
179
+ "Crie uma regra de automacao: quando criar conversa com label VIP, atribuir ao time Premium"
180
+ → lionchat_automation_rules_create
181
+
182
+ "Qual o saldo do meu VoIP?"
183
+ → lionchat_voip_calls_balance
184
+ ```
185
+
186
+ ### No n8n
187
+
188
+ O n8n suporta MCP de duas formas:
189
+
190
+ #### Opcao 1: MCP Client + AI Agent (recomendado para decisoes inteligentes)
191
+
192
+ 1. Adicione um node **"AI Agent"** ao seu workflow (Claude, GPT, ou outro LLM)
193
+ 2. Adicione um node **"MCP Client"** como ferramenta do agente
194
+ 3. Configure o MCP Client:
195
+ - **Transport:** stdio
196
+ - **Command:** `npx`
197
+ - **Arguments:** `@lionchat/mcp-server`
198
+ - **Environment Variables:**
199
+ - `LIONCHAT_API_TOKEN` = seu token
200
+ - `LIONCHAT_ACCOUNT_ID` = seu account ID
201
+ - `LIONCHAT_CATEGORIES` = categorias desejadas (opcional)
202
+ 4. Conecte o MCP Client ao AI Agent
203
+ 5. O agente de IA decide automaticamente quais ferramentas usar
204
+
205
+ **Exemplo de prompt no AI Agent:**
206
+ > "Analise os contatos criados ontem. Se algum tem empresa no nome, crie um card no funil 'Vendas B2B' na etapa 'Prospeccao'."
207
+
208
+ O agente vai chamar `lionchat_contacts_list`, analisar os resultados, e chamar `lionchat_kanban_items_create` para cada contato relevante.
209
+
210
+ #### Opcao 2: HTTP Request (para automacoes fixas)
211
+
212
+ Para automacoes tipo "se X entao Y" sem necessidade de IA, use o node **HTTP Request** do n8n chamando a API do LionChat diretamente:
213
+
214
+ - **URL:** `https://app.lionchat.com.br/api/v1/accounts/{account_id}/contacts`
215
+ - **Header:** `api_access_token: seu_token`
216
+ - **Method:** GET, POST, etc.
217
+
218
+ #### Quando usar cada opcao
219
+
220
+ | Abordagem | Quando usar |
221
+ |-----------|-------------|
222
+ | **MCP + AI Agent** | O fluxo precisa de decisao inteligente ("analise e decida") |
223
+ | **HTTP Request** | Automacao fixa ("quando receber webhook, criar contato") |
224
+
225
+ ### Em scripts ou agentes customizados
226
+
227
+ O MCP server funciona com qualquer cliente MCP via transporte stdio. Execute como subprocesso e comunique via stdin/stdout (JSON-RPC).
228
+
229
+ ---
230
+
231
+ ## Ferramentas Meta
232
+
233
+ Sempre disponiveis, independente do filtro de categorias:
234
+
235
+ | Ferramenta | Descricao |
236
+ |------------|-----------|
237
+ | `lionchat_ping` | Testa conectividade e valida o token |
238
+ | `lionchat_list_categories` | Lista categorias disponiveis com contagem de ferramentas |
239
+
240
+ Use `lionchat_ping` para verificar se a conexao esta funcionando antes de executar outras acoes.
241
+
242
+ ---
243
+
244
+ ## API Publica
245
+
246
+ Os 12 endpoints da API publica (widget, contatos publicos, CSAT) sao **ocultos por padrao** por seguranca. Para habilitar:
247
+
248
+ ```bash
249
+ npx @lionchat/mcp-server --include-public-api
250
+ ```
251
+
252
+ Esses endpoints usam `inbox_identifier` e `contact_identifier` em vez de token. Habilite apenas se seu agente precisa criar contatos ou conversas em nome de usuarios finais.
253
+
254
+ ---
255
+
256
+ ## Upload de Arquivos
257
+
258
+ Endpoints que requerem upload de arquivo (importacao CSV, avatar, anexos) estao incluidos mas retornam uma mensagem orientando a usar a interface web ou chamadas API diretas. Upload via MCP sera suportado em versoes futuras.
259
+
260
+ ---
261
+
262
+ ## Seguranca
263
+
264
+ - Token armazenado em variavel de ambiente, nunca logado ou incluido em respostas
265
+ - Transporte stdio -- comunicacao local entre processos, sem porta de rede aberta
266
+ - Stateless -- nada salvo em disco
267
+ - Timeout de 30 segundos por requisicao
268
+ - Retry automatico com backoff exponencial para rate limiting (429)
269
+ - Cada requisicao usa o token do cliente -- permissoes do LionChat sao respeitadas no servidor
270
+
271
+ **Recomendacao:** Use um token com permissoes minimas para seu caso de uso. Evite tokens de administrador em agentes automatizados.
272
+
273
+ ---
274
+
275
+ ## Requisitos
276
+
277
+ - Node.js 18 ou superior
278
+ - Conta no LionChat com access token
279
+
280
+ ---
281
+
282
+ ## Desenvolvimento
283
+
284
+ ```bash
285
+ # Clonar o repositorio
286
+ git clone https://github.com/LionChatCRM/lionchat-mcp-server-.git
287
+ cd lionchat-mcp-server-
288
+
289
+ # Instalar dependencias
290
+ npm install
291
+
292
+ # Build
293
+ npm run build
294
+
295
+ # Testar localmente
296
+ LIONCHAT_API_TOKEN=seu_token LIONCHAT_ACCOUNT_ID=123 node dist/index.js
297
+ ```
298
+
299
+ ### Atualizar endpoints
300
+
301
+ Quando a API do LionChat mudar:
302
+
303
+ 1. Atualize o HTML de documentacao da API
304
+ 2. Execute `npm run extract -- caminho/para/api-docs.html`
305
+ 3. Verifique o `endpoints.json` gerado
306
+ 4. Incremente a versao no `package.json`
307
+ 5. `npm publish`
308
+
309
+ ---
310
+
311
+ ## Licenca
312
+
313
+ MIT
@@ -0,0 +1,27 @@
1
+ import { Config } from './config.js';
2
+ export interface RequestOptions {
3
+ method: string;
4
+ path: string;
5
+ body?: Record<string, unknown>;
6
+ }
7
+ export interface PaginatedResponse {
8
+ data: unknown[];
9
+ pagination?: {
10
+ current_page: number;
11
+ total_pages: number;
12
+ total_count: number;
13
+ has_more: boolean;
14
+ };
15
+ }
16
+ export declare class LionChatApiError extends Error {
17
+ readonly status: number;
18
+ readonly responseBody: unknown;
19
+ constructor(message: string, status: number, responseBody?: unknown);
20
+ }
21
+ export declare class LionChatClient {
22
+ private config;
23
+ constructor(config: Config);
24
+ request(options: RequestOptions): Promise<unknown>;
25
+ private buildUrl;
26
+ private executeWithRetry;
27
+ }
package/dist/client.js ADDED
@@ -0,0 +1,264 @@
1
+ // AIDEV-NOTE: HTTP client for LionChat API
2
+ // Uses native fetch (Node 18+), zero external dependencies
3
+ // Handles auth, retry (429/5xx/network), timeout, and response normalization
4
+ // AIDEV-NOTE: Custom error class with HTTP status for callers to inspect
5
+ export class LionChatApiError extends Error {
6
+ status;
7
+ responseBody;
8
+ constructor(message, status, responseBody) {
9
+ super(message);
10
+ this.name = 'LionChatApiError';
11
+ this.status = status;
12
+ this.responseBody = responseBody;
13
+ }
14
+ }
15
+ const TIMEOUT_MS = 30_000;
16
+ const MAX_RETRIES_429 = 3;
17
+ const MAX_RETRIES_5XX = 1;
18
+ const MAX_RETRIES_NETWORK = 1;
19
+ // AIDEV-NOTE: Actionable error messages per HTTP status
20
+ function getErrorMessage(status, body) {
21
+ switch (status) {
22
+ case 401:
23
+ return 'Authentication failed. Check your token at Login > Profile Settings';
24
+ case 403:
25
+ return 'Permission denied. Your token may not have access to this resource';
26
+ case 404:
27
+ return 'Resource not found. Check the ID and account_id';
28
+ case 422: {
29
+ const details = extractValidationDetails(body);
30
+ return `Validation error: ${details}`;
31
+ }
32
+ case 429:
33
+ return 'Rate limited. Wait and retry';
34
+ default:
35
+ if (status >= 500) {
36
+ return 'LionChat server error. Try again later';
37
+ }
38
+ return `HTTP error ${status}`;
39
+ }
40
+ }
41
+ // AIDEV-NOTE: Extract validation details from 422 response body
42
+ function extractValidationDetails(body) {
43
+ if (body && typeof body === 'object') {
44
+ const obj = body;
45
+ // Chatwoot returns errors in various formats
46
+ if (obj.message && typeof obj.message === 'string') {
47
+ return obj.message;
48
+ }
49
+ if (obj.error && typeof obj.error === 'string') {
50
+ return obj.error;
51
+ }
52
+ if (obj.errors && Array.isArray(obj.errors)) {
53
+ return obj.errors.join(', ');
54
+ }
55
+ if (obj.errors && typeof obj.errors === 'object') {
56
+ return JSON.stringify(obj.errors);
57
+ }
58
+ }
59
+ return JSON.stringify(body);
60
+ }
61
+ // AIDEV-NOTE: Check if an error is a network/timeout error worth retrying
62
+ function isNetworkError(err) {
63
+ if (err instanceof Error) {
64
+ const msg = err.message.toLowerCase();
65
+ return (msg.includes('econnrefused') ||
66
+ msg.includes('econnreset') ||
67
+ msg.includes('etimedout') ||
68
+ msg.includes('fetch failed') ||
69
+ msg.includes('abort') ||
70
+ err.name === 'AbortError');
71
+ }
72
+ return false;
73
+ }
74
+ // AIDEV-NOTE: Sleep utility for retry backoff
75
+ function sleep(ms) {
76
+ return new Promise((resolve) => setTimeout(resolve, ms));
77
+ }
78
+ // AIDEV-NOTE: Normalize LionChat API responses to a consistent format
79
+ // - Array with meta/payload pagination -> PaginatedResponse
80
+ // - Plain array -> { data: [...] }
81
+ // - Single object -> returned as-is
82
+ function normalizeResponse(body) {
83
+ if (body && typeof body === 'object' && !Array.isArray(body)) {
84
+ const obj = body;
85
+ // AIDEV-NOTE: Chatwoot pagination format: { payload: [...], meta: { all_count, current_page } }
86
+ if (Array.isArray(obj.payload) && obj.meta && typeof obj.meta === 'object') {
87
+ const meta = obj.meta;
88
+ const allCount = typeof meta.all_count === 'number' ? meta.all_count : 0;
89
+ const currentPage = typeof meta.current_page === 'number' ? meta.current_page : 1;
90
+ // AIDEV-NOTE: Chatwoot uses 25 items per page by default. Don't use payload.length
91
+ // as it's wrong on the last page (e.g. 3 items on last page → wrong totalPages calc)
92
+ const perPage = 25;
93
+ const totalPages = perPage > 0 ? Math.ceil(allCount / perPage) : 1;
94
+ return {
95
+ data: obj.payload,
96
+ pagination: {
97
+ current_page: currentPage,
98
+ total_pages: totalPages,
99
+ total_count: allCount,
100
+ has_more: currentPage < totalPages,
101
+ },
102
+ };
103
+ }
104
+ // AIDEV-NOTE: Some endpoints return { data: [...], meta: {...} } format
105
+ if (Array.isArray(obj.data) && obj.meta && typeof obj.meta === 'object') {
106
+ const meta = obj.meta;
107
+ const totalCount = typeof meta.total_count === 'number'
108
+ ? meta.total_count
109
+ : typeof meta.all_count === 'number'
110
+ ? meta.all_count
111
+ : obj.data.length;
112
+ const currentPage = typeof meta.current_page === 'number' ? meta.current_page : 1;
113
+ const totalPages = typeof meta.total_pages === 'number'
114
+ ? meta.total_pages
115
+ : Math.ceil(totalCount / Math.max(obj.data.length, 1));
116
+ return {
117
+ data: obj.data,
118
+ pagination: {
119
+ current_page: currentPage,
120
+ total_pages: totalPages,
121
+ total_count: totalCount,
122
+ has_more: currentPage < totalPages,
123
+ },
124
+ };
125
+ }
126
+ // AIDEV-NOTE: Single object response — return as-is
127
+ return body;
128
+ }
129
+ // AIDEV-NOTE: Flat array response — wrap in { data: [...] }
130
+ if (Array.isArray(body)) {
131
+ return { data: body };
132
+ }
133
+ return body;
134
+ }
135
+ export class LionChatClient {
136
+ config;
137
+ constructor(config) {
138
+ this.config = config;
139
+ }
140
+ // AIDEV-NOTE: Main request method with auth, timeout, retry, and normalization
141
+ async request(options) {
142
+ const { method, path, body } = options;
143
+ // AIDEV-NOTE: Build full URL (query params already embedded in path by tools.ts)
144
+ const url = this.buildUrl(path);
145
+ // AIDEV-NOTE: Build headers — api_access_token on all requests
146
+ const headers = {
147
+ api_access_token: this.config.apiToken,
148
+ };
149
+ const hasBody = body && ['POST', 'PATCH', 'PUT', 'DELETE'].includes(method.toUpperCase());
150
+ if (hasBody) {
151
+ headers['Content-Type'] = 'application/json';
152
+ }
153
+ const fetchOptions = {
154
+ method: method.toUpperCase(),
155
+ headers,
156
+ };
157
+ if (hasBody) {
158
+ fetchOptions.body = JSON.stringify(body);
159
+ }
160
+ // AIDEV-NOTE: Execute with retry logic
161
+ return this.executeWithRetry(url, fetchOptions);
162
+ }
163
+ // AIDEV-NOTE: Build URL from base + path (query params already in path string)
164
+ buildUrl(path) {
165
+ const base = this.config.baseUrl.replace(/\/+$/, '');
166
+ const cleanPath = path.startsWith('/') ? path : `/${path}`;
167
+ return `${base}${cleanPath}`;
168
+ }
169
+ // AIDEV-NOTE: Retry logic: 429 (exponential backoff, 3x), 5xx (once, 2s), network (once, 2s)
170
+ async executeWithRetry(url, fetchOptions) {
171
+ let lastError;
172
+ let retries429 = 0;
173
+ let retries5xx = 0;
174
+ let retriesNetwork = 0;
175
+ // AIDEV-NOTE: Max possible attempts = 1 initial + 3 (429) + 1 (5xx) + 1 (network)
176
+ // In practice, only one retry category applies per request
177
+ const maxAttempts = 1 + MAX_RETRIES_429 + MAX_RETRIES_5XX + MAX_RETRIES_NETWORK;
178
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
179
+ try {
180
+ // AIDEV-NOTE: AbortController for 30s timeout
181
+ const controller = new AbortController();
182
+ const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
183
+ let response;
184
+ try {
185
+ response = await fetch(url, {
186
+ ...fetchOptions,
187
+ signal: controller.signal,
188
+ });
189
+ }
190
+ finally {
191
+ clearTimeout(timeoutId);
192
+ }
193
+ // AIDEV-NOTE: Parse response body
194
+ let responseBody;
195
+ const contentType = response.headers.get('content-type') ?? '';
196
+ if (contentType.includes('application/json')) {
197
+ responseBody = await response.json();
198
+ }
199
+ else {
200
+ const text = await response.text();
201
+ // AIDEV-NOTE: Try parsing as JSON even without content-type header
202
+ try {
203
+ responseBody = JSON.parse(text);
204
+ }
205
+ catch {
206
+ responseBody = text;
207
+ }
208
+ }
209
+ // AIDEV-NOTE: Success — normalize and return
210
+ if (response.ok) {
211
+ return normalizeResponse(responseBody);
212
+ }
213
+ // AIDEV-NOTE: 429 — exponential backoff with Retry-After header support
214
+ if (response.status === 429 && retries429 < MAX_RETRIES_429) {
215
+ retries429++;
216
+ const retryAfter = response.headers.get('Retry-After');
217
+ let delayMs;
218
+ if (retryAfter) {
219
+ const seconds = parseInt(retryAfter, 10);
220
+ // AIDEV-NOTE: Retry-After can be seconds (integer) or HTTP-date. parseInt on
221
+ // a date string returns NaN, so fall back to exponential backoff.
222
+ delayMs = Number.isNaN(seconds) ? 1000 * Math.pow(2, retries429 - 1) : seconds * 1000;
223
+ }
224
+ else {
225
+ delayMs = 1000 * Math.pow(2, retries429 - 1); // 1s, 2s, 4s
226
+ }
227
+ await sleep(delayMs);
228
+ continue;
229
+ }
230
+ // AIDEV-NOTE: 5xx — retry once after 2s
231
+ if (response.status >= 500 && retries5xx < MAX_RETRIES_5XX) {
232
+ retries5xx++;
233
+ await sleep(2000);
234
+ continue;
235
+ }
236
+ // AIDEV-NOTE: Non-retryable error — throw with actionable message
237
+ const message = getErrorMessage(response.status, responseBody);
238
+ throw new LionChatApiError(message, response.status, responseBody);
239
+ }
240
+ catch (err) {
241
+ // AIDEV-NOTE: Re-throw our own errors (already handled above)
242
+ if (err instanceof LionChatApiError) {
243
+ throw err;
244
+ }
245
+ // AIDEV-NOTE: Network/timeout errors — retry once after 2s
246
+ if (isNetworkError(err) && retriesNetwork < MAX_RETRIES_NETWORK) {
247
+ retriesNetwork++;
248
+ lastError = err;
249
+ await sleep(2000);
250
+ continue;
251
+ }
252
+ // AIDEV-NOTE: Unrecoverable network error
253
+ if (isNetworkError(err)) {
254
+ throw new LionChatApiError(`Network error: Could not connect to ${this.config.baseUrl}. Check your base URL and network connection.`, 0, undefined);
255
+ }
256
+ // AIDEV-NOTE: Unexpected error — rethrow
257
+ throw err;
258
+ }
259
+ }
260
+ // AIDEV-NOTE: Should not reach here, but safety fallback
261
+ throw lastError ?? new Error('Request failed after all retries');
262
+ }
263
+ }
264
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export interface Config {
2
+ apiToken: string;
3
+ accountId: string;
4
+ baseUrl: string;
5
+ categories: string[] | null;
6
+ includePublicApi: boolean;
7
+ }
8
+ export declare function loadConfig(): Config;