portal-aiatende-api 0.2.0 → 0.4.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/dist/index.d.mts +208 -2
- package/dist/index.d.ts +208 -2
- package/dist/index.js +104 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -12
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.d.mts
CHANGED
|
@@ -94,6 +94,14 @@ interface AiConfig {
|
|
|
94
94
|
untaggedLeadAiState?: 'inactive' | 'active' | 'active_for_new_leads';
|
|
95
95
|
/** Estado da IA após handoff. 'inactive' = trava permanente e global (nunca reativa sozinha). 'untag' = remove a tag, elegível pro bootstrap na próxima mensagem. */
|
|
96
96
|
handoffAiState?: 'inactive' | 'untag';
|
|
97
|
+
/** Canal WhatsApp direto (aiatendeWa) — domínio separado das tags Kommo acima, usa Conversation.aiCareStatus/aiResumeMode. Se true (default), conversas novas nesse canal já nascem com aiCareStatus ACTIVE; se false, nascem INACTIVE e exigem ativação manual pelo Portal. */
|
|
98
|
+
aiatendeWaDefaultActive?: boolean;
|
|
99
|
+
/** Canal aiatendeWa: responder em áudio (TTS) quando o lead mandar uma mensagem de áudio. Default true. */
|
|
100
|
+
audioReplyOnInboundAudio?: boolean;
|
|
101
|
+
/** Canal aiatendeWa: responder em áudio em vez de texto quando a resposta gerada passar desse tamanho (caracteres). `undefined`/`null`/`0` desliga esse gatilho específico. Default 300. */
|
|
102
|
+
audioReplyCharThreshold?: number | null;
|
|
103
|
+
/** Canal aiatendeWa: id bruto da voz de TTS escolhida — seu significado depende de qual provider `model` indica no momento do envio (OpenAI e Gemini têm listas de vozes totalmente diferentes). */
|
|
104
|
+
ttsVoice?: string | null;
|
|
97
105
|
/** Ativa a Reflection Agent (segunda passada de revisão/auditoria da resposta) pra este cliente. Ausente/undefined = usa o fallback global (env USE_REFLECTION_AGENT) no atende360-assistant — ver Orchestrator.ts. */
|
|
98
106
|
reflectionAgentEnabled?: boolean;
|
|
99
107
|
/** Limiar mínimo de similaridade (cosine, 0-1) pra um trecho da base de conhecimento entrar no contexto do RAG. `undefined`/`null` = o Portal usa o fallback global 0.5 até o admin calibrar via RAG eval. Aplicado internamente pelo Portal em `POST /api/knowledge/internal/context` — não precisa ser enviado pelo assistant-api. */
|
|
@@ -286,14 +294,32 @@ declare class ClientsResource extends BaseResource {
|
|
|
286
294
|
getByKommoSubdomain(subdomain: string): Promise<Client | null>;
|
|
287
295
|
/** Busca o Client dono de um canal Wazzup (`GET /api/clients?channelId=...`). */
|
|
288
296
|
getByWazzupChannelId(channelId: string): Promise<Client | null>;
|
|
297
|
+
/**
|
|
298
|
+
* Busca o Client pelo seu id direto (`GET /api/clients/{id}`) — inclui `aiConfig` e
|
|
299
|
+
* `messagingConfig` (sem a API key criptografada). Usado pelo canal aiatendeWa, que resolve o
|
|
300
|
+
* tenant a partir do `clientId` já incluído no payload do relay de webhook, sem precisar de
|
|
301
|
+
* um identificador de canal indireto como Kommo subdomain ou Wazzup channelId.
|
|
302
|
+
*/
|
|
303
|
+
getById(clientId: string): Promise<Client | null>;
|
|
289
304
|
}
|
|
290
305
|
|
|
306
|
+
/** Uma mensagem simplificada do histórico da conversa, enviada pro Portal reescrever a
|
|
307
|
+
* pergunta de acompanhamento como consulta autônoma antes de gerar o embedding. */
|
|
308
|
+
interface ConversationHistoryMessage {
|
|
309
|
+
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
310
|
+
content: string;
|
|
311
|
+
}
|
|
291
312
|
interface GetInternalContextParams {
|
|
292
313
|
/** Id do AiConfig do cliente — o Portal usa a `apiKey` configurada nele pra gerar o embedding da pergunta. */
|
|
293
314
|
aiConfigId: string;
|
|
294
315
|
/** Pergunta em texto puro do usuário. O embedding é gerado internamente pelo Portal (RagService.getEmbedding), não pelo chamador. */
|
|
295
316
|
question: string;
|
|
296
|
-
|
|
317
|
+
/** Últimas mensagens da conversa (mais antiga → mais recente), sem incluir `question`. Quando
|
|
318
|
+
* presente e não vazio, o Portal reescreve `question` como uma consulta autônoma (LLM rewrite)
|
|
319
|
+
* antes de buscar na base de conhecimento — melhora o recall em perguntas de acompanhamento
|
|
320
|
+
* (ex.: "e o azul?"). Omitir ou passar array vazio preserva o comportamento anterior (busca
|
|
321
|
+
* direto pela `question`, sem custo extra). */
|
|
322
|
+
conversationHistory?: ConversationHistoryMessage[];
|
|
297
323
|
}
|
|
298
324
|
interface InternalContextChunk {
|
|
299
325
|
chunkId?: string;
|
|
@@ -310,11 +336,191 @@ declare class KnowledgeResource extends BaseResource {
|
|
|
310
336
|
getInternalContext(params: GetInternalContextParams): Promise<InternalContextResult>;
|
|
311
337
|
}
|
|
312
338
|
|
|
339
|
+
type AiCareStatus = 'ACTIVE' | 'INACTIVE' | 'PAUSED';
|
|
340
|
+
type AiResumeMode = 'immediate' | 'next_message';
|
|
341
|
+
interface MessagingContact {
|
|
342
|
+
id: string;
|
|
343
|
+
waId: string;
|
|
344
|
+
profileName: string | null;
|
|
345
|
+
displayName: string | null;
|
|
346
|
+
displayNameSetByName: string | null;
|
|
347
|
+
displayNameSetAt: Date | string | null;
|
|
348
|
+
}
|
|
349
|
+
interface MessagingPhoneNumber {
|
|
350
|
+
id: string;
|
|
351
|
+
phoneNumberId: string;
|
|
352
|
+
displayNumber: string;
|
|
353
|
+
metaConnection: {
|
|
354
|
+
channel: string;
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
interface MessagingConversation {
|
|
358
|
+
id: string;
|
|
359
|
+
contactId: string;
|
|
360
|
+
phoneNumberId: string;
|
|
361
|
+
lastMessageAt: Date | string | null;
|
|
362
|
+
contact: MessagingContact;
|
|
363
|
+
phoneNumber: MessagingPhoneNumber;
|
|
364
|
+
_count: {
|
|
365
|
+
messages: number;
|
|
366
|
+
};
|
|
367
|
+
assignedToId: string | null;
|
|
368
|
+
assignedTo: {
|
|
369
|
+
id: string;
|
|
370
|
+
name: string;
|
|
371
|
+
email: string;
|
|
372
|
+
} | null;
|
|
373
|
+
lastMessage: Record<string, unknown> | null;
|
|
374
|
+
lastInboundAt: Date | string | null;
|
|
375
|
+
lastOutboundAt: Date | string | null;
|
|
376
|
+
temperature: 'HOT' | 'WARM' | 'COLD' | null;
|
|
377
|
+
aiCareStatus: AiCareStatus;
|
|
378
|
+
aiCareStatusSetAt: Date | string | null;
|
|
379
|
+
aiCareStatusSetByName: string | null;
|
|
380
|
+
/** Só presente na resposta do GET de detalhe (não na listagem). */
|
|
381
|
+
aiResumeMode?: AiResumeMode | null;
|
|
382
|
+
[key: string]: unknown;
|
|
383
|
+
}
|
|
384
|
+
interface MessagingConversationsListResponse {
|
|
385
|
+
data: MessagingConversation[];
|
|
386
|
+
meta: {
|
|
387
|
+
total: number;
|
|
388
|
+
page: number;
|
|
389
|
+
limit: number;
|
|
390
|
+
totalPages: number;
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
interface MessagingMessage {
|
|
394
|
+
id: string;
|
|
395
|
+
externalId: string;
|
|
396
|
+
conversationId: string;
|
|
397
|
+
direction: 'inbound' | 'outbound';
|
|
398
|
+
type: string;
|
|
399
|
+
status: string;
|
|
400
|
+
content: Record<string, unknown>;
|
|
401
|
+
waMessageId: string | null;
|
|
402
|
+
media: unknown[];
|
|
403
|
+
sentByType: 'platform_user' | 'api_key' | 'external_agent' | 'whatsapp_app' | null;
|
|
404
|
+
sentById: string | null;
|
|
405
|
+
sentByName: string | null;
|
|
406
|
+
error: string | null;
|
|
407
|
+
errorCode: string | null;
|
|
408
|
+
errorDetails: unknown;
|
|
409
|
+
createdAt: Date | string;
|
|
410
|
+
updatedAt: Date | string;
|
|
411
|
+
}
|
|
412
|
+
interface MessagingMessagesListResponse {
|
|
413
|
+
data: MessagingMessage[];
|
|
414
|
+
meta: {
|
|
415
|
+
total: number;
|
|
416
|
+
page: number;
|
|
417
|
+
limit: number;
|
|
418
|
+
totalPages: number;
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
interface ListConversationsFilters {
|
|
422
|
+
page?: number;
|
|
423
|
+
limit?: number;
|
|
424
|
+
assignedToId?: string | 'unassigned';
|
|
425
|
+
phoneNumberId?: string;
|
|
426
|
+
contactWaId?: string;
|
|
427
|
+
contactName?: string;
|
|
428
|
+
createdFrom?: string;
|
|
429
|
+
createdTo?: string;
|
|
430
|
+
lastMessageFrom?: string;
|
|
431
|
+
lastMessageTo?: string;
|
|
432
|
+
sortBy?: 'default' | 'createdAt' | 'lastMessageAt' | 'contactName';
|
|
433
|
+
sortDirection?: 'asc' | 'desc';
|
|
434
|
+
}
|
|
435
|
+
interface PatchConversationPayload {
|
|
436
|
+
assignedToId?: string | null;
|
|
437
|
+
contactDisplayName?: string | null;
|
|
438
|
+
aiCareStatus?: AiCareStatus;
|
|
439
|
+
/** Só tem efeito quando `aiCareStatus` é 'ACTIVE' — em qualquer outro status o Portal força `null`. */
|
|
440
|
+
aiResumeMode?: AiResumeMode | null;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* `actor` só é respeitado pelo Portal quando o chamador é um papel de sistema/staff (ex.: o
|
|
444
|
+
* atende360-assistant autenticado via APP_API_KEY) — um usuário comum (OWNER/MEMBER) sempre
|
|
445
|
+
* manda como si mesmo, a API ignora um `actor` customizado nesse caso.
|
|
446
|
+
*/
|
|
447
|
+
interface SendMessagePayload {
|
|
448
|
+
phoneNumberId: string;
|
|
449
|
+
to: string;
|
|
450
|
+
type: string;
|
|
451
|
+
content: Record<string, unknown> & {
|
|
452
|
+
id?: string;
|
|
453
|
+
link?: string;
|
|
454
|
+
_media?: {
|
|
455
|
+
storagePath?: string | null;
|
|
456
|
+
mimeType?: string;
|
|
457
|
+
fileSize?: number;
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
replyToWaMessageId?: string;
|
|
461
|
+
actor?: {
|
|
462
|
+
externalUserId: string;
|
|
463
|
+
externalUserName?: string;
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
interface SendMessageResponse {
|
|
467
|
+
messageId: string;
|
|
468
|
+
conversationId: string;
|
|
469
|
+
status: string;
|
|
470
|
+
correlationId: string;
|
|
471
|
+
}
|
|
472
|
+
interface UploadMediaPayload {
|
|
473
|
+
/** Bytes do arquivo (buffer do áudio/imagem/etc. gerado ou recebido). */
|
|
474
|
+
file: Buffer;
|
|
475
|
+
filename: string;
|
|
476
|
+
mimeType: string;
|
|
477
|
+
phoneNumberId: string;
|
|
478
|
+
/**
|
|
479
|
+
* true faz a plataforma transcodificar pra OGG/Opus mono e renderizar como balão de
|
|
480
|
+
* mensagem de voz no WhatsApp (em vez de anexo de áudio genérico) — usar sempre que for
|
|
481
|
+
* uma resposta de TTS da IA.
|
|
482
|
+
*/
|
|
483
|
+
isVoiceNote?: boolean;
|
|
484
|
+
}
|
|
485
|
+
interface UploadMediaResponse {
|
|
486
|
+
id: string | null;
|
|
487
|
+
storagePath: string | null;
|
|
488
|
+
filename: string;
|
|
489
|
+
mimeType: string;
|
|
490
|
+
fileSize: number;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Canal WhatsApp direto (aiatendeWa) — proxy pras rotas `/api/clients/{clientId}/messaging/...`
|
|
495
|
+
* do Portal, que por sua vez falam com a plataforma de mensageria própria
|
|
496
|
+
* (plataforma_whatsapp_coexistence). O atende360-assistant nunca fala direto com essa
|
|
497
|
+
* plataforma — sempre por aqui, autenticado via a mesma `apiKey`/APP_API_KEY já usada pro
|
|
498
|
+
* resto do SDK.
|
|
499
|
+
*/
|
|
500
|
+
declare class MessagingResource extends BaseResource {
|
|
501
|
+
listConversations(clientId: string, filters?: ListConversationsFilters): Promise<MessagingConversationsListResponse>;
|
|
502
|
+
getConversation(clientId: string, conversationId: string): Promise<MessagingConversation>;
|
|
503
|
+
patchConversation(clientId: string, conversationId: string, payload: PatchConversationPayload): Promise<MessagingConversation>;
|
|
504
|
+
getMessages(clientId: string, conversationId: string, params?: {
|
|
505
|
+
page?: number;
|
|
506
|
+
limit?: number;
|
|
507
|
+
}): Promise<MessagingMessagesListResponse>;
|
|
508
|
+
sendMessage(clientId: string, conversationId: string, payload: SendMessagePayload): Promise<SendMessageResponse>;
|
|
509
|
+
/**
|
|
510
|
+
* Upload de mídia (ex.: áudio gerado por TTS) — pré-requisito pra mandar `type: 'audio'` no
|
|
511
|
+
* `sendMessage` (o `content.id` retornado aqui vira `content.id` do envio; `storagePath`
|
|
512
|
+
* precisa ser ecoado em `content._media.storagePath` no send, senão a plataforma não cria o
|
|
513
|
+
* registro de mídia local pra conexões Cloud API).
|
|
514
|
+
*/
|
|
515
|
+
uploadMedia(clientId: string, payload: UploadMediaPayload): Promise<UploadMediaResponse>;
|
|
516
|
+
}
|
|
517
|
+
|
|
313
518
|
declare class PortalClient {
|
|
314
519
|
config: PortalClientConfig;
|
|
315
520
|
httpClient: AxiosInstance;
|
|
316
521
|
clients: ClientsResource;
|
|
317
522
|
knowledge: KnowledgeResource;
|
|
523
|
+
messaging: MessagingResource;
|
|
318
524
|
constructor(config: PortalClientConfig);
|
|
319
525
|
}
|
|
320
526
|
|
|
@@ -324,4 +530,4 @@ declare class PortalApiError extends Error {
|
|
|
324
530
|
constructor(message: string, info?: Partial<PortalApiError>);
|
|
325
531
|
}
|
|
326
532
|
|
|
327
|
-
export { type AiActivationSchedule, type AiConfig, type AiExperiment, type AiExperimentConfig, type AiExperimentCriteria, type AiExperimentVariant, type AiPrompt, type BusinessHours, type CalendarConfig, type Client, type ClientsListResponse, ClientsResource, type DateException, type GetInternalContextParams, type InternalContextChunk, type InternalContextResult, KnowledgeResource, type KommoAccount, type KommoConfig, type LossReasonMapping, type NudgeSettings, type PipelineMapping, PortalApiError, PortalClient, type PortalClientConfig, type StageMapping, type TimeRange, type Wazzup, type WazzupChannel };
|
|
533
|
+
export { type AiActivationSchedule, type AiCareStatus, type AiConfig, type AiExperiment, type AiExperimentConfig, type AiExperimentCriteria, type AiExperimentVariant, type AiPrompt, type AiResumeMode, type BusinessHours, type CalendarConfig, type Client, type ClientsListResponse, ClientsResource, type ConversationHistoryMessage, type DateException, type GetInternalContextParams, type InternalContextChunk, type InternalContextResult, KnowledgeResource, type KommoAccount, type KommoConfig, type ListConversationsFilters, type LossReasonMapping, type MessagingContact, type MessagingConversation, type MessagingConversationsListResponse, type MessagingMessage, type MessagingMessagesListResponse, type MessagingPhoneNumber, MessagingResource, type NudgeSettings, type PatchConversationPayload, type PipelineMapping, PortalApiError, PortalClient, type PortalClientConfig, type SendMessagePayload, type SendMessageResponse, type StageMapping, type TimeRange, type UploadMediaPayload, type UploadMediaResponse, type Wazzup, type WazzupChannel };
|
package/dist/index.d.ts
CHANGED
|
@@ -94,6 +94,14 @@ interface AiConfig {
|
|
|
94
94
|
untaggedLeadAiState?: 'inactive' | 'active' | 'active_for_new_leads';
|
|
95
95
|
/** Estado da IA após handoff. 'inactive' = trava permanente e global (nunca reativa sozinha). 'untag' = remove a tag, elegível pro bootstrap na próxima mensagem. */
|
|
96
96
|
handoffAiState?: 'inactive' | 'untag';
|
|
97
|
+
/** Canal WhatsApp direto (aiatendeWa) — domínio separado das tags Kommo acima, usa Conversation.aiCareStatus/aiResumeMode. Se true (default), conversas novas nesse canal já nascem com aiCareStatus ACTIVE; se false, nascem INACTIVE e exigem ativação manual pelo Portal. */
|
|
98
|
+
aiatendeWaDefaultActive?: boolean;
|
|
99
|
+
/** Canal aiatendeWa: responder em áudio (TTS) quando o lead mandar uma mensagem de áudio. Default true. */
|
|
100
|
+
audioReplyOnInboundAudio?: boolean;
|
|
101
|
+
/** Canal aiatendeWa: responder em áudio em vez de texto quando a resposta gerada passar desse tamanho (caracteres). `undefined`/`null`/`0` desliga esse gatilho específico. Default 300. */
|
|
102
|
+
audioReplyCharThreshold?: number | null;
|
|
103
|
+
/** Canal aiatendeWa: id bruto da voz de TTS escolhida — seu significado depende de qual provider `model` indica no momento do envio (OpenAI e Gemini têm listas de vozes totalmente diferentes). */
|
|
104
|
+
ttsVoice?: string | null;
|
|
97
105
|
/** Ativa a Reflection Agent (segunda passada de revisão/auditoria da resposta) pra este cliente. Ausente/undefined = usa o fallback global (env USE_REFLECTION_AGENT) no atende360-assistant — ver Orchestrator.ts. */
|
|
98
106
|
reflectionAgentEnabled?: boolean;
|
|
99
107
|
/** Limiar mínimo de similaridade (cosine, 0-1) pra um trecho da base de conhecimento entrar no contexto do RAG. `undefined`/`null` = o Portal usa o fallback global 0.5 até o admin calibrar via RAG eval. Aplicado internamente pelo Portal em `POST /api/knowledge/internal/context` — não precisa ser enviado pelo assistant-api. */
|
|
@@ -286,14 +294,32 @@ declare class ClientsResource extends BaseResource {
|
|
|
286
294
|
getByKommoSubdomain(subdomain: string): Promise<Client | null>;
|
|
287
295
|
/** Busca o Client dono de um canal Wazzup (`GET /api/clients?channelId=...`). */
|
|
288
296
|
getByWazzupChannelId(channelId: string): Promise<Client | null>;
|
|
297
|
+
/**
|
|
298
|
+
* Busca o Client pelo seu id direto (`GET /api/clients/{id}`) — inclui `aiConfig` e
|
|
299
|
+
* `messagingConfig` (sem a API key criptografada). Usado pelo canal aiatendeWa, que resolve o
|
|
300
|
+
* tenant a partir do `clientId` já incluído no payload do relay de webhook, sem precisar de
|
|
301
|
+
* um identificador de canal indireto como Kommo subdomain ou Wazzup channelId.
|
|
302
|
+
*/
|
|
303
|
+
getById(clientId: string): Promise<Client | null>;
|
|
289
304
|
}
|
|
290
305
|
|
|
306
|
+
/** Uma mensagem simplificada do histórico da conversa, enviada pro Portal reescrever a
|
|
307
|
+
* pergunta de acompanhamento como consulta autônoma antes de gerar o embedding. */
|
|
308
|
+
interface ConversationHistoryMessage {
|
|
309
|
+
role: 'user' | 'assistant' | 'system' | 'tool';
|
|
310
|
+
content: string;
|
|
311
|
+
}
|
|
291
312
|
interface GetInternalContextParams {
|
|
292
313
|
/** Id do AiConfig do cliente — o Portal usa a `apiKey` configurada nele pra gerar o embedding da pergunta. */
|
|
293
314
|
aiConfigId: string;
|
|
294
315
|
/** Pergunta em texto puro do usuário. O embedding é gerado internamente pelo Portal (RagService.getEmbedding), não pelo chamador. */
|
|
295
316
|
question: string;
|
|
296
|
-
|
|
317
|
+
/** Últimas mensagens da conversa (mais antiga → mais recente), sem incluir `question`. Quando
|
|
318
|
+
* presente e não vazio, o Portal reescreve `question` como uma consulta autônoma (LLM rewrite)
|
|
319
|
+
* antes de buscar na base de conhecimento — melhora o recall em perguntas de acompanhamento
|
|
320
|
+
* (ex.: "e o azul?"). Omitir ou passar array vazio preserva o comportamento anterior (busca
|
|
321
|
+
* direto pela `question`, sem custo extra). */
|
|
322
|
+
conversationHistory?: ConversationHistoryMessage[];
|
|
297
323
|
}
|
|
298
324
|
interface InternalContextChunk {
|
|
299
325
|
chunkId?: string;
|
|
@@ -310,11 +336,191 @@ declare class KnowledgeResource extends BaseResource {
|
|
|
310
336
|
getInternalContext(params: GetInternalContextParams): Promise<InternalContextResult>;
|
|
311
337
|
}
|
|
312
338
|
|
|
339
|
+
type AiCareStatus = 'ACTIVE' | 'INACTIVE' | 'PAUSED';
|
|
340
|
+
type AiResumeMode = 'immediate' | 'next_message';
|
|
341
|
+
interface MessagingContact {
|
|
342
|
+
id: string;
|
|
343
|
+
waId: string;
|
|
344
|
+
profileName: string | null;
|
|
345
|
+
displayName: string | null;
|
|
346
|
+
displayNameSetByName: string | null;
|
|
347
|
+
displayNameSetAt: Date | string | null;
|
|
348
|
+
}
|
|
349
|
+
interface MessagingPhoneNumber {
|
|
350
|
+
id: string;
|
|
351
|
+
phoneNumberId: string;
|
|
352
|
+
displayNumber: string;
|
|
353
|
+
metaConnection: {
|
|
354
|
+
channel: string;
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
interface MessagingConversation {
|
|
358
|
+
id: string;
|
|
359
|
+
contactId: string;
|
|
360
|
+
phoneNumberId: string;
|
|
361
|
+
lastMessageAt: Date | string | null;
|
|
362
|
+
contact: MessagingContact;
|
|
363
|
+
phoneNumber: MessagingPhoneNumber;
|
|
364
|
+
_count: {
|
|
365
|
+
messages: number;
|
|
366
|
+
};
|
|
367
|
+
assignedToId: string | null;
|
|
368
|
+
assignedTo: {
|
|
369
|
+
id: string;
|
|
370
|
+
name: string;
|
|
371
|
+
email: string;
|
|
372
|
+
} | null;
|
|
373
|
+
lastMessage: Record<string, unknown> | null;
|
|
374
|
+
lastInboundAt: Date | string | null;
|
|
375
|
+
lastOutboundAt: Date | string | null;
|
|
376
|
+
temperature: 'HOT' | 'WARM' | 'COLD' | null;
|
|
377
|
+
aiCareStatus: AiCareStatus;
|
|
378
|
+
aiCareStatusSetAt: Date | string | null;
|
|
379
|
+
aiCareStatusSetByName: string | null;
|
|
380
|
+
/** Só presente na resposta do GET de detalhe (não na listagem). */
|
|
381
|
+
aiResumeMode?: AiResumeMode | null;
|
|
382
|
+
[key: string]: unknown;
|
|
383
|
+
}
|
|
384
|
+
interface MessagingConversationsListResponse {
|
|
385
|
+
data: MessagingConversation[];
|
|
386
|
+
meta: {
|
|
387
|
+
total: number;
|
|
388
|
+
page: number;
|
|
389
|
+
limit: number;
|
|
390
|
+
totalPages: number;
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
interface MessagingMessage {
|
|
394
|
+
id: string;
|
|
395
|
+
externalId: string;
|
|
396
|
+
conversationId: string;
|
|
397
|
+
direction: 'inbound' | 'outbound';
|
|
398
|
+
type: string;
|
|
399
|
+
status: string;
|
|
400
|
+
content: Record<string, unknown>;
|
|
401
|
+
waMessageId: string | null;
|
|
402
|
+
media: unknown[];
|
|
403
|
+
sentByType: 'platform_user' | 'api_key' | 'external_agent' | 'whatsapp_app' | null;
|
|
404
|
+
sentById: string | null;
|
|
405
|
+
sentByName: string | null;
|
|
406
|
+
error: string | null;
|
|
407
|
+
errorCode: string | null;
|
|
408
|
+
errorDetails: unknown;
|
|
409
|
+
createdAt: Date | string;
|
|
410
|
+
updatedAt: Date | string;
|
|
411
|
+
}
|
|
412
|
+
interface MessagingMessagesListResponse {
|
|
413
|
+
data: MessagingMessage[];
|
|
414
|
+
meta: {
|
|
415
|
+
total: number;
|
|
416
|
+
page: number;
|
|
417
|
+
limit: number;
|
|
418
|
+
totalPages: number;
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
interface ListConversationsFilters {
|
|
422
|
+
page?: number;
|
|
423
|
+
limit?: number;
|
|
424
|
+
assignedToId?: string | 'unassigned';
|
|
425
|
+
phoneNumberId?: string;
|
|
426
|
+
contactWaId?: string;
|
|
427
|
+
contactName?: string;
|
|
428
|
+
createdFrom?: string;
|
|
429
|
+
createdTo?: string;
|
|
430
|
+
lastMessageFrom?: string;
|
|
431
|
+
lastMessageTo?: string;
|
|
432
|
+
sortBy?: 'default' | 'createdAt' | 'lastMessageAt' | 'contactName';
|
|
433
|
+
sortDirection?: 'asc' | 'desc';
|
|
434
|
+
}
|
|
435
|
+
interface PatchConversationPayload {
|
|
436
|
+
assignedToId?: string | null;
|
|
437
|
+
contactDisplayName?: string | null;
|
|
438
|
+
aiCareStatus?: AiCareStatus;
|
|
439
|
+
/** Só tem efeito quando `aiCareStatus` é 'ACTIVE' — em qualquer outro status o Portal força `null`. */
|
|
440
|
+
aiResumeMode?: AiResumeMode | null;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* `actor` só é respeitado pelo Portal quando o chamador é um papel de sistema/staff (ex.: o
|
|
444
|
+
* atende360-assistant autenticado via APP_API_KEY) — um usuário comum (OWNER/MEMBER) sempre
|
|
445
|
+
* manda como si mesmo, a API ignora um `actor` customizado nesse caso.
|
|
446
|
+
*/
|
|
447
|
+
interface SendMessagePayload {
|
|
448
|
+
phoneNumberId: string;
|
|
449
|
+
to: string;
|
|
450
|
+
type: string;
|
|
451
|
+
content: Record<string, unknown> & {
|
|
452
|
+
id?: string;
|
|
453
|
+
link?: string;
|
|
454
|
+
_media?: {
|
|
455
|
+
storagePath?: string | null;
|
|
456
|
+
mimeType?: string;
|
|
457
|
+
fileSize?: number;
|
|
458
|
+
};
|
|
459
|
+
};
|
|
460
|
+
replyToWaMessageId?: string;
|
|
461
|
+
actor?: {
|
|
462
|
+
externalUserId: string;
|
|
463
|
+
externalUserName?: string;
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
interface SendMessageResponse {
|
|
467
|
+
messageId: string;
|
|
468
|
+
conversationId: string;
|
|
469
|
+
status: string;
|
|
470
|
+
correlationId: string;
|
|
471
|
+
}
|
|
472
|
+
interface UploadMediaPayload {
|
|
473
|
+
/** Bytes do arquivo (buffer do áudio/imagem/etc. gerado ou recebido). */
|
|
474
|
+
file: Buffer;
|
|
475
|
+
filename: string;
|
|
476
|
+
mimeType: string;
|
|
477
|
+
phoneNumberId: string;
|
|
478
|
+
/**
|
|
479
|
+
* true faz a plataforma transcodificar pra OGG/Opus mono e renderizar como balão de
|
|
480
|
+
* mensagem de voz no WhatsApp (em vez de anexo de áudio genérico) — usar sempre que for
|
|
481
|
+
* uma resposta de TTS da IA.
|
|
482
|
+
*/
|
|
483
|
+
isVoiceNote?: boolean;
|
|
484
|
+
}
|
|
485
|
+
interface UploadMediaResponse {
|
|
486
|
+
id: string | null;
|
|
487
|
+
storagePath: string | null;
|
|
488
|
+
filename: string;
|
|
489
|
+
mimeType: string;
|
|
490
|
+
fileSize: number;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Canal WhatsApp direto (aiatendeWa) — proxy pras rotas `/api/clients/{clientId}/messaging/...`
|
|
495
|
+
* do Portal, que por sua vez falam com a plataforma de mensageria própria
|
|
496
|
+
* (plataforma_whatsapp_coexistence). O atende360-assistant nunca fala direto com essa
|
|
497
|
+
* plataforma — sempre por aqui, autenticado via a mesma `apiKey`/APP_API_KEY já usada pro
|
|
498
|
+
* resto do SDK.
|
|
499
|
+
*/
|
|
500
|
+
declare class MessagingResource extends BaseResource {
|
|
501
|
+
listConversations(clientId: string, filters?: ListConversationsFilters): Promise<MessagingConversationsListResponse>;
|
|
502
|
+
getConversation(clientId: string, conversationId: string): Promise<MessagingConversation>;
|
|
503
|
+
patchConversation(clientId: string, conversationId: string, payload: PatchConversationPayload): Promise<MessagingConversation>;
|
|
504
|
+
getMessages(clientId: string, conversationId: string, params?: {
|
|
505
|
+
page?: number;
|
|
506
|
+
limit?: number;
|
|
507
|
+
}): Promise<MessagingMessagesListResponse>;
|
|
508
|
+
sendMessage(clientId: string, conversationId: string, payload: SendMessagePayload): Promise<SendMessageResponse>;
|
|
509
|
+
/**
|
|
510
|
+
* Upload de mídia (ex.: áudio gerado por TTS) — pré-requisito pra mandar `type: 'audio'` no
|
|
511
|
+
* `sendMessage` (o `content.id` retornado aqui vira `content.id` do envio; `storagePath`
|
|
512
|
+
* precisa ser ecoado em `content._media.storagePath` no send, senão a plataforma não cria o
|
|
513
|
+
* registro de mídia local pra conexões Cloud API).
|
|
514
|
+
*/
|
|
515
|
+
uploadMedia(clientId: string, payload: UploadMediaPayload): Promise<UploadMediaResponse>;
|
|
516
|
+
}
|
|
517
|
+
|
|
313
518
|
declare class PortalClient {
|
|
314
519
|
config: PortalClientConfig;
|
|
315
520
|
httpClient: AxiosInstance;
|
|
316
521
|
clients: ClientsResource;
|
|
317
522
|
knowledge: KnowledgeResource;
|
|
523
|
+
messaging: MessagingResource;
|
|
318
524
|
constructor(config: PortalClientConfig);
|
|
319
525
|
}
|
|
320
526
|
|
|
@@ -324,4 +530,4 @@ declare class PortalApiError extends Error {
|
|
|
324
530
|
constructor(message: string, info?: Partial<PortalApiError>);
|
|
325
531
|
}
|
|
326
532
|
|
|
327
|
-
export { type AiActivationSchedule, type AiConfig, type AiExperiment, type AiExperimentConfig, type AiExperimentCriteria, type AiExperimentVariant, type AiPrompt, type BusinessHours, type CalendarConfig, type Client, type ClientsListResponse, ClientsResource, type DateException, type GetInternalContextParams, type InternalContextChunk, type InternalContextResult, KnowledgeResource, type KommoAccount, type KommoConfig, type LossReasonMapping, type NudgeSettings, type PipelineMapping, PortalApiError, PortalClient, type PortalClientConfig, type StageMapping, type TimeRange, type Wazzup, type WazzupChannel };
|
|
533
|
+
export { type AiActivationSchedule, type AiCareStatus, type AiConfig, type AiExperiment, type AiExperimentConfig, type AiExperimentCriteria, type AiExperimentVariant, type AiPrompt, type AiResumeMode, type BusinessHours, type CalendarConfig, type Client, type ClientsListResponse, ClientsResource, type ConversationHistoryMessage, type DateException, type GetInternalContextParams, type InternalContextChunk, type InternalContextResult, KnowledgeResource, type KommoAccount, type KommoConfig, type ListConversationsFilters, type LossReasonMapping, type MessagingContact, type MessagingConversation, type MessagingConversationsListResponse, type MessagingMessage, type MessagingMessagesListResponse, type MessagingPhoneNumber, MessagingResource, type NudgeSettings, type PatchConversationPayload, type PipelineMapping, PortalApiError, PortalClient, type PortalClientConfig, type SendMessagePayload, type SendMessageResponse, type StageMapping, type TimeRange, type UploadMediaPayload, type UploadMediaResponse, type Wazzup, type WazzupChannel };
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
ClientsResource: () => ClientsResource,
|
|
34
34
|
KnowledgeResource: () => KnowledgeResource,
|
|
35
|
+
MessagingResource: () => MessagingResource,
|
|
35
36
|
PortalApiError: () => PortalApiError,
|
|
36
37
|
PortalClient: () => PortalClient
|
|
37
38
|
});
|
|
@@ -48,6 +49,20 @@ var BaseResource = class {
|
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
51
|
|
|
52
|
+
// src/errors.ts
|
|
53
|
+
var PortalApiError = class extends Error {
|
|
54
|
+
status;
|
|
55
|
+
raw;
|
|
56
|
+
constructor(message, info) {
|
|
57
|
+
super(message);
|
|
58
|
+
this.name = "PortalApiError";
|
|
59
|
+
if (info) {
|
|
60
|
+
this.status = info.status;
|
|
61
|
+
this.raw = info.raw;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
51
66
|
// src/resources/clients/index.ts
|
|
52
67
|
var ClientsResource = class extends BaseResource {
|
|
53
68
|
/** Busca o Client dono de um subdomínio Kommo (`GET /api/clients?kommo_subdomain=...`). */
|
|
@@ -64,9 +79,32 @@ var ClientsResource = class extends BaseResource {
|
|
|
64
79
|
});
|
|
65
80
|
return response.data.data[0] ?? null;
|
|
66
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Busca o Client pelo seu id direto (`GET /api/clients/{id}`) — inclui `aiConfig` e
|
|
84
|
+
* `messagingConfig` (sem a API key criptografada). Usado pelo canal aiatendeWa, que resolve o
|
|
85
|
+
* tenant a partir do `clientId` já incluído no payload do relay de webhook, sem precisar de
|
|
86
|
+
* um identificador de canal indireto como Kommo subdomain ou Wazzup channelId.
|
|
87
|
+
*/
|
|
88
|
+
async getById(clientId) {
|
|
89
|
+
try {
|
|
90
|
+
const response = await this.client.get(`/api/clients/${clientId}`);
|
|
91
|
+
return response.data;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error instanceof PortalApiError && error.status === 404) return null;
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
67
97
|
};
|
|
68
98
|
|
|
69
99
|
// src/resources/knowledge/index.ts
|
|
100
|
+
var import_zod = require("zod");
|
|
101
|
+
var internalContextChunkSchema = import_zod.z.object({
|
|
102
|
+
chunkId: import_zod.z.string().optional(),
|
|
103
|
+
content: import_zod.z.string(),
|
|
104
|
+
similarity: import_zod.z.number(),
|
|
105
|
+
metadata: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
106
|
+
});
|
|
107
|
+
var internalContextResultSchema = import_zod.z.array(internalContextChunkSchema);
|
|
70
108
|
var KnowledgeResource = class extends BaseResource {
|
|
71
109
|
/** Recupera trechos relevantes da base RAG do cliente pra uma pergunta em texto puro (`POST /api/knowledge/internal/context`). O Portal gera o embedding internamente usando a `apiKey` do AiConfig. */
|
|
72
110
|
async getInternalContext(params) {
|
|
@@ -75,21 +113,72 @@ var KnowledgeResource = class extends BaseResource {
|
|
|
75
113
|
question: params.question,
|
|
76
114
|
conversationHistory: params.conversationHistory
|
|
77
115
|
});
|
|
78
|
-
|
|
116
|
+
const parsed = internalContextResultSchema.safeParse(response.data);
|
|
117
|
+
if (!parsed.success) {
|
|
118
|
+
throw new PortalApiError("Resposta inv\xE1lida de /api/knowledge/internal/context", {
|
|
119
|
+
raw: parsed.error.flatten()
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return parsed.data;
|
|
79
123
|
}
|
|
80
124
|
};
|
|
81
125
|
|
|
82
|
-
// src/
|
|
83
|
-
var
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
126
|
+
// src/resources/messaging/index.ts
|
|
127
|
+
var MessagingResource = class extends BaseResource {
|
|
128
|
+
async listConversations(clientId, filters) {
|
|
129
|
+
const response = await this.client.get(
|
|
130
|
+
`/api/clients/${clientId}/messaging/conversations`,
|
|
131
|
+
{ params: filters }
|
|
132
|
+
);
|
|
133
|
+
return response.data;
|
|
134
|
+
}
|
|
135
|
+
async getConversation(clientId, conversationId) {
|
|
136
|
+
const response = await this.client.get(
|
|
137
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}`
|
|
138
|
+
);
|
|
139
|
+
return response.data;
|
|
140
|
+
}
|
|
141
|
+
async patchConversation(clientId, conversationId, payload) {
|
|
142
|
+
const response = await this.client.patch(
|
|
143
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}`,
|
|
144
|
+
payload
|
|
145
|
+
);
|
|
146
|
+
return response.data;
|
|
147
|
+
}
|
|
148
|
+
async getMessages(clientId, conversationId, params) {
|
|
149
|
+
const response = await this.client.get(
|
|
150
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,
|
|
151
|
+
{ params }
|
|
152
|
+
);
|
|
153
|
+
return response.data;
|
|
154
|
+
}
|
|
155
|
+
async sendMessage(clientId, conversationId, payload) {
|
|
156
|
+
const response = await this.client.post(
|
|
157
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,
|
|
158
|
+
payload
|
|
159
|
+
);
|
|
160
|
+
return response.data;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Upload de mídia (ex.: áudio gerado por TTS) — pré-requisito pra mandar `type: 'audio'` no
|
|
164
|
+
* `sendMessage` (o `content.id` retornado aqui vira `content.id` do envio; `storagePath`
|
|
165
|
+
* precisa ser ecoado em `content._media.storagePath` no send, senão a plataforma não cria o
|
|
166
|
+
* registro de mídia local pra conexões Cloud API).
|
|
167
|
+
*/
|
|
168
|
+
async uploadMedia(clientId, payload) {
|
|
169
|
+
const form = new FormData();
|
|
170
|
+
form.append("phoneNumberId", payload.phoneNumberId);
|
|
171
|
+
if (payload.isVoiceNote) form.append("isVoiceNote", "true");
|
|
172
|
+
form.append(
|
|
173
|
+
"file",
|
|
174
|
+
new Blob([new Uint8Array(payload.file)], { type: payload.mimeType }),
|
|
175
|
+
payload.filename
|
|
176
|
+
);
|
|
177
|
+
const response = await this.client.post(
|
|
178
|
+
`/api/clients/${clientId}/messaging/media`,
|
|
179
|
+
form
|
|
180
|
+
);
|
|
181
|
+
return response.data;
|
|
93
182
|
}
|
|
94
183
|
};
|
|
95
184
|
|
|
@@ -100,6 +189,7 @@ var PortalClient = class {
|
|
|
100
189
|
httpClient;
|
|
101
190
|
clients;
|
|
102
191
|
knowledge;
|
|
192
|
+
messaging;
|
|
103
193
|
constructor(config) {
|
|
104
194
|
this.config = config;
|
|
105
195
|
this.httpClient = import_axios.default.create({
|
|
@@ -125,12 +215,14 @@ var PortalClient = class {
|
|
|
125
215
|
);
|
|
126
216
|
this.clients = new ClientsResource(this.httpClient);
|
|
127
217
|
this.knowledge = new KnowledgeResource(this.httpClient);
|
|
218
|
+
this.messaging = new MessagingResource(this.httpClient);
|
|
128
219
|
}
|
|
129
220
|
};
|
|
130
221
|
// Annotate the CommonJS export names for ESM import in node:
|
|
131
222
|
0 && (module.exports = {
|
|
132
223
|
ClientsResource,
|
|
133
224
|
KnowledgeResource,
|
|
225
|
+
MessagingResource,
|
|
134
226
|
PortalApiError,
|
|
135
227
|
PortalClient
|
|
136
228
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/base.ts","../src/resources/clients/index.ts","../src/resources/knowledge/index.ts","../src/errors.ts"],"sourcesContent":["export * from './client';\nexport * from './types';\nexport * from './errors';\nexport * from './resources/clients';\nexport * from './resources/clients/types';\nexport * from './resources/knowledge';\nexport * from './resources/knowledge/types';\n","import axios, { AxiosInstance } from 'axios';\nimport { PortalClientConfig } from './types';\nimport { ClientsResource } from './resources/clients';\nimport { KnowledgeResource } from './resources/knowledge';\nimport { PortalApiError } from './errors';\n\nconst DEFAULT_BASE_URL = 'https://portal.aiatende.com.br';\n\nexport class PortalClient {\n public config: PortalClientConfig;\n public httpClient: AxiosInstance;\n\n public clients: ClientsResource;\n public knowledge: KnowledgeResource;\n\n constructor(config: PortalClientConfig) {\n this.config = config;\n\n this.httpClient = axios.create({\n baseURL: config.baseUrl || DEFAULT_BASE_URL,\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'x-internal-token': config.apiKey\n }\n });\n\n this.httpClient.interceptors.response.use(\n (response) => response,\n (error) => {\n if (error.response) {\n const errData = error.response.data;\n throw new PortalApiError(errData?.error || 'Portal API Error', {\n status: error.response.status,\n raw: errData\n });\n }\n throw error;\n }\n );\n\n this.clients = new ClientsResource(this.httpClient);\n this.knowledge = new KnowledgeResource(this.httpClient);\n }\n}\n","import { AxiosInstance } from 'axios';\n\nexport abstract class BaseResource {\n protected client: AxiosInstance;\n\n constructor(client: AxiosInstance) {\n this.client = client;\n }\n}\n","import { BaseResource } from '../../base';\nimport { Client, ClientsListResponse } from './types';\n\nexport class ClientsResource extends BaseResource {\n /** Busca o Client dono de um subdomínio Kommo (`GET /api/clients?kommo_subdomain=...`). */\n async getByKommoSubdomain(subdomain: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { kommo_subdomain: subdomain, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n\n /** Busca o Client dono de um canal Wazzup (`GET /api/clients?channelId=...`). */\n async getByWazzupChannelId(channelId: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { channelId, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n}\n","import { BaseResource } from '../../base';\nimport { GetInternalContextParams, InternalContextResult } from './types';\n\nexport class KnowledgeResource extends BaseResource {\n /** Recupera trechos relevantes da base RAG do cliente pra uma pergunta em texto puro (`POST /api/knowledge/internal/context`). O Portal gera o embedding internamente usando a `apiKey` do AiConfig. */\n async getInternalContext(params: GetInternalContextParams): Promise<InternalContextResult> {\n const response = await this.client.post<InternalContextResult>('/api/knowledge/internal/context', {\n aiConfigId: params.aiConfigId,\n question: params.question,\n conversationHistory: params.conversationHistory\n });\n return response.data;\n }\n}\n","export class PortalApiError extends Error {\n status?: number;\n raw?: unknown;\n\n constructor(message: string, info?: Partial<PortalApiError>) {\n super(message);\n this.name = 'PortalApiError';\n\n if (info) {\n this.status = info.status;\n this.raw = info.raw;\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAAqC;;;ACE9B,IAAe,eAAf,MAA4B;AAAA,EACvB;AAAA,EAEV,YAAY,QAAuB;AACjC,SAAK,SAAS;AAAA,EAChB;AACF;;;ACLO,IAAM,kBAAN,cAA8B,aAAa;AAAA;AAAA,EAEhD,MAAM,oBAAoB,WAA2C;AACnE,UAAM,WAAW,MAAM,KAAK,OAAO,IAAyB,gBAAgB;AAAA,MAC1E,QAAQ,EAAE,iBAAiB,WAAW,gBAAgB,KAAK;AAAA,IAC7D,CAAC;AACD,WAAO,SAAS,KAAK,KAAK,CAAC,KAAK;AAAA,EAClC;AAAA;AAAA,EAGA,MAAM,qBAAqB,WAA2C;AACpE,UAAM,WAAW,MAAM,KAAK,OAAO,IAAyB,gBAAgB;AAAA,MAC1E,QAAQ,EAAE,WAAW,gBAAgB,KAAK;AAAA,IAC5C,CAAC;AACD,WAAO,SAAS,KAAK,KAAK,CAAC,KAAK;AAAA,EAClC;AACF;;;AChBO,IAAM,oBAAN,cAAgC,aAAa;AAAA;AAAA,EAElD,MAAM,mBAAmB,QAAkE;AACzF,UAAM,WAAW,MAAM,KAAK,OAAO,KAA4B,mCAAmC;AAAA,MAChG,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,qBAAqB,OAAO;AAAA,IAC9B,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AACF;;;ACbO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC;AAAA,EACA;AAAA,EAEA,YAAY,SAAiB,MAAgC;AAC3D,UAAM,OAAO;AACb,SAAK,OAAO;AAEZ,QAAI,MAAM;AACR,WAAK,SAAS,KAAK;AACnB,WAAK,MAAM,KAAK;AAAA,IAClB;AAAA,EACF;AACF;;;AJPA,IAAM,mBAAmB;AAElB,IAAM,eAAN,MAAmB;AAAA,EACjB;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EAEP,YAAY,QAA4B;AACtC,SAAK,SAAS;AAEd,SAAK,aAAa,aAAAA,QAAM,OAAO;AAAA,MAC7B,SAAS,OAAO,WAAW;AAAA,MAC3B,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,aAAa,OAAO;AAAA,QACpB,oBAAoB,OAAO;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,SAAK,WAAW,aAAa,SAAS;AAAA,MACpC,CAAC,aAAa;AAAA,MACd,CAAC,UAAU;AACT,YAAI,MAAM,UAAU;AAClB,gBAAM,UAAU,MAAM,SAAS;AAC/B,gBAAM,IAAI,eAAe,SAAS,SAAS,oBAAoB;AAAA,YAC7D,QAAQ,MAAM,SAAS;AAAA,YACvB,KAAK;AAAA,UACP,CAAC;AAAA,QACH;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,SAAK,UAAU,IAAI,gBAAgB,KAAK,UAAU;AAClD,SAAK,YAAY,IAAI,kBAAkB,KAAK,UAAU;AAAA,EACxD;AACF;","names":["axios"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts","../src/base.ts","../src/errors.ts","../src/resources/clients/index.ts","../src/resources/knowledge/index.ts","../src/resources/messaging/index.ts"],"sourcesContent":["export * from './client';\nexport * from './types';\nexport * from './errors';\nexport * from './resources/clients';\nexport * from './resources/clients/types';\nexport * from './resources/knowledge';\nexport * from './resources/knowledge/types';\nexport * from './resources/messaging';\nexport * from './resources/messaging/types';\n","import axios, { AxiosInstance } from 'axios';\nimport { PortalClientConfig } from './types';\nimport { ClientsResource } from './resources/clients';\nimport { KnowledgeResource } from './resources/knowledge';\nimport { MessagingResource } from './resources/messaging';\nimport { PortalApiError } from './errors';\n\nconst DEFAULT_BASE_URL = 'https://portal.aiatende.com.br';\n\nexport class PortalClient {\n public config: PortalClientConfig;\n public httpClient: AxiosInstance;\n\n public clients: ClientsResource;\n public knowledge: KnowledgeResource;\n public messaging: MessagingResource;\n\n constructor(config: PortalClientConfig) {\n this.config = config;\n\n this.httpClient = axios.create({\n baseURL: config.baseUrl || DEFAULT_BASE_URL,\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'x-internal-token': config.apiKey\n }\n });\n\n this.httpClient.interceptors.response.use(\n (response) => response,\n (error) => {\n if (error.response) {\n const errData = error.response.data;\n throw new PortalApiError(errData?.error || 'Portal API Error', {\n status: error.response.status,\n raw: errData\n });\n }\n throw error;\n }\n );\n\n this.clients = new ClientsResource(this.httpClient);\n this.knowledge = new KnowledgeResource(this.httpClient);\n this.messaging = new MessagingResource(this.httpClient);\n }\n}\n","import { AxiosInstance } from 'axios';\n\nexport abstract class BaseResource {\n protected client: AxiosInstance;\n\n constructor(client: AxiosInstance) {\n this.client = client;\n }\n}\n","export class PortalApiError extends Error {\n status?: number;\n raw?: unknown;\n\n constructor(message: string, info?: Partial<PortalApiError>) {\n super(message);\n this.name = 'PortalApiError';\n\n if (info) {\n this.status = info.status;\n this.raw = info.raw;\n }\n }\n}\n","import { BaseResource } from '../../base';\nimport { PortalApiError } from '../../errors';\nimport { Client, ClientsListResponse } from './types';\n\nexport class ClientsResource extends BaseResource {\n /** Busca o Client dono de um subdomínio Kommo (`GET /api/clients?kommo_subdomain=...`). */\n async getByKommoSubdomain(subdomain: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { kommo_subdomain: subdomain, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n\n /** Busca o Client dono de um canal Wazzup (`GET /api/clients?channelId=...`). */\n async getByWazzupChannelId(channelId: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { channelId, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n\n /**\n * Busca o Client pelo seu id direto (`GET /api/clients/{id}`) — inclui `aiConfig` e\n * `messagingConfig` (sem a API key criptografada). Usado pelo canal aiatendeWa, que resolve o\n * tenant a partir do `clientId` já incluído no payload do relay de webhook, sem precisar de\n * um identificador de canal indireto como Kommo subdomain ou Wazzup channelId.\n */\n async getById(clientId: string): Promise<Client | null> {\n try {\n const response = await this.client.get<Client>(`/api/clients/${clientId}`);\n return response.data;\n } catch (error) {\n if (error instanceof PortalApiError && error.status === 404) return null;\n throw error;\n }\n }\n}\n","import { z } from 'zod';\nimport { BaseResource } from '../../base';\nimport { PortalApiError } from '../../errors';\nimport { GetInternalContextParams, InternalContextResult } from './types';\n\nconst internalContextChunkSchema = z.object({\n chunkId: z.string().optional(),\n content: z.string(),\n similarity: z.number(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst internalContextResultSchema = z.array(internalContextChunkSchema);\n\nexport class KnowledgeResource extends BaseResource {\n /** Recupera trechos relevantes da base RAG do cliente pra uma pergunta em texto puro (`POST /api/knowledge/internal/context`). O Portal gera o embedding internamente usando a `apiKey` do AiConfig. */\n async getInternalContext(params: GetInternalContextParams): Promise<InternalContextResult> {\n const response = await this.client.post<unknown>('/api/knowledge/internal/context', {\n aiConfigId: params.aiConfigId,\n question: params.question,\n conversationHistory: params.conversationHistory\n });\n\n const parsed = internalContextResultSchema.safeParse(response.data);\n if (!parsed.success) {\n throw new PortalApiError('Resposta inválida de /api/knowledge/internal/context', {\n raw: parsed.error.flatten(),\n });\n }\n return parsed.data;\n }\n}\n","import { BaseResource } from '../../base';\nimport {\n ListConversationsFilters,\n MessagingConversation,\n MessagingConversationsListResponse,\n MessagingMessagesListResponse,\n PatchConversationPayload,\n SendMessagePayload,\n SendMessageResponse,\n UploadMediaPayload,\n UploadMediaResponse,\n} from './types';\n\n/**\n * Canal WhatsApp direto (aiatendeWa) — proxy pras rotas `/api/clients/{clientId}/messaging/...`\n * do Portal, que por sua vez falam com a plataforma de mensageria própria\n * (plataforma_whatsapp_coexistence). O atende360-assistant nunca fala direto com essa\n * plataforma — sempre por aqui, autenticado via a mesma `apiKey`/APP_API_KEY já usada pro\n * resto do SDK.\n */\nexport class MessagingResource extends BaseResource {\n async listConversations(\n clientId: string,\n filters?: ListConversationsFilters,\n ): Promise<MessagingConversationsListResponse> {\n const response = await this.client.get<MessagingConversationsListResponse>(\n `/api/clients/${clientId}/messaging/conversations`,\n { params: filters },\n );\n return response.data;\n }\n\n async getConversation(clientId: string, conversationId: string): Promise<MessagingConversation> {\n const response = await this.client.get<MessagingConversation>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}`,\n );\n return response.data;\n }\n\n async patchConversation(\n clientId: string,\n conversationId: string,\n payload: PatchConversationPayload,\n ): Promise<MessagingConversation> {\n const response = await this.client.patch<MessagingConversation>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}`,\n payload,\n );\n return response.data;\n }\n\n async getMessages(\n clientId: string,\n conversationId: string,\n params?: { page?: number; limit?: number },\n ): Promise<MessagingMessagesListResponse> {\n const response = await this.client.get<MessagingMessagesListResponse>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,\n { params },\n );\n return response.data;\n }\n\n async sendMessage(\n clientId: string,\n conversationId: string,\n payload: SendMessagePayload,\n ): Promise<SendMessageResponse> {\n const response = await this.client.post<SendMessageResponse>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,\n payload,\n );\n return response.data;\n }\n\n /**\n * Upload de mídia (ex.: áudio gerado por TTS) — pré-requisito pra mandar `type: 'audio'` no\n * `sendMessage` (o `content.id` retornado aqui vira `content.id` do envio; `storagePath`\n * precisa ser ecoado em `content._media.storagePath` no send, senão a plataforma não cria o\n * registro de mídia local pra conexões Cloud API).\n */\n async uploadMedia(clientId: string, payload: UploadMediaPayload): Promise<UploadMediaResponse> {\n const form = new FormData();\n // Ordem importa: phoneNumberId/isVoiceNote precisam vir ANTES de file no multipart — o\n // parser do Portal (e o da plataforma por trás dele) lê em stream.\n form.append('phoneNumberId', payload.phoneNumberId);\n if (payload.isVoiceNote) form.append('isVoiceNote', 'true');\n form.append(\n 'file',\n new Blob([new Uint8Array(payload.file)], { type: payload.mimeType }),\n payload.filename,\n );\n\n const response = await this.client.post<UploadMediaResponse>(\n `/api/clients/${clientId}/messaging/media`,\n form,\n );\n return response.data;\n }\n}\n"],"mappings":"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","names":["axios"]}
|
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,20 @@ var BaseResource = class {
|
|
|
9
9
|
}
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// src/errors.ts
|
|
13
|
+
var PortalApiError = class extends Error {
|
|
14
|
+
status;
|
|
15
|
+
raw;
|
|
16
|
+
constructor(message, info) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "PortalApiError";
|
|
19
|
+
if (info) {
|
|
20
|
+
this.status = info.status;
|
|
21
|
+
this.raw = info.raw;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
12
26
|
// src/resources/clients/index.ts
|
|
13
27
|
var ClientsResource = class extends BaseResource {
|
|
14
28
|
/** Busca o Client dono de um subdomínio Kommo (`GET /api/clients?kommo_subdomain=...`). */
|
|
@@ -25,9 +39,32 @@ var ClientsResource = class extends BaseResource {
|
|
|
25
39
|
});
|
|
26
40
|
return response.data.data[0] ?? null;
|
|
27
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Busca o Client pelo seu id direto (`GET /api/clients/{id}`) — inclui `aiConfig` e
|
|
44
|
+
* `messagingConfig` (sem a API key criptografada). Usado pelo canal aiatendeWa, que resolve o
|
|
45
|
+
* tenant a partir do `clientId` já incluído no payload do relay de webhook, sem precisar de
|
|
46
|
+
* um identificador de canal indireto como Kommo subdomain ou Wazzup channelId.
|
|
47
|
+
*/
|
|
48
|
+
async getById(clientId) {
|
|
49
|
+
try {
|
|
50
|
+
const response = await this.client.get(`/api/clients/${clientId}`);
|
|
51
|
+
return response.data;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error instanceof PortalApiError && error.status === 404) return null;
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
28
57
|
};
|
|
29
58
|
|
|
30
59
|
// src/resources/knowledge/index.ts
|
|
60
|
+
import { z } from "zod";
|
|
61
|
+
var internalContextChunkSchema = z.object({
|
|
62
|
+
chunkId: z.string().optional(),
|
|
63
|
+
content: z.string(),
|
|
64
|
+
similarity: z.number(),
|
|
65
|
+
metadata: z.record(z.string(), z.unknown()).optional()
|
|
66
|
+
});
|
|
67
|
+
var internalContextResultSchema = z.array(internalContextChunkSchema);
|
|
31
68
|
var KnowledgeResource = class extends BaseResource {
|
|
32
69
|
/** Recupera trechos relevantes da base RAG do cliente pra uma pergunta em texto puro (`POST /api/knowledge/internal/context`). O Portal gera o embedding internamente usando a `apiKey` do AiConfig. */
|
|
33
70
|
async getInternalContext(params) {
|
|
@@ -36,21 +73,72 @@ var KnowledgeResource = class extends BaseResource {
|
|
|
36
73
|
question: params.question,
|
|
37
74
|
conversationHistory: params.conversationHistory
|
|
38
75
|
});
|
|
39
|
-
|
|
76
|
+
const parsed = internalContextResultSchema.safeParse(response.data);
|
|
77
|
+
if (!parsed.success) {
|
|
78
|
+
throw new PortalApiError("Resposta inv\xE1lida de /api/knowledge/internal/context", {
|
|
79
|
+
raw: parsed.error.flatten()
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return parsed.data;
|
|
40
83
|
}
|
|
41
84
|
};
|
|
42
85
|
|
|
43
|
-
// src/
|
|
44
|
-
var
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
86
|
+
// src/resources/messaging/index.ts
|
|
87
|
+
var MessagingResource = class extends BaseResource {
|
|
88
|
+
async listConversations(clientId, filters) {
|
|
89
|
+
const response = await this.client.get(
|
|
90
|
+
`/api/clients/${clientId}/messaging/conversations`,
|
|
91
|
+
{ params: filters }
|
|
92
|
+
);
|
|
93
|
+
return response.data;
|
|
94
|
+
}
|
|
95
|
+
async getConversation(clientId, conversationId) {
|
|
96
|
+
const response = await this.client.get(
|
|
97
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}`
|
|
98
|
+
);
|
|
99
|
+
return response.data;
|
|
100
|
+
}
|
|
101
|
+
async patchConversation(clientId, conversationId, payload) {
|
|
102
|
+
const response = await this.client.patch(
|
|
103
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}`,
|
|
104
|
+
payload
|
|
105
|
+
);
|
|
106
|
+
return response.data;
|
|
107
|
+
}
|
|
108
|
+
async getMessages(clientId, conversationId, params) {
|
|
109
|
+
const response = await this.client.get(
|
|
110
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,
|
|
111
|
+
{ params }
|
|
112
|
+
);
|
|
113
|
+
return response.data;
|
|
114
|
+
}
|
|
115
|
+
async sendMessage(clientId, conversationId, payload) {
|
|
116
|
+
const response = await this.client.post(
|
|
117
|
+
`/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,
|
|
118
|
+
payload
|
|
119
|
+
);
|
|
120
|
+
return response.data;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Upload de mídia (ex.: áudio gerado por TTS) — pré-requisito pra mandar `type: 'audio'` no
|
|
124
|
+
* `sendMessage` (o `content.id` retornado aqui vira `content.id` do envio; `storagePath`
|
|
125
|
+
* precisa ser ecoado em `content._media.storagePath` no send, senão a plataforma não cria o
|
|
126
|
+
* registro de mídia local pra conexões Cloud API).
|
|
127
|
+
*/
|
|
128
|
+
async uploadMedia(clientId, payload) {
|
|
129
|
+
const form = new FormData();
|
|
130
|
+
form.append("phoneNumberId", payload.phoneNumberId);
|
|
131
|
+
if (payload.isVoiceNote) form.append("isVoiceNote", "true");
|
|
132
|
+
form.append(
|
|
133
|
+
"file",
|
|
134
|
+
new Blob([new Uint8Array(payload.file)], { type: payload.mimeType }),
|
|
135
|
+
payload.filename
|
|
136
|
+
);
|
|
137
|
+
const response = await this.client.post(
|
|
138
|
+
`/api/clients/${clientId}/messaging/media`,
|
|
139
|
+
form
|
|
140
|
+
);
|
|
141
|
+
return response.data;
|
|
54
142
|
}
|
|
55
143
|
};
|
|
56
144
|
|
|
@@ -61,6 +149,7 @@ var PortalClient = class {
|
|
|
61
149
|
httpClient;
|
|
62
150
|
clients;
|
|
63
151
|
knowledge;
|
|
152
|
+
messaging;
|
|
64
153
|
constructor(config) {
|
|
65
154
|
this.config = config;
|
|
66
155
|
this.httpClient = axios.create({
|
|
@@ -86,11 +175,13 @@ var PortalClient = class {
|
|
|
86
175
|
);
|
|
87
176
|
this.clients = new ClientsResource(this.httpClient);
|
|
88
177
|
this.knowledge = new KnowledgeResource(this.httpClient);
|
|
178
|
+
this.messaging = new MessagingResource(this.httpClient);
|
|
89
179
|
}
|
|
90
180
|
};
|
|
91
181
|
export {
|
|
92
182
|
ClientsResource,
|
|
93
183
|
KnowledgeResource,
|
|
184
|
+
MessagingResource,
|
|
94
185
|
PortalApiError,
|
|
95
186
|
PortalClient
|
|
96
187
|
};
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts","../src/base.ts","../src/resources/clients/index.ts","../src/resources/knowledge/index.ts","../src/errors.ts"],"sourcesContent":["import axios, { AxiosInstance } from 'axios';\nimport { PortalClientConfig } from './types';\nimport { ClientsResource } from './resources/clients';\nimport { KnowledgeResource } from './resources/knowledge';\nimport { PortalApiError } from './errors';\n\nconst DEFAULT_BASE_URL = 'https://portal.aiatende.com.br';\n\nexport class PortalClient {\n public config: PortalClientConfig;\n public httpClient: AxiosInstance;\n\n public clients: ClientsResource;\n public knowledge: KnowledgeResource;\n\n constructor(config: PortalClientConfig) {\n this.config = config;\n\n this.httpClient = axios.create({\n baseURL: config.baseUrl || DEFAULT_BASE_URL,\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'x-internal-token': config.apiKey\n }\n });\n\n this.httpClient.interceptors.response.use(\n (response) => response,\n (error) => {\n if (error.response) {\n const errData = error.response.data;\n throw new PortalApiError(errData?.error || 'Portal API Error', {\n status: error.response.status,\n raw: errData\n });\n }\n throw error;\n }\n );\n\n this.clients = new ClientsResource(this.httpClient);\n this.knowledge = new KnowledgeResource(this.httpClient);\n }\n}\n","import { AxiosInstance } from 'axios';\n\nexport abstract class BaseResource {\n protected client: AxiosInstance;\n\n constructor(client: AxiosInstance) {\n this.client = client;\n }\n}\n","import { BaseResource } from '../../base';\nimport { Client, ClientsListResponse } from './types';\n\nexport class ClientsResource extends BaseResource {\n /** Busca o Client dono de um subdomínio Kommo (`GET /api/clients?kommo_subdomain=...`). */\n async getByKommoSubdomain(subdomain: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { kommo_subdomain: subdomain, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n\n /** Busca o Client dono de um canal Wazzup (`GET /api/clients?channelId=...`). */\n async getByWazzupChannelId(channelId: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { channelId, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n}\n","import { BaseResource } from '../../base';\nimport { GetInternalContextParams, InternalContextResult } from './types';\n\nexport class KnowledgeResource extends BaseResource {\n /** Recupera trechos relevantes da base RAG do cliente pra uma pergunta em texto puro (`POST /api/knowledge/internal/context`). O Portal gera o embedding internamente usando a `apiKey` do AiConfig. */\n async getInternalContext(params: GetInternalContextParams): Promise<InternalContextResult> {\n const response = await this.client.post<InternalContextResult>('/api/knowledge/internal/context', {\n aiConfigId: params.aiConfigId,\n question: params.question,\n conversationHistory: params.conversationHistory\n });\n return response.data;\n }\n}\n","export class PortalApiError extends Error {\n status?: number;\n raw?: unknown;\n\n constructor(message: string, info?: Partial<PortalApiError>) {\n super(message);\n this.name = 'PortalApiError';\n\n if (info) {\n this.status = info.status;\n this.raw = info.raw;\n }\n }\n}\n"],"mappings":";AAAA,OAAO,WAA8B;;;ACE9B,IAAe,eAAf,MAA4B;AAAA,EACvB;AAAA,EAEV,YAAY,QAAuB;AACjC,SAAK,SAAS;AAAA,EAChB;AACF;;;ACLO,IAAM,kBAAN,cAA8B,aAAa;AAAA;AAAA,EAEhD,MAAM,oBAAoB,WAA2C;AACnE,UAAM,WAAW,MAAM,KAAK,OAAO,IAAyB,gBAAgB;AAAA,MAC1E,QAAQ,EAAE,iBAAiB,WAAW,gBAAgB,KAAK;AAAA,IAC7D,CAAC;AACD,WAAO,SAAS,KAAK,KAAK,CAAC,KAAK;AAAA,EAClC;AAAA;AAAA,EAGA,MAAM,qBAAqB,WAA2C;AACpE,UAAM,WAAW,MAAM,KAAK,OAAO,IAAyB,gBAAgB;AAAA,MAC1E,QAAQ,EAAE,WAAW,gBAAgB,KAAK;AAAA,IAC5C,CAAC;AACD,WAAO,SAAS,KAAK,KAAK,CAAC,KAAK;AAAA,EAClC;AACF;;;AChBO,IAAM,oBAAN,cAAgC,aAAa;AAAA;AAAA,EAElD,MAAM,mBAAmB,QAAkE;AACzF,UAAM,WAAW,MAAM,KAAK,OAAO,KAA4B,mCAAmC;AAAA,MAChG,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB,qBAAqB,OAAO;AAAA,IAC9B,CAAC;AACD,WAAO,SAAS;AAAA,EAClB;AACF;;;ACbO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC;AAAA,EACA;AAAA,EAEA,YAAY,SAAiB,MAAgC;AAC3D,UAAM,OAAO;AACb,SAAK,OAAO;AAEZ,QAAI,MAAM;AACR,WAAK,SAAS,KAAK;AACnB,WAAK,MAAM,KAAK;AAAA,IAClB;AAAA,EACF;AACF;;;AJPA,IAAM,mBAAmB;AAElB,IAAM,eAAN,MAAmB;AAAA,EACjB;AAAA,EACA;AAAA,EAEA;AAAA,EACA;AAAA,EAEP,YAAY,QAA4B;AACtC,SAAK,SAAS;AAEd,SAAK,aAAa,MAAM,OAAO;AAAA,MAC7B,SAAS,OAAO,WAAW;AAAA,MAC3B,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,aAAa,OAAO;AAAA,QACpB,oBAAoB,OAAO;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,SAAK,WAAW,aAAa,SAAS;AAAA,MACpC,CAAC,aAAa;AAAA,MACd,CAAC,UAAU;AACT,YAAI,MAAM,UAAU;AAClB,gBAAM,UAAU,MAAM,SAAS;AAC/B,gBAAM,IAAI,eAAe,SAAS,SAAS,oBAAoB;AAAA,YAC7D,QAAQ,MAAM,SAAS;AAAA,YACvB,KAAK;AAAA,UACP,CAAC;AAAA,QACH;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,SAAK,UAAU,IAAI,gBAAgB,KAAK,UAAU;AAClD,SAAK,YAAY,IAAI,kBAAkB,KAAK,UAAU;AAAA,EACxD;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts","../src/base.ts","../src/errors.ts","../src/resources/clients/index.ts","../src/resources/knowledge/index.ts","../src/resources/messaging/index.ts"],"sourcesContent":["import axios, { AxiosInstance } from 'axios';\nimport { PortalClientConfig } from './types';\nimport { ClientsResource } from './resources/clients';\nimport { KnowledgeResource } from './resources/knowledge';\nimport { MessagingResource } from './resources/messaging';\nimport { PortalApiError } from './errors';\n\nconst DEFAULT_BASE_URL = 'https://portal.aiatende.com.br';\n\nexport class PortalClient {\n public config: PortalClientConfig;\n public httpClient: AxiosInstance;\n\n public clients: ClientsResource;\n public knowledge: KnowledgeResource;\n public messaging: MessagingResource;\n\n constructor(config: PortalClientConfig) {\n this.config = config;\n\n this.httpClient = axios.create({\n baseURL: config.baseUrl || DEFAULT_BASE_URL,\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'x-internal-token': config.apiKey\n }\n });\n\n this.httpClient.interceptors.response.use(\n (response) => response,\n (error) => {\n if (error.response) {\n const errData = error.response.data;\n throw new PortalApiError(errData?.error || 'Portal API Error', {\n status: error.response.status,\n raw: errData\n });\n }\n throw error;\n }\n );\n\n this.clients = new ClientsResource(this.httpClient);\n this.knowledge = new KnowledgeResource(this.httpClient);\n this.messaging = new MessagingResource(this.httpClient);\n }\n}\n","import { AxiosInstance } from 'axios';\n\nexport abstract class BaseResource {\n protected client: AxiosInstance;\n\n constructor(client: AxiosInstance) {\n this.client = client;\n }\n}\n","export class PortalApiError extends Error {\n status?: number;\n raw?: unknown;\n\n constructor(message: string, info?: Partial<PortalApiError>) {\n super(message);\n this.name = 'PortalApiError';\n\n if (info) {\n this.status = info.status;\n this.raw = info.raw;\n }\n }\n}\n","import { BaseResource } from '../../base';\nimport { PortalApiError } from '../../errors';\nimport { Client, ClientsListResponse } from './types';\n\nexport class ClientsResource extends BaseResource {\n /** Busca o Client dono de um subdomínio Kommo (`GET /api/clients?kommo_subdomain=...`). */\n async getByKommoSubdomain(subdomain: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { kommo_subdomain: subdomain, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n\n /** Busca o Client dono de um canal Wazzup (`GET /api/clients?channelId=...`). */\n async getByWazzupChannelId(channelId: string): Promise<Client | null> {\n const response = await this.client.get<ClientsListResponse>('/api/clients', {\n params: { channelId, includeConfigs: true }\n });\n return response.data.data[0] ?? null;\n }\n\n /**\n * Busca o Client pelo seu id direto (`GET /api/clients/{id}`) — inclui `aiConfig` e\n * `messagingConfig` (sem a API key criptografada). Usado pelo canal aiatendeWa, que resolve o\n * tenant a partir do `clientId` já incluído no payload do relay de webhook, sem precisar de\n * um identificador de canal indireto como Kommo subdomain ou Wazzup channelId.\n */\n async getById(clientId: string): Promise<Client | null> {\n try {\n const response = await this.client.get<Client>(`/api/clients/${clientId}`);\n return response.data;\n } catch (error) {\n if (error instanceof PortalApiError && error.status === 404) return null;\n throw error;\n }\n }\n}\n","import { z } from 'zod';\nimport { BaseResource } from '../../base';\nimport { PortalApiError } from '../../errors';\nimport { GetInternalContextParams, InternalContextResult } from './types';\n\nconst internalContextChunkSchema = z.object({\n chunkId: z.string().optional(),\n content: z.string(),\n similarity: z.number(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nconst internalContextResultSchema = z.array(internalContextChunkSchema);\n\nexport class KnowledgeResource extends BaseResource {\n /** Recupera trechos relevantes da base RAG do cliente pra uma pergunta em texto puro (`POST /api/knowledge/internal/context`). O Portal gera o embedding internamente usando a `apiKey` do AiConfig. */\n async getInternalContext(params: GetInternalContextParams): Promise<InternalContextResult> {\n const response = await this.client.post<unknown>('/api/knowledge/internal/context', {\n aiConfigId: params.aiConfigId,\n question: params.question,\n conversationHistory: params.conversationHistory\n });\n\n const parsed = internalContextResultSchema.safeParse(response.data);\n if (!parsed.success) {\n throw new PortalApiError('Resposta inválida de /api/knowledge/internal/context', {\n raw: parsed.error.flatten(),\n });\n }\n return parsed.data;\n }\n}\n","import { BaseResource } from '../../base';\nimport {\n ListConversationsFilters,\n MessagingConversation,\n MessagingConversationsListResponse,\n MessagingMessagesListResponse,\n PatchConversationPayload,\n SendMessagePayload,\n SendMessageResponse,\n UploadMediaPayload,\n UploadMediaResponse,\n} from './types';\n\n/**\n * Canal WhatsApp direto (aiatendeWa) — proxy pras rotas `/api/clients/{clientId}/messaging/...`\n * do Portal, que por sua vez falam com a plataforma de mensageria própria\n * (plataforma_whatsapp_coexistence). O atende360-assistant nunca fala direto com essa\n * plataforma — sempre por aqui, autenticado via a mesma `apiKey`/APP_API_KEY já usada pro\n * resto do SDK.\n */\nexport class MessagingResource extends BaseResource {\n async listConversations(\n clientId: string,\n filters?: ListConversationsFilters,\n ): Promise<MessagingConversationsListResponse> {\n const response = await this.client.get<MessagingConversationsListResponse>(\n `/api/clients/${clientId}/messaging/conversations`,\n { params: filters },\n );\n return response.data;\n }\n\n async getConversation(clientId: string, conversationId: string): Promise<MessagingConversation> {\n const response = await this.client.get<MessagingConversation>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}`,\n );\n return response.data;\n }\n\n async patchConversation(\n clientId: string,\n conversationId: string,\n payload: PatchConversationPayload,\n ): Promise<MessagingConversation> {\n const response = await this.client.patch<MessagingConversation>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}`,\n payload,\n );\n return response.data;\n }\n\n async getMessages(\n clientId: string,\n conversationId: string,\n params?: { page?: number; limit?: number },\n ): Promise<MessagingMessagesListResponse> {\n const response = await this.client.get<MessagingMessagesListResponse>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,\n { params },\n );\n return response.data;\n }\n\n async sendMessage(\n clientId: string,\n conversationId: string,\n payload: SendMessagePayload,\n ): Promise<SendMessageResponse> {\n const response = await this.client.post<SendMessageResponse>(\n `/api/clients/${clientId}/messaging/conversations/${conversationId}/messages`,\n payload,\n );\n return response.data;\n }\n\n /**\n * Upload de mídia (ex.: áudio gerado por TTS) — pré-requisito pra mandar `type: 'audio'` no\n * `sendMessage` (o `content.id` retornado aqui vira `content.id` do envio; `storagePath`\n * precisa ser ecoado em `content._media.storagePath` no send, senão a plataforma não cria o\n * registro de mídia local pra conexões Cloud API).\n */\n async uploadMedia(clientId: string, payload: UploadMediaPayload): Promise<UploadMediaResponse> {\n const form = new FormData();\n // Ordem importa: phoneNumberId/isVoiceNote precisam vir ANTES de file no multipart — o\n // parser do Portal (e o da plataforma por trás dele) lê em stream.\n form.append('phoneNumberId', payload.phoneNumberId);\n if (payload.isVoiceNote) form.append('isVoiceNote', 'true');\n form.append(\n 'file',\n new Blob([new Uint8Array(payload.file)], { type: payload.mimeType }),\n payload.filename,\n );\n\n const response = await this.client.post<UploadMediaResponse>(\n `/api/clients/${clientId}/messaging/media`,\n form,\n );\n return response.data;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "portal-aiatende-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Cliente TypeScript tipado para a API interna do Portal AI Atende.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"license": "ISC",
|
|
24
24
|
"type": "commonjs",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"axios": "^1.15.2"
|
|
26
|
+
"axios": "^1.15.2",
|
|
27
|
+
"zod": "^4.3.6"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@types/node": "^22.10.0",
|