@hostwebhook/node-sdk 0.6.0 → 0.7.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.
@@ -37,23 +37,70 @@ export type CredRefShape =
37
37
  {
38
38
  kind: 'scalar';
39
39
  path: string;
40
+ soloLectura?: boolean;
40
41
  }
41
42
  /** `extraCredentialIds: ObjectId[]` */
42
43
  | {
43
44
  kind: 'array';
44
45
  path: string;
46
+ soloLectura?: boolean;
45
47
  }
46
48
  /** `credentialIds: { plataforma: id | id[] }` */
47
49
  | {
48
50
  kind: 'map';
49
51
  path: string;
52
+ soloLectura?: boolean;
53
+ }
54
+ /**
55
+ * `tools: [{ credentialId, ... }]` — un array de OBJETOS, cada uno con su
56
+ * propia referencia. No es `array`: ahí los elementos SON el id.
57
+ *
58
+ * ⚠️ `campo` no es opcional a propósito. Una forma que no dice dónde mirar
59
+ * dentro del objeto no puede mirar en ningún sitio, y el fallo sería
60
+ * silencioso: `formasQueReferencian` devolvería vacío y el documento pasaría
61
+ * por «no usa esta credencial».
62
+ */
63
+ | {
64
+ kind: 'arrayDeObjetos';
65
+ path: string;
66
+ campo: string;
67
+ soloLectura?: boolean;
50
68
  };
51
69
  /**
52
- * Las cinco formas que existen hoy.
70
+ * Las nueve formas que existen hoy.
53
71
  *
54
72
  * Se barren en TODAS las colecciones de nodos, no sólo en las que declaran el
55
73
  * campo: una consulta por un campo que la colección no tiene simplemente no
56
74
  * devuelve nada, y así añadir el campo a otro nodo no obliga a tocar esta lista.
75
+ *
76
+ * ## Las cuatro que faltaban, y lo que costaban
77
+ *
78
+ * Eran cinco, y se quedaban cortas exactamente igual que la versión anterior a
79
+ * ésta — aquélla miraba dos campos escritos a mano en la consulta, y por eso
80
+ * nació este fichero. Las que faltaban:
81
+ *
82
+ * `tools[].credentialId` las credenciales de las TOOLS del AI Node:
83
+ * toda tool MCP y todo puente de audio
84
+ * `audioTranscribeCredentialId` el puente de transcripción del AI Node
85
+ * `embedding.credentialId` la clave que paga cada `embed` del vector store
86
+ * `backend.config.credentialId` la conexión del backend del vector store
87
+ * `results[].credentialId` a qué cuenta se publicó cada fila de un post
88
+ *
89
+ * Consecuencia medible y VIVA: `findConsumers` usa esta misma lista, así que
90
+ * borrar una credencial `mcp_server` usada sólo por una tool encontraba CERO
91
+ * consumidores — ni 409, ni desatachado, ni marcador. La credencial
92
+ * desaparecía y el nodo se quedaba con un id que ya no resuelve. Es el mismo
93
+ * fallo por el que se perdió la de Mastodon el 12-ago, con otro campo.
94
+ *
95
+ * ## ⚠️ `soloLectura`: referenciar no es lo mismo que desatachar
96
+ *
97
+ * `results[]` de un post es un REGISTRO HISTÓRICO: dice a qué cuenta se
98
+ * publicó cada fila. Tiene que contar para encontrar consumidores —que salte
99
+ * el 409— pero reescribirlo al desatachar sería falsear lo que pasó: una
100
+ * publicación que SÍ ocurrió quedaría sin decir con qué cuenta.
101
+ *
102
+ * Sin esta marca, ampliar la lista habría arreglado el borrado silencioso y
103
+ * roto el historial en el mismo movimiento.
57
104
  */
58
105
  export declare const CREDENTIAL_REF_SHAPES: readonly CredRefShape[];
59
106
  /** Lee un camino con puntos. Devuelve `undefined` si algo del medio falta. */
@@ -65,7 +112,7 @@ export declare function leerCamino(doc: unknown, path: string): unknown;
65
112
  * formas conviven en datos reales (`credentialIds` está declarado como
66
113
  * `Record<string, string[] | string>` justamente por eso).
67
114
  */
68
- export declare function valorReferencia(valor: unknown, id: string, kind: CredRefShape['kind']): boolean;
115
+ export declare function valorReferencia(valor: unknown, id: string, forma: CredRefShape): boolean;
69
116
  /** Las formas por las que ESTE documento referencia la credencial. */
70
117
  export declare function formasQueReferencian(doc: Record<string, unknown>, id: string): CredRefShape[];
71
118
  /**
@@ -78,7 +125,7 @@ export declare function formasQueReferencian(doc: Record<string, unknown>, id: s
78
125
  * con `[]` haría que el trigger siguiera anunciando que vigila Mastodon sin
79
126
  * ninguna cuenta con la que hacerlo.
80
127
  */
81
- export declare function valorTrasDesatacar(valor: unknown, id: string, kind: CredRefShape['kind']): unknown;
128
+ export declare function valorTrasDesatacar(valor: unknown, id: string, forma: CredRefShape): unknown;
82
129
  /**
83
130
  * Los dos campos que `credentials.service.remove` escribe en cada nodo que se
84
131
  * queda huérfano, para que la pantalla pueda decir QUÉ credencial era y
@@ -88,7 +135,7 @@ export declare const CAMPOS_MARCADOR_DETACH: readonly ["credentialDetachedAt", "
88
135
  /** El `$unset` que los quita. */
89
136
  export declare const UNSET_MARCADOR_DETACH: Record<string, ''>;
90
137
  /** ¿Este valor trae al menos una credencial puesta? */
91
- export declare function valorTieneCredencial(valor: unknown, kind: CredRefShape['kind']): boolean;
138
+ export declare function valorTieneCredencial(valor: unknown, forma: CredRefShape): boolean;
92
139
  /**
93
140
  * ¿El nodo tiene AHORA alguna credencial, por cualquiera de las cinco formas?
94
141
  *
@@ -43,11 +43,40 @@ exports.tieneAlgunaCredencial = tieneAlgunaCredencial;
43
43
  exports.marcadorEsFosil = marcadorEsFosil;
44
44
  exports.dtoTocaCredencial = dtoTocaCredencial;
45
45
  /**
46
- * Las cinco formas que existen hoy.
46
+ * Las nueve formas que existen hoy.
47
47
  *
48
48
  * Se barren en TODAS las colecciones de nodos, no sólo en las que declaran el
49
49
  * campo: una consulta por un campo que la colección no tiene simplemente no
50
50
  * devuelve nada, y así añadir el campo a otro nodo no obliga a tocar esta lista.
51
+ *
52
+ * ## Las cuatro que faltaban, y lo que costaban
53
+ *
54
+ * Eran cinco, y se quedaban cortas exactamente igual que la versión anterior a
55
+ * ésta — aquélla miraba dos campos escritos a mano en la consulta, y por eso
56
+ * nació este fichero. Las que faltaban:
57
+ *
58
+ * `tools[].credentialId` las credenciales de las TOOLS del AI Node:
59
+ * toda tool MCP y todo puente de audio
60
+ * `audioTranscribeCredentialId` el puente de transcripción del AI Node
61
+ * `embedding.credentialId` la clave que paga cada `embed` del vector store
62
+ * `backend.config.credentialId` la conexión del backend del vector store
63
+ * `results[].credentialId` a qué cuenta se publicó cada fila de un post
64
+ *
65
+ * Consecuencia medible y VIVA: `findConsumers` usa esta misma lista, así que
66
+ * borrar una credencial `mcp_server` usada sólo por una tool encontraba CERO
67
+ * consumidores — ni 409, ni desatachado, ni marcador. La credencial
68
+ * desaparecía y el nodo se quedaba con un id que ya no resuelve. Es el mismo
69
+ * fallo por el que se perdió la de Mastodon el 12-ago, con otro campo.
70
+ *
71
+ * ## ⚠️ `soloLectura`: referenciar no es lo mismo que desatachar
72
+ *
73
+ * `results[]` de un post es un REGISTRO HISTÓRICO: dice a qué cuenta se
74
+ * publicó cada fila. Tiene que contar para encontrar consumidores —que salte
75
+ * el 409— pero reescribirlo al desatachar sería falsear lo que pasó: una
76
+ * publicación que SÍ ocurrió quedaría sin decir con qué cuenta.
77
+ *
78
+ * Sin esta marca, ampliar la lista habría arreglado el borrado silencioso y
79
+ * roto el historial en el mismo movimiento.
51
80
  */
52
81
  exports.CREDENTIAL_REF_SHAPES = [
53
82
  { kind: 'scalar', path: 'credentialId' },
@@ -55,6 +84,16 @@ exports.CREDENTIAL_REF_SHAPES = [
55
84
  { kind: 'array', path: 'extraCredentialIds' },
56
85
  { kind: 'map', path: 'credentialIds' },
57
86
  { kind: 'map', path: 'serviceConfig.social_media.credentialIds' },
87
+ { kind: 'arrayDeObjetos', path: 'tools', campo: 'credentialId' },
88
+ { kind: 'scalar', path: 'audioTranscribeCredentialId' },
89
+ { kind: 'scalar', path: 'embedding.credentialId' },
90
+ { kind: 'scalar', path: 'backend.config.credentialId' },
91
+ {
92
+ kind: 'arrayDeObjetos',
93
+ path: 'results',
94
+ campo: 'credentialId',
95
+ soloLectura: true,
96
+ },
58
97
  ];
59
98
  const mismoId = (v, id) => v !== null && v !== undefined && String(v) === id;
60
99
  /** Lee un camino con puntos. Devuelve `undefined` si algo del medio falta. */
@@ -74,13 +113,19 @@ function leerCamino(doc, path) {
74
113
  * formas conviven en datos reales (`credentialIds` está declarado como
75
114
  * `Record<string, string[] | string>` justamente por eso).
76
115
  */
77
- function valorReferencia(valor, id, kind) {
116
+ function valorReferencia(valor, id, forma) {
78
117
  if (valor === null || valor === undefined)
79
118
  return false;
80
- if (kind === 'scalar')
119
+ if (forma.kind === 'scalar')
81
120
  return mismoId(valor, id);
82
- if (kind === 'array')
121
+ if (forma.kind === 'array')
83
122
  return Array.isArray(valor) && valor.some((v) => mismoId(v, id));
123
+ if (forma.kind === 'arrayDeObjetos') {
124
+ return (Array.isArray(valor) &&
125
+ valor.some((o) => o !== null &&
126
+ typeof o === 'object' &&
127
+ mismoId(o[forma.campo], id)));
128
+ }
84
129
  // map
85
130
  if (typeof valor !== 'object' || Array.isArray(valor))
86
131
  return false;
@@ -88,7 +133,7 @@ function valorReferencia(valor, id, kind) {
88
133
  }
89
134
  /** Las formas por las que ESTE documento referencia la credencial. */
90
135
  function formasQueReferencian(doc, id) {
91
- return exports.CREDENTIAL_REF_SHAPES.filter((forma) => valorReferencia(leerCamino(doc, forma.path), id, forma.kind));
136
+ return exports.CREDENTIAL_REF_SHAPES.filter((forma) => valorReferencia(leerCamino(doc, forma.path), id, forma));
92
137
  }
93
138
  /**
94
139
  * El valor que hay que dejar en el campo al quitar la credencial.
@@ -100,7 +145,22 @@ function formasQueReferencian(doc, id) {
100
145
  * con `[]` haría que el trigger siguiera anunciando que vigila Mastodon sin
101
146
  * ninguna cuenta con la que hacerlo.
102
147
  */
103
- function valorTrasDesatacar(valor, id, kind) {
148
+ function valorTrasDesatacar(valor, id, forma) {
149
+ const kind = forma.kind;
150
+ if (kind === 'arrayDeObjetos') {
151
+ /* ⚠️ Se le quita el id a la fila, pero la fila SE QUEDA. Borrar la tool
152
+ entera sería borrarle al usuario algo que él configuró porque nosotros
153
+ borramos otra cosa; sin credencial dará un error con nombre, que es lo
154
+ que toca. */
155
+ if (!Array.isArray(valor))
156
+ return null;
157
+ const resto = valor.map((o) => o !== null &&
158
+ typeof o === 'object' &&
159
+ mismoId(o[forma.campo], id)
160
+ ? { ...o, [forma.campo]: null }
161
+ : o);
162
+ return resto.length > 0 ? resto : null;
163
+ }
104
164
  if (kind === 'scalar')
105
165
  return null;
106
166
  if (kind === 'array') {
@@ -141,9 +201,19 @@ exports.UNSET_MARCADOR_DETACH = {
141
201
  credentialDetachedName: '',
142
202
  };
143
203
  /** ¿Este valor trae al menos una credencial puesta? */
144
- function valorTieneCredencial(valor, kind) {
204
+ function valorTieneCredencial(valor, forma) {
145
205
  if (valor === null || valor === undefined || valor === '')
146
206
  return false;
207
+ const kind = forma.kind;
208
+ if (kind === 'arrayDeObjetos') {
209
+ return (Array.isArray(valor) &&
210
+ valor.some((o) => {
211
+ if (o === null || typeof o !== 'object')
212
+ return false;
213
+ const v = o[forma.campo];
214
+ return v !== null && v !== undefined && v !== '';
215
+ }));
216
+ }
147
217
  if (kind === 'scalar')
148
218
  return true;
149
219
  if (kind === 'array')
@@ -166,7 +236,7 @@ function valorTieneCredencial(valor, kind) {
166
236
  function tieneAlgunaCredencial(doc) {
167
237
  if (!doc || typeof doc !== 'object')
168
238
  return false;
169
- return exports.CREDENTIAL_REF_SHAPES.some((forma) => valorTieneCredencial(leerCamino(doc, forma.path), forma.kind));
239
+ return exports.CREDENTIAL_REF_SHAPES.some((forma) => valorTieneCredencial(leerCamino(doc, forma.path), forma));
170
240
  }
171
241
  /**
172
242
  * ¿Hay que quitarle el marcador a este documento?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostwebhook/node-sdk",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "El SDK de un nodo de HostWebhook: ciclo de vida, ejecución con iteración, reintentos, filtros y validación de esquema — lo que comparten la api y el futuro servicio de nodos",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",