@wondai/n8n-nodes-nucleo 0.2.5 → 0.2.6

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.
@@ -15,6 +15,7 @@ const n8n_workflow_1 = require("n8n-workflow");
15
15
  * signature = HMAC_SHA256(signingSecret, canônica) em hex.
16
16
  */
17
17
  const SIGNATURE_VERSION = "v1";
18
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
18
19
  const HEADERS = {
19
20
  key: "x-wondai-key",
20
21
  timestamp: "x-wondai-timestamp",
@@ -599,7 +600,9 @@ class Nucleo {
599
600
  const b = { resumo, resultado };
600
601
  if (convTelefone)
601
602
  b.telefone = convTelefone;
602
- if (convPedidoId)
603
+ // pedido_id é opcional e a IA costuma alucinar ("nenhum", texto, UUID stale).
604
+ // Só envia se for UUID bem-formado — lixo nunca chega ao Núcleo.
605
+ if (convPedidoId && UUID_RE.test(convPedidoId))
603
606
  b.pedido_id = convPedidoId;
604
607
  idempotencyKey =
605
608
  this.getNodeParameter("convIdempotencyKey", i, "").trim() || undefined;
@@ -613,38 +616,54 @@ class Nucleo {
613
616
  });
614
617
  }
615
618
  // ---- assina e envia (HMAC v1) ----
616
- const rawBody = bodyObj === undefined ? "" : JSON.stringify(bodyObj);
617
- const timestamp = Math.floor(Date.now() / 1000).toString();
618
- const nonce = (0, node_crypto_1.randomUUID)();
619
- const canonical = canonicalString(method, path, timestamp, nonce, rawBody);
620
- const signature = sign(signingSecret, canonical);
621
- const headers = {
622
- [HEADERS.key]: tokenId,
623
- [HEADERS.timestamp]: timestamp,
624
- [HEADERS.nonce]: nonce,
625
- [HEADERS.signature]: signature,
619
+ const sendSigned = async (rawBody) => {
620
+ const timestamp = Math.floor(Date.now() / 1000).toString();
621
+ const nonce = (0, node_crypto_1.randomUUID)();
622
+ const canonical = canonicalString(method, path, timestamp, nonce, rawBody);
623
+ const signature = sign(signingSecret, canonical);
624
+ const headers = {
625
+ [HEADERS.key]: tokenId,
626
+ [HEADERS.timestamp]: timestamp,
627
+ [HEADERS.nonce]: nonce,
628
+ [HEADERS.signature]: signature,
629
+ };
630
+ if (rawBody)
631
+ headers["content-type"] = "application/json";
632
+ if (idempotencyKey)
633
+ headers["idempotency-key"] = idempotencyKey;
634
+ const res = await this.helpers.httpRequest({
635
+ method,
636
+ url: baseUrl + path,
637
+ headers,
638
+ body: rawBody || undefined,
639
+ json: false,
640
+ returnFullResponse: true,
641
+ ignoreHttpStatusErrors: true,
642
+ });
643
+ const status = res.statusCode;
644
+ const rawRes = res.body;
645
+ let payload;
646
+ try {
647
+ payload = typeof rawRes === "string" ? JSON.parse(rawRes) : rawRes;
648
+ }
649
+ catch {
650
+ payload = { raw: rawRes };
651
+ }
652
+ return { status, payload };
626
653
  };
627
- if (rawBody)
628
- headers["content-type"] = "application/json";
629
- if (idempotencyKey)
630
- headers["idempotency-key"] = idempotencyKey;
631
- const res = await this.helpers.httpRequest({
632
- method,
633
- url: baseUrl + path,
634
- headers,
635
- body: rawBody || undefined,
636
- json: false,
637
- returnFullResponse: true,
638
- ignoreHttpStatusErrors: true,
639
- });
640
- const status = res.statusCode;
641
- const rawRes = res.body;
642
- let payload;
643
- try {
644
- payload = typeof rawRes === "string" ? JSON.parse(rawRes) : rawRes;
645
- }
646
- catch {
647
- payload = { raw: rawRes };
654
+ let rawBody = bodyObj === undefined ? "" : JSON.stringify(bodyObj);
655
+ let { status, payload } = await sendSigned(rawBody);
656
+ // Registrar conversa nunca deve falhar por causa de um pedido_id inválido
657
+ // (a IA pode mandar um UUID que não existe no tenant). Se o Núcleo recusar
658
+ // o pedido, reenvia sem ele — a conversa ainda é registrada.
659
+ if (status === 404 &&
660
+ resource === "conversa" &&
661
+ operation === "registrar" &&
662
+ bodyObj &&
663
+ bodyObj.pedido_id) {
664
+ delete bodyObj.pedido_id;
665
+ rawBody = JSON.stringify(bodyObj);
666
+ ({ status, payload } = await sendSigned(rawBody));
648
667
  }
649
668
  if (status >= 400) {
650
669
  const msg = (payload && payload.error) || `Núcleo respondeu HTTP ${status}.`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wondai/n8n-nodes-nucleo",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Node n8n para o Núcleo Wondai — atendimento de IA (cliente, catálogo fuzzy, pedidos) com assinatura HMAC v1. Tenant vem do token (a parede, ADR-013).",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",