n8n-nodes-aib 0.6.0 → 0.7.1

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.
@@ -28,23 +28,32 @@ class AibDigitalApi {
28
28
  description: "Gerada em Integrações → Chaves de API. Use uma chave de agência para escolher a conta dentro do nó.",
29
29
  },
30
30
  ];
31
- // Sem `authenticate` de propósito. O n8n injeta um "Custom API Call" no
32
- // fim de toda lista chamada `resource` ou `operation` quando a credencial
33
- // define esse campo — a regra é literal, sem como desligar:
31
+ // `authenticate` volta, e com ele o "Custom API Call" que o n8n injeta em
32
+ // toda lista chamada `resource` ou `operation`:
34
33
  //
35
34
  // if (credType.authenticate !== undefined) return true;
36
35
  // — load-nodes-and-credentials.js, supportsProxyAuth()
37
36
  //
38
- // A opção caía no meio das operações de verdade, e quem a escolhesse via
39
- // o n8n esconder todos os outros campos do nó. O nó nunca dependeu disso:
40
- // ele monta o `Authorization` na mão em `api()`. O que se perde é a
41
- // credencial aparecer como tipo predefinido no nó HTTP Request.
37
+ // Tirá-lo limpava o menu do nó, mas quebrava quem usa esta credencial
38
+ // como tipo predefinido no HTTP Request — e o agente usa em quatro nós
39
+ // (Buscar funil, e os três de download de mídia), além do instalador.
40
+ // Um menu com uma opção a mais incomoda; um agente sem autenticação para.
41
+ //
42
+ // Para limpar o menu sem esse custo, o caminho é outro: renomear as
43
+ // propriedades `resource`/`operation` do nó, já que a injeção casa por
44
+ // esses dois nomes exatos. Isso muda parâmetro salvo e pede uma v3.
45
+ authenticate = {
46
+ type: "generic",
47
+ properties: {
48
+ headers: {
49
+ Authorization: "=Bearer {{$credentials.apiKey}}",
50
+ },
51
+ },
52
+ };
42
53
  test = {
43
54
  request: {
44
55
  baseURL: "={{$credentials.baseUrl}}",
45
56
  url: "/api/v1/ping",
46
- // Com `authenticate` fora, o cabeçalho do teste vem daqui.
47
- headers: { Authorization: "=Bearer {{$credentials.apiKey}}" },
48
57
  },
49
58
  };
50
59
  }
@@ -79,38 +79,12 @@ class AibDigital {
79
79
  outputs: ["main"],
80
80
  credentials: [{ name: "aibDigitalApi", required: true }],
81
81
  properties: [
82
- {
83
- displayName: "Conta",
84
- name: "conta",
85
- type: "options",
86
- typeOptions: { loadOptionsMethod: "getContas" },
87
- default: "",
88
- displayOptions: { show: { "@version": [1] } },
89
- description: "O cliente. Com chave de agência, escolha aqui; com chave de conta, deixe vazio.",
90
- },
91
- {
92
- displayName: "Conta",
93
- name: "conta",
94
- type: "resourceLocator",
95
- default: { mode: "list", value: "" },
96
- displayOptions: { show: { "@version": [2] } },
97
- description: "O cliente. Com chave de agência, escolha aqui; com chave de conta, deixe vazio.",
98
- modes: [
99
- {
100
- displayName: "Da lista",
101
- name: "list",
102
- type: "list",
103
- typeOptions: { searchListMethod: "buscarContas", searchable: true },
104
- },
105
- {
106
- displayName: "Por ID",
107
- name: "id",
108
- type: "string",
109
- hint: "O UUID da conta. Vazio = a conta da própria chave.",
110
- },
111
- ],
112
- },
113
- // ── Recurso → Operação, como no nó do Chatwoot ──────────────
82
+ // ── Recurso → Operação → Conta ──────────────────────────────
83
+ //
84
+ // Nesta ordem, e não com a Conta na frente: primeiro se diz O QUE
85
+ // fazer, depois ONDE. É como o nó do Chatwoot se apresenta, e é a
86
+ // ordem em que a pessoa pensa. A Conta na frente obrigava a
87
+ // escolher o cliente antes de saber o que se ia fazer nele.
114
88
  {
115
89
  displayName: "Recurso",
116
90
  name: "recurso",
@@ -200,6 +174,37 @@ class AibDigital {
200
174
  { name: "Listar etiquetas", value: "listarEtiquetas", action: "Listar as etiquetas da conta" },
201
175
  ],
202
176
  },
177
+ {
178
+ displayName: "Conta",
179
+ name: "conta",
180
+ type: "options",
181
+ typeOptions: { loadOptionsMethod: "getContas" },
182
+ default: "",
183
+ displayOptions: { show: { "@version": [1] } },
184
+ description: "O cliente. Com chave de agência, escolha aqui; com chave de conta, deixe vazio.",
185
+ },
186
+ {
187
+ displayName: "Conta",
188
+ name: "conta",
189
+ type: "resourceLocator",
190
+ default: { mode: "list", value: "" },
191
+ displayOptions: { show: { "@version": [2] } },
192
+ description: "O cliente. Com chave de agência é obrigatória — a API recusa o pedido sem ela. Com chave de conta, deixe vazio: é a conta da própria chave.",
193
+ modes: [
194
+ {
195
+ displayName: "Da lista",
196
+ name: "list",
197
+ type: "list",
198
+ typeOptions: { searchListMethod: "buscarContas", searchable: true },
199
+ },
200
+ {
201
+ displayName: "Por ID",
202
+ name: "id",
203
+ type: "string",
204
+ hint: "O UUID da conta. Vazio = a conta da própria chave.",
205
+ },
206
+ ],
207
+ },
203
208
  // ── parâmetros por operação ─────────────────────────────
204
209
  {
205
210
  displayName: "Conversa (ID)",
@@ -321,12 +326,14 @@ class AibDigital {
321
326
  description: "Onde o funil/dado vai nascer. Conta com 2+ ambientes exige escolher aqui.",
322
327
  },
323
328
  {
329
+ // Onde o dado NASCE, então continua em primeiro plano: criar um
330
+ // funil ou uma etiqueta no ambiente errado é trabalho refeito.
324
331
  displayName: "Ambiente",
325
332
  name: "ambienteId",
326
333
  type: "resourceLocator",
327
334
  default: { mode: "list", value: "" },
328
335
  displayOptions: {
329
- show: { "@version": [2], operation: ["selecionarConta", "criarFunil", "criarEtiqueta"] },
336
+ show: { "@version": [2], operation: ["criarFunil", "criarEtiqueta"] },
330
337
  },
331
338
  description: "Onde o funil/dado vai nascer. Conta com 2+ ambientes exige escolher aqui.",
332
339
  modes: [
@@ -340,23 +347,34 @@ class AibDigital {
340
347
  ],
341
348
  },
342
349
  {
343
- // A outra metade do que o atendimento precisa saber antes de agir:
344
- // escolhida a conta, escolher o WhatsApp em que se opera. Fica na
345
- // âncora do fluxo, para os nós seguintes lerem `.caixa_id`.
346
- displayName: "Caixa de entrada",
347
- name: "caixaId",
348
- type: "resourceLocator",
349
- default: { mode: "list", value: "" },
350
+ // Na âncora, Ambiente e Caixa são REFINAMENTO: sem eles o nó já
351
+ // responde, e a conta com um ambiente só — que é a maioria —
352
+ // nunca precisa tocar aqui. Soltos na tela, pareciam pendências e
353
+ // faziam a pergunta "preciso preencher isso?" a cada vez. Dentro
354
+ // de Opções, aparecem quando são procurados.
355
+ displayName: "Opções",
356
+ name: "opcoes",
357
+ type: "collection",
358
+ placeholder: "Escolher ambiente ou caixa",
359
+ default: {},
350
360
  displayOptions: { show: { "@version": [2], operation: ["selecionarConta"] } },
351
- description: "O WhatsApp da conta. Vazio = o fluxo não se prende a uma caixa.",
352
- modes: [
361
+ options: [
353
362
  {
354
- displayName: "Da lista",
355
- name: "list",
356
- type: "list",
357
- typeOptions: { searchListMethod: "buscarCaixas", searchable: true },
363
+ displayName: "Ambiente",
364
+ name: "ambienteId",
365
+ type: "options",
366
+ typeOptions: { loadOptionsMethod: "getAmbientes", loadOptionsDependsOn: ["conta.value"] },
367
+ default: "",
368
+ description: "Vazio = o único ambiente da conta",
369
+ },
370
+ {
371
+ displayName: "Caixa de Entrada",
372
+ name: "caixaId",
373
+ type: "options",
374
+ typeOptions: { loadOptionsMethod: "getCaixas", loadOptionsDependsOn: ["conta.value"] },
375
+ default: "",
376
+ description: "O WhatsApp da conta. Vazio = o fluxo não se prende a uma caixa.",
358
377
  },
359
- { displayName: "Por ID", name: "id", type: "string" },
360
378
  ],
361
379
  },
362
380
  {
@@ -551,6 +569,20 @@ class AibDigital {
551
569
  return [{ name: "— Único ambiente da conta —", value: "" }];
552
570
  }
553
571
  },
572
+ async getCaixas() {
573
+ const conta = contaDeLista(this);
574
+ try {
575
+ const res = await api(this, "GET", "/api/v1/caixas", undefined, conta ? { conta } : undefined);
576
+ const caixas = (res?.caixas ?? []);
577
+ return caixas.map((c) => ({
578
+ name: c.telefone ? `${c.nome} · ${c.telefone}` : c.nome,
579
+ value: c.id,
580
+ }));
581
+ }
582
+ catch {
583
+ return [];
584
+ }
585
+ },
554
586
  async getFunis() {
555
587
  const conta = contaDeLista(this);
556
588
  const res = await api(this, "GET", "/api/v1/funis", undefined, conta ? { conta } : undefined);
@@ -680,8 +712,14 @@ class AibDigital {
680
712
  // .ambiente_id e .caixa_id). É onde o funil vai nascer e por onde o
681
713
  // atendimento fala.
682
714
  const contaSel = idDe(this.getNodeParameter("conta", i, ""));
683
- const ambienteSel = idDe(this.getNodeParameter("ambienteId", i, ""));
684
- const caixaSel = idDe(this.getNodeParameter("caixaId", i, ""));
715
+ // Ambiente e caixa mudaram de lugar na 0.7.0 (foram para `opcoes`).
716
+ // O nó gravado antes disso guardou os dois no primeiro nível, e
717
+ // continua valendo: lê-se a coleção e, se ela não disser nada, o
718
+ // campo antigo. Sem isso, um fluxo já montado perderia o ambiente
719
+ // em silêncio — e criaria o funil no lugar errado.
720
+ const opcoes = this.getNodeParameter("opcoes", i, {});
721
+ const ambienteSel = idDe(opcoes.ambienteId) || idDe(this.getNodeParameter("ambienteId", i, ""));
722
+ const caixaSel = idDe(opcoes.caixaId) || idDe(this.getNodeParameter("caixaId", i, ""));
685
723
  let base;
686
724
  if (contaSel) {
687
725
  const r = await api(this, "GET", "/api/v1/contas");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n8n-nodes-aib",
3
- "version": "0.6.0",
3
+ "version": "0.7.1",
4
4
  "description": "Nós do Sistema AIB Digital para n8n: gatilho de mensagens do WhatsApp (via AIB Inbox) e ações — enviar mensagem, mover card no funil, pausar IA — escolhendo conta e caixa por dropdown.",
5
5
  "license": "MIT",
6
6
  "author": "AIB Digital",