@hostwebhook/node-types 1.70.0 → 1.71.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/bucket-operations.d.ts +88 -0
- package/dist/bucket-operations.js +140 -0
- package/dist/connections.js +1 -0
- package/dist/dispatch.js +1 -0
- package/dist/esm/bucket-operations.d.ts +88 -0
- package/dist/esm/bucket-operations.js +136 -0
- package/dist/esm/connections.js +1 -0
- package/dist/esm/dispatch.js +1 -0
- package/dist/esm/index.d.ts +2 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/registry.d.ts +4 -4
- package/dist/esm/registry.js +540 -210
- package/dist/esm/types.d.ts +1 -1
- package/dist/esm/ui.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8 -2
- package/dist/registry.d.ts +4 -4
- package/dist/registry.js +540 -210
- package/dist/types.d.ts +1 -1
- package/dist/ui.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El nodo de bucket: guardar, firmar y borrar objetos en un almacenamiento
|
|
3
|
+
* compatible con S3.
|
|
4
|
+
*
|
|
5
|
+
* ## Por qué se llama `bucket` y no `r2`
|
|
6
|
+
*
|
|
7
|
+
* Porque el proveedor es un ENDPOINT, no un tipo de nodo. La credencial
|
|
8
|
+
* `aws_s3` ya guarda `endpoint`, `bucket` y `region`, así que el mismo nodo
|
|
9
|
+
* habla con Cloudflare R2, con AWS S3, con MinIO o con Backblaze sin cambiar
|
|
10
|
+
* una línea. Llamarlo `r2Action` habría obligado, el día que llegue AWS, a
|
|
11
|
+
* tener dos nodos casi idénticos o a renombrar un tipo — y el prefijo del tipo
|
|
12
|
+
* vive DENTRO de los ids de nodo ya guardados en la base de cada cliente, así
|
|
13
|
+
* que renombrar es migrar datos.
|
|
14
|
+
*
|
|
15
|
+
* ## La operación que motiva el nodo
|
|
16
|
+
*
|
|
17
|
+
* `presignDownload`. La plataforma sabe firmar peticiones S3 desde el nodo
|
|
18
|
+
* HTTP —`common/s3-signer.ts`— pero **por cabecera**, y una cabecera no cabe en
|
|
19
|
+
* un enlace que se manda por correo. Sin esto no había forma de entregarle a un
|
|
20
|
+
* comprador una descarga temporal desde un flujo.
|
|
21
|
+
*
|
|
22
|
+
* ## Por qué sólo cuatro operaciones
|
|
23
|
+
*
|
|
24
|
+
* Listar y subida multiparte son las dos que piden el SDK de AWS de verdad
|
|
25
|
+
* —paginación y reanudación— y el ejecutor hoy no tiene ni un `@aws-sdk/*`.
|
|
26
|
+
* Entrar sin esa dependencia y traerla cuando aparezca la operación que la
|
|
27
|
+
* justifique es más barato que al revés. Y un nodo con veinte operaciones es un
|
|
28
|
+
* nodo que nadie entiende.
|
|
29
|
+
*/
|
|
30
|
+
export declare const BUCKET_OPERATIONS: readonly ["presignDownload", "putObject", "headObject", "deleteObject"];
|
|
31
|
+
export type BucketOperation = (typeof BUCKET_OPERATIONS)[number];
|
|
32
|
+
export declare function isBucketOperation(value: unknown): value is BucketOperation;
|
|
33
|
+
/**
|
|
34
|
+
* Ninguna es iterable.
|
|
35
|
+
*
|
|
36
|
+
* Una operación iterable es la que devuelve una COLECCIÓN sobre la que el nodo
|
|
37
|
+
* de abajo repite. Las cuatro de aquí actúan sobre UN objeto, así que el que
|
|
38
|
+
* viene detrás recibe un resultado, no una lista. El día que entre `listObjects`
|
|
39
|
+
* ésa sí entra en esta lista.
|
|
40
|
+
*/
|
|
41
|
+
export declare const BUCKET_ITERABLE_OPERATIONS: readonly BucketOperation[];
|
|
42
|
+
export type BucketParamType =
|
|
43
|
+
/** La clave del objeto dentro del bucket. Con autocompletado de
|
|
44
|
+
* `{{payload.*}}`, porque el 90% de los casos la construye del evento:
|
|
45
|
+
* `cuadernillos/{{payload.orderId}}.pdf`. */
|
|
46
|
+
"template"
|
|
47
|
+
/** Área de texto larga, también con autocompletado. */
|
|
48
|
+
| "textarea"
|
|
49
|
+
/** `<select>` normal; las etiquetas no son los valores, `options` obliga. */
|
|
50
|
+
| "select" | "number"
|
|
51
|
+
/**
|
|
52
|
+
* `<select>` de `''` / `'true'` / `'false'` que se guarda como BOOLEANO, o
|
|
53
|
+
* no se guarda si es `''`. "— sin tocar —" tiene que significar que la clave
|
|
54
|
+
* no viaja, no que viaja en `false`.
|
|
55
|
+
*/
|
|
56
|
+
| "booleanSelect";
|
|
57
|
+
export interface BucketParamSpec {
|
|
58
|
+
/** La clave de `operationConfig`. Es lo que lee la api, no un nombre de UI. */
|
|
59
|
+
name: string;
|
|
60
|
+
label: string;
|
|
61
|
+
type: BucketParamType;
|
|
62
|
+
required?: boolean;
|
|
63
|
+
/** Ayuda bajo el campo. Texto plano: el paquete no lleva React. */
|
|
64
|
+
description?: string;
|
|
65
|
+
placeholder?: string;
|
|
66
|
+
/** Prerrellenado cuando la config guardada no trae valor para esta clave. */
|
|
67
|
+
default?: string | number;
|
|
68
|
+
/** Obligatorio en `select` y `booleanSelect`. */
|
|
69
|
+
options?: ReadonlyArray<{
|
|
70
|
+
value: string;
|
|
71
|
+
label: string;
|
|
72
|
+
}>;
|
|
73
|
+
min?: number;
|
|
74
|
+
max?: number;
|
|
75
|
+
/** Se pinta en la pestaña "Advanced" en vez de en "Config". */
|
|
76
|
+
advanced?: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface BucketOperationSpec {
|
|
79
|
+
/** Etiqueta de la fila en el desplegable de operación. */
|
|
80
|
+
label: string;
|
|
81
|
+
/** Sub-línea bajo la etiqueta. */
|
|
82
|
+
description: string;
|
|
83
|
+
/** La llamada S3 a la que mapea, para poder cotejarla con los docs. */
|
|
84
|
+
apiRoute: string;
|
|
85
|
+
/** Esquema de parámetros. El orden ES el orden en pantalla. */
|
|
86
|
+
params: BucketParamSpec[];
|
|
87
|
+
}
|
|
88
|
+
export declare const BUCKET_OPERATION_SPECS: Record<BucketOperation, BucketOperationSpec>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* El nodo de bucket: guardar, firmar y borrar objetos en un almacenamiento
|
|
4
|
+
* compatible con S3.
|
|
5
|
+
*
|
|
6
|
+
* ## Por qué se llama `bucket` y no `r2`
|
|
7
|
+
*
|
|
8
|
+
* Porque el proveedor es un ENDPOINT, no un tipo de nodo. La credencial
|
|
9
|
+
* `aws_s3` ya guarda `endpoint`, `bucket` y `region`, así que el mismo nodo
|
|
10
|
+
* habla con Cloudflare R2, con AWS S3, con MinIO o con Backblaze sin cambiar
|
|
11
|
+
* una línea. Llamarlo `r2Action` habría obligado, el día que llegue AWS, a
|
|
12
|
+
* tener dos nodos casi idénticos o a renombrar un tipo — y el prefijo del tipo
|
|
13
|
+
* vive DENTRO de los ids de nodo ya guardados en la base de cada cliente, así
|
|
14
|
+
* que renombrar es migrar datos.
|
|
15
|
+
*
|
|
16
|
+
* ## La operación que motiva el nodo
|
|
17
|
+
*
|
|
18
|
+
* `presignDownload`. La plataforma sabe firmar peticiones S3 desde el nodo
|
|
19
|
+
* HTTP —`common/s3-signer.ts`— pero **por cabecera**, y una cabecera no cabe en
|
|
20
|
+
* un enlace que se manda por correo. Sin esto no había forma de entregarle a un
|
|
21
|
+
* comprador una descarga temporal desde un flujo.
|
|
22
|
+
*
|
|
23
|
+
* ## Por qué sólo cuatro operaciones
|
|
24
|
+
*
|
|
25
|
+
* Listar y subida multiparte son las dos que piden el SDK de AWS de verdad
|
|
26
|
+
* —paginación y reanudación— y el ejecutor hoy no tiene ni un `@aws-sdk/*`.
|
|
27
|
+
* Entrar sin esa dependencia y traerla cuando aparezca la operación que la
|
|
28
|
+
* justifique es más barato que al revés. Y un nodo con veinte operaciones es un
|
|
29
|
+
* nodo que nadie entiende.
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.BUCKET_OPERATION_SPECS = exports.BUCKET_ITERABLE_OPERATIONS = exports.BUCKET_OPERATIONS = void 0;
|
|
33
|
+
exports.isBucketOperation = isBucketOperation;
|
|
34
|
+
exports.BUCKET_OPERATIONS = [
|
|
35
|
+
"presignDownload",
|
|
36
|
+
"putObject",
|
|
37
|
+
"headObject",
|
|
38
|
+
"deleteObject",
|
|
39
|
+
];
|
|
40
|
+
function isBucketOperation(value) {
|
|
41
|
+
return (typeof value === "string" &&
|
|
42
|
+
exports.BUCKET_OPERATIONS.includes(value));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Ninguna es iterable.
|
|
46
|
+
*
|
|
47
|
+
* Una operación iterable es la que devuelve una COLECCIÓN sobre la que el nodo
|
|
48
|
+
* de abajo repite. Las cuatro de aquí actúan sobre UN objeto, así que el que
|
|
49
|
+
* viene detrás recibe un resultado, no una lista. El día que entre `listObjects`
|
|
50
|
+
* ésa sí entra en esta lista.
|
|
51
|
+
*/
|
|
52
|
+
exports.BUCKET_ITERABLE_OPERATIONS = [];
|
|
53
|
+
/* Ayudantes — repetir el mismo objeto cuatro veces es cómo se desincronizan las
|
|
54
|
+
descripciones. */
|
|
55
|
+
const objectKey = (placeholder) => ({
|
|
56
|
+
name: "key",
|
|
57
|
+
label: "Object key",
|
|
58
|
+
type: "template",
|
|
59
|
+
required: true,
|
|
60
|
+
placeholder,
|
|
61
|
+
description: "La ruta dentro del bucket. Sin barra inicial. Admite {{payload.x}}.",
|
|
62
|
+
});
|
|
63
|
+
exports.BUCKET_OPERATION_SPECS = {
|
|
64
|
+
presignDownload: {
|
|
65
|
+
label: "Sign download link",
|
|
66
|
+
description: "Devuelve una URL temporal para descargar un objeto privado. No mueve el fichero.",
|
|
67
|
+
apiRoute: "GET (presigned)",
|
|
68
|
+
params: [
|
|
69
|
+
objectKey("cuadernillos/{{payload.orderId}}.pdf"),
|
|
70
|
+
{
|
|
71
|
+
name: "expiresIn",
|
|
72
|
+
label: "Link valid for (seconds)",
|
|
73
|
+
type: "number",
|
|
74
|
+
required: true,
|
|
75
|
+
default: 3600,
|
|
76
|
+
min: 60,
|
|
77
|
+
/* El tope de SigV4 es de siete días y no se puede pasar: firmar por
|
|
78
|
+
más tiempo produce una URL que el proveedor rechaza, y el error
|
|
79
|
+
llega tarde y sin explicación. */
|
|
80
|
+
max: 604800,
|
|
81
|
+
description: "Desde 60 s hasta 7 días, que es el máximo que admite la firma. Pasado ese plazo el enlace deja de servir.",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: "downloadAs",
|
|
85
|
+
label: "Download as (filename)",
|
|
86
|
+
type: "template",
|
|
87
|
+
placeholder: "Cuadernillo 1.pdf",
|
|
88
|
+
description: "Si se rellena, el navegador DESCARGA el fichero con ese nombre en vez de abrirlo. Déjalo vacío para que lo abra.",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
putObject: {
|
|
93
|
+
label: "Upload object",
|
|
94
|
+
description: "Guarda un objeto en el bucket. Sobreescribe si la clave ya existe.",
|
|
95
|
+
apiRoute: "PUT /{bucket}/{key}",
|
|
96
|
+
params: [
|
|
97
|
+
objectKey("recibos/{{payload.orderId}}.json"),
|
|
98
|
+
{
|
|
99
|
+
name: "body",
|
|
100
|
+
label: "Contents",
|
|
101
|
+
type: "textarea",
|
|
102
|
+
required: true,
|
|
103
|
+
placeholder: "{{payload}}",
|
|
104
|
+
description: "Lo que se guarda. Admite {{payload.x}}; un objeto se guarda como JSON.",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "contentType",
|
|
108
|
+
label: "Content type",
|
|
109
|
+
type: "template",
|
|
110
|
+
default: "application/json",
|
|
111
|
+
placeholder: "application/pdf",
|
|
112
|
+
description: "Lo que el navegador usará para decidir qué hacer con el fichero.",
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
headObject: {
|
|
117
|
+
label: "Check object exists",
|
|
118
|
+
description: "Comprueba si un objeto existe, y su tamaño, sin descargarlo.",
|
|
119
|
+
apiRoute: "HEAD /{bucket}/{key}",
|
|
120
|
+
params: [
|
|
121
|
+
objectKey("cuadernillos/{{payload.orderId}}.pdf"),
|
|
122
|
+
{
|
|
123
|
+
name: "failIfMissing",
|
|
124
|
+
label: "Fail when the object is missing",
|
|
125
|
+
type: "booleanSelect",
|
|
126
|
+
options: [
|
|
127
|
+
{ value: "true", label: "Sí — cortar el flujo" },
|
|
128
|
+
{ value: "false", label: "No — seguir con exists: false" },
|
|
129
|
+
],
|
|
130
|
+
description: 'Con "No", el paso sale bien y el de abajo decide. Con "Sí", un objeto que falta corta el flujo.',
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
deleteObject: {
|
|
135
|
+
label: "Delete object",
|
|
136
|
+
description: "Borra un objeto del bucket. No se puede deshacer.",
|
|
137
|
+
apiRoute: "DELETE /{bucket}/{key}",
|
|
138
|
+
params: [objectKey("temporales/{{payload.id}}.tmp")],
|
|
139
|
+
},
|
|
140
|
+
};
|
package/dist/connections.js
CHANGED
|
@@ -81,6 +81,7 @@ exports.NODE_CONNECTIONS = {
|
|
|
81
81
|
shopifyAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
82
82
|
githubAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
83
83
|
jiraAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
84
|
+
bucketAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
84
85
|
googleContactsAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
85
86
|
googleAnalyticsAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
86
87
|
notionAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
package/dist/dispatch.js
CHANGED
|
@@ -56,6 +56,7 @@ exports.NODE_DISPATCH = {
|
|
|
56
56
|
shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
57
57
|
githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
58
58
|
jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
59
|
+
bucketAction: { service: 'bucketActionsService', collection: 'bucketactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
59
60
|
slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
60
61
|
googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
61
62
|
googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El nodo de bucket: guardar, firmar y borrar objetos en un almacenamiento
|
|
3
|
+
* compatible con S3.
|
|
4
|
+
*
|
|
5
|
+
* ## Por qué se llama `bucket` y no `r2`
|
|
6
|
+
*
|
|
7
|
+
* Porque el proveedor es un ENDPOINT, no un tipo de nodo. La credencial
|
|
8
|
+
* `aws_s3` ya guarda `endpoint`, `bucket` y `region`, así que el mismo nodo
|
|
9
|
+
* habla con Cloudflare R2, con AWS S3, con MinIO o con Backblaze sin cambiar
|
|
10
|
+
* una línea. Llamarlo `r2Action` habría obligado, el día que llegue AWS, a
|
|
11
|
+
* tener dos nodos casi idénticos o a renombrar un tipo — y el prefijo del tipo
|
|
12
|
+
* vive DENTRO de los ids de nodo ya guardados en la base de cada cliente, así
|
|
13
|
+
* que renombrar es migrar datos.
|
|
14
|
+
*
|
|
15
|
+
* ## La operación que motiva el nodo
|
|
16
|
+
*
|
|
17
|
+
* `presignDownload`. La plataforma sabe firmar peticiones S3 desde el nodo
|
|
18
|
+
* HTTP —`common/s3-signer.ts`— pero **por cabecera**, y una cabecera no cabe en
|
|
19
|
+
* un enlace que se manda por correo. Sin esto no había forma de entregarle a un
|
|
20
|
+
* comprador una descarga temporal desde un flujo.
|
|
21
|
+
*
|
|
22
|
+
* ## Por qué sólo cuatro operaciones
|
|
23
|
+
*
|
|
24
|
+
* Listar y subida multiparte son las dos que piden el SDK de AWS de verdad
|
|
25
|
+
* —paginación y reanudación— y el ejecutor hoy no tiene ni un `@aws-sdk/*`.
|
|
26
|
+
* Entrar sin esa dependencia y traerla cuando aparezca la operación que la
|
|
27
|
+
* justifique es más barato que al revés. Y un nodo con veinte operaciones es un
|
|
28
|
+
* nodo que nadie entiende.
|
|
29
|
+
*/
|
|
30
|
+
export declare const BUCKET_OPERATIONS: readonly ["presignDownload", "putObject", "headObject", "deleteObject"];
|
|
31
|
+
export type BucketOperation = (typeof BUCKET_OPERATIONS)[number];
|
|
32
|
+
export declare function isBucketOperation(value: unknown): value is BucketOperation;
|
|
33
|
+
/**
|
|
34
|
+
* Ninguna es iterable.
|
|
35
|
+
*
|
|
36
|
+
* Una operación iterable es la que devuelve una COLECCIÓN sobre la que el nodo
|
|
37
|
+
* de abajo repite. Las cuatro de aquí actúan sobre UN objeto, así que el que
|
|
38
|
+
* viene detrás recibe un resultado, no una lista. El día que entre `listObjects`
|
|
39
|
+
* ésa sí entra en esta lista.
|
|
40
|
+
*/
|
|
41
|
+
export declare const BUCKET_ITERABLE_OPERATIONS: readonly BucketOperation[];
|
|
42
|
+
export type BucketParamType =
|
|
43
|
+
/** La clave del objeto dentro del bucket. Con autocompletado de
|
|
44
|
+
* `{{payload.*}}`, porque el 90% de los casos la construye del evento:
|
|
45
|
+
* `cuadernillos/{{payload.orderId}}.pdf`. */
|
|
46
|
+
"template"
|
|
47
|
+
/** Área de texto larga, también con autocompletado. */
|
|
48
|
+
| "textarea"
|
|
49
|
+
/** `<select>` normal; las etiquetas no son los valores, `options` obliga. */
|
|
50
|
+
| "select" | "number"
|
|
51
|
+
/**
|
|
52
|
+
* `<select>` de `''` / `'true'` / `'false'` que se guarda como BOOLEANO, o
|
|
53
|
+
* no se guarda si es `''`. "— sin tocar —" tiene que significar que la clave
|
|
54
|
+
* no viaja, no que viaja en `false`.
|
|
55
|
+
*/
|
|
56
|
+
| "booleanSelect";
|
|
57
|
+
export interface BucketParamSpec {
|
|
58
|
+
/** La clave de `operationConfig`. Es lo que lee la api, no un nombre de UI. */
|
|
59
|
+
name: string;
|
|
60
|
+
label: string;
|
|
61
|
+
type: BucketParamType;
|
|
62
|
+
required?: boolean;
|
|
63
|
+
/** Ayuda bajo el campo. Texto plano: el paquete no lleva React. */
|
|
64
|
+
description?: string;
|
|
65
|
+
placeholder?: string;
|
|
66
|
+
/** Prerrellenado cuando la config guardada no trae valor para esta clave. */
|
|
67
|
+
default?: string | number;
|
|
68
|
+
/** Obligatorio en `select` y `booleanSelect`. */
|
|
69
|
+
options?: ReadonlyArray<{
|
|
70
|
+
value: string;
|
|
71
|
+
label: string;
|
|
72
|
+
}>;
|
|
73
|
+
min?: number;
|
|
74
|
+
max?: number;
|
|
75
|
+
/** Se pinta en la pestaña "Advanced" en vez de en "Config". */
|
|
76
|
+
advanced?: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface BucketOperationSpec {
|
|
79
|
+
/** Etiqueta de la fila en el desplegable de operación. */
|
|
80
|
+
label: string;
|
|
81
|
+
/** Sub-línea bajo la etiqueta. */
|
|
82
|
+
description: string;
|
|
83
|
+
/** La llamada S3 a la que mapea, para poder cotejarla con los docs. */
|
|
84
|
+
apiRoute: string;
|
|
85
|
+
/** Esquema de parámetros. El orden ES el orden en pantalla. */
|
|
86
|
+
params: BucketParamSpec[];
|
|
87
|
+
}
|
|
88
|
+
export declare const BUCKET_OPERATION_SPECS: Record<BucketOperation, BucketOperationSpec>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El nodo de bucket: guardar, firmar y borrar objetos en un almacenamiento
|
|
3
|
+
* compatible con S3.
|
|
4
|
+
*
|
|
5
|
+
* ## Por qué se llama `bucket` y no `r2`
|
|
6
|
+
*
|
|
7
|
+
* Porque el proveedor es un ENDPOINT, no un tipo de nodo. La credencial
|
|
8
|
+
* `aws_s3` ya guarda `endpoint`, `bucket` y `region`, así que el mismo nodo
|
|
9
|
+
* habla con Cloudflare R2, con AWS S3, con MinIO o con Backblaze sin cambiar
|
|
10
|
+
* una línea. Llamarlo `r2Action` habría obligado, el día que llegue AWS, a
|
|
11
|
+
* tener dos nodos casi idénticos o a renombrar un tipo — y el prefijo del tipo
|
|
12
|
+
* vive DENTRO de los ids de nodo ya guardados en la base de cada cliente, así
|
|
13
|
+
* que renombrar es migrar datos.
|
|
14
|
+
*
|
|
15
|
+
* ## La operación que motiva el nodo
|
|
16
|
+
*
|
|
17
|
+
* `presignDownload`. La plataforma sabe firmar peticiones S3 desde el nodo
|
|
18
|
+
* HTTP —`common/s3-signer.ts`— pero **por cabecera**, y una cabecera no cabe en
|
|
19
|
+
* un enlace que se manda por correo. Sin esto no había forma de entregarle a un
|
|
20
|
+
* comprador una descarga temporal desde un flujo.
|
|
21
|
+
*
|
|
22
|
+
* ## Por qué sólo cuatro operaciones
|
|
23
|
+
*
|
|
24
|
+
* Listar y subida multiparte son las dos que piden el SDK de AWS de verdad
|
|
25
|
+
* —paginación y reanudación— y el ejecutor hoy no tiene ni un `@aws-sdk/*`.
|
|
26
|
+
* Entrar sin esa dependencia y traerla cuando aparezca la operación que la
|
|
27
|
+
* justifique es más barato que al revés. Y un nodo con veinte operaciones es un
|
|
28
|
+
* nodo que nadie entiende.
|
|
29
|
+
*/
|
|
30
|
+
export const BUCKET_OPERATIONS = [
|
|
31
|
+
"presignDownload",
|
|
32
|
+
"putObject",
|
|
33
|
+
"headObject",
|
|
34
|
+
"deleteObject",
|
|
35
|
+
];
|
|
36
|
+
export function isBucketOperation(value) {
|
|
37
|
+
return (typeof value === "string" &&
|
|
38
|
+
BUCKET_OPERATIONS.includes(value));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Ninguna es iterable.
|
|
42
|
+
*
|
|
43
|
+
* Una operación iterable es la que devuelve una COLECCIÓN sobre la que el nodo
|
|
44
|
+
* de abajo repite. Las cuatro de aquí actúan sobre UN objeto, así que el que
|
|
45
|
+
* viene detrás recibe un resultado, no una lista. El día que entre `listObjects`
|
|
46
|
+
* ésa sí entra en esta lista.
|
|
47
|
+
*/
|
|
48
|
+
export const BUCKET_ITERABLE_OPERATIONS = [];
|
|
49
|
+
/* Ayudantes — repetir el mismo objeto cuatro veces es cómo se desincronizan las
|
|
50
|
+
descripciones. */
|
|
51
|
+
const objectKey = (placeholder) => ({
|
|
52
|
+
name: "key",
|
|
53
|
+
label: "Object key",
|
|
54
|
+
type: "template",
|
|
55
|
+
required: true,
|
|
56
|
+
placeholder,
|
|
57
|
+
description: "La ruta dentro del bucket. Sin barra inicial. Admite {{payload.x}}.",
|
|
58
|
+
});
|
|
59
|
+
export const BUCKET_OPERATION_SPECS = {
|
|
60
|
+
presignDownload: {
|
|
61
|
+
label: "Sign download link",
|
|
62
|
+
description: "Devuelve una URL temporal para descargar un objeto privado. No mueve el fichero.",
|
|
63
|
+
apiRoute: "GET (presigned)",
|
|
64
|
+
params: [
|
|
65
|
+
objectKey("cuadernillos/{{payload.orderId}}.pdf"),
|
|
66
|
+
{
|
|
67
|
+
name: "expiresIn",
|
|
68
|
+
label: "Link valid for (seconds)",
|
|
69
|
+
type: "number",
|
|
70
|
+
required: true,
|
|
71
|
+
default: 3600,
|
|
72
|
+
min: 60,
|
|
73
|
+
/* El tope de SigV4 es de siete días y no se puede pasar: firmar por
|
|
74
|
+
más tiempo produce una URL que el proveedor rechaza, y el error
|
|
75
|
+
llega tarde y sin explicación. */
|
|
76
|
+
max: 604800,
|
|
77
|
+
description: "Desde 60 s hasta 7 días, que es el máximo que admite la firma. Pasado ese plazo el enlace deja de servir.",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "downloadAs",
|
|
81
|
+
label: "Download as (filename)",
|
|
82
|
+
type: "template",
|
|
83
|
+
placeholder: "Cuadernillo 1.pdf",
|
|
84
|
+
description: "Si se rellena, el navegador DESCARGA el fichero con ese nombre en vez de abrirlo. Déjalo vacío para que lo abra.",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
},
|
|
88
|
+
putObject: {
|
|
89
|
+
label: "Upload object",
|
|
90
|
+
description: "Guarda un objeto en el bucket. Sobreescribe si la clave ya existe.",
|
|
91
|
+
apiRoute: "PUT /{bucket}/{key}",
|
|
92
|
+
params: [
|
|
93
|
+
objectKey("recibos/{{payload.orderId}}.json"),
|
|
94
|
+
{
|
|
95
|
+
name: "body",
|
|
96
|
+
label: "Contents",
|
|
97
|
+
type: "textarea",
|
|
98
|
+
required: true,
|
|
99
|
+
placeholder: "{{payload}}",
|
|
100
|
+
description: "Lo que se guarda. Admite {{payload.x}}; un objeto se guarda como JSON.",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "contentType",
|
|
104
|
+
label: "Content type",
|
|
105
|
+
type: "template",
|
|
106
|
+
default: "application/json",
|
|
107
|
+
placeholder: "application/pdf",
|
|
108
|
+
description: "Lo que el navegador usará para decidir qué hacer con el fichero.",
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
},
|
|
112
|
+
headObject: {
|
|
113
|
+
label: "Check object exists",
|
|
114
|
+
description: "Comprueba si un objeto existe, y su tamaño, sin descargarlo.",
|
|
115
|
+
apiRoute: "HEAD /{bucket}/{key}",
|
|
116
|
+
params: [
|
|
117
|
+
objectKey("cuadernillos/{{payload.orderId}}.pdf"),
|
|
118
|
+
{
|
|
119
|
+
name: "failIfMissing",
|
|
120
|
+
label: "Fail when the object is missing",
|
|
121
|
+
type: "booleanSelect",
|
|
122
|
+
options: [
|
|
123
|
+
{ value: "true", label: "Sí — cortar el flujo" },
|
|
124
|
+
{ value: "false", label: "No — seguir con exists: false" },
|
|
125
|
+
],
|
|
126
|
+
description: 'Con "No", el paso sale bien y el de abajo decide. Con "Sí", un objeto que falta corta el flujo.',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
deleteObject: {
|
|
131
|
+
label: "Delete object",
|
|
132
|
+
description: "Borra un objeto del bucket. No se puede deshacer.",
|
|
133
|
+
apiRoute: "DELETE /{bucket}/{key}",
|
|
134
|
+
params: [objectKey("temporales/{{payload.id}}.tmp")],
|
|
135
|
+
},
|
|
136
|
+
};
|
package/dist/esm/connections.js
CHANGED
|
@@ -73,6 +73,7 @@ export const NODE_CONNECTIONS = {
|
|
|
73
73
|
shopifyAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
74
74
|
githubAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
75
75
|
jiraAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
76
|
+
bucketAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
76
77
|
googleContactsAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
77
78
|
googleAnalyticsAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
|
78
79
|
notionAction: { acceptsInputFrom: ACTION_INPUTS, canOutputTo: PROCESSING_OUTPUTS },
|
package/dist/esm/dispatch.js
CHANGED
|
@@ -51,6 +51,7 @@ export const NODE_DISPATCH = {
|
|
|
51
51
|
shopifyAction: { service: 'shopifyActionsService', collection: 'shopifyactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
52
52
|
githubAction: { service: 'githubActionsService', collection: 'githubactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
53
53
|
jiraAction: { service: 'jiraActionsService', collection: 'jiraactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
54
|
+
bucketAction: { service: 'bucketActionsService', collection: 'bucketactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
54
55
|
slackAction: { service: 'slackActionsService', collection: 'slackactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
55
56
|
googleContactsAction: { service: 'googleContactsActionsService', collection: 'googlecontactsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
|
56
57
|
googleAnalyticsAction: { service: 'googleAnalyticsActionsService', collection: 'googleanalyticsactions', hasFilters: true, outputFields: ['outputNodes'], customDispatch: true, pipelineDispatch: 'excluded' },
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ export { GITHUB_OPERATIONS, GITHUB_OPERATION_SPECS, GITHUB_DROPDOWN_OPERATIONS,
|
|
|
36
36
|
export type { GithubOperation, GithubParamType, GithubParamSpec, GithubOperationSpec, } from './github-operations.js';
|
|
37
37
|
export { JIRA_OPERATIONS, JIRA_OPERATION_SPECS, JIRA_DROPDOWN_OPERATIONS, JIRA_ITERABLE_OPERATIONS, isJiraOperation, } from './jira-operations.js';
|
|
38
38
|
export type { JiraOperation, JiraParamType, JiraParamSpec, JiraOperationSpec, } from './jira-operations.js';
|
|
39
|
+
export { BUCKET_OPERATIONS, BUCKET_OPERATION_SPECS, BUCKET_ITERABLE_OPERATIONS, isBucketOperation, } from './bucket-operations.js';
|
|
40
|
+
export type { BucketOperation, BucketParamType, BucketParamSpec, BucketOperationSpec, } from './bucket-operations.js';
|
|
39
41
|
export { SLACK_OPERATIONS, SLACK_OPERATION_SPECS, SLACK_CAPACIDADES_POR_CREDENCIAL, operacionesDeSlackPara, slackPuedeEjecutar, camposDeSlackNoDisponibles, isSlackOperation, } from './slack-operations.js';
|
|
40
42
|
export type { SlackOperation, SlackParamSpec, SlackOperationSpec, } from './slack-operations.js';
|
|
41
43
|
export { SLACK_TOOLKIT_SPECS, SLACK_TOOLKIT_BY_TOOL_NAME, herramientasDeSlackPara, } from './slack-toolkit.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export { MAILCHIMP_OPERATIONS, MAILCHIMP_OPERATION_SPECS, MAILCHIMP_CONTACT_STAT
|
|
|
32
32
|
export { SHOPIFY_OPERATIONS, SHOPIFY_OPERATION_SPECS, SHOPIFY_TAGGABLE_RESOURCES, SHOPIFY_SEARCHABLE_RESOURCES, isShopifyOperation, } from './shopify-operations.js';
|
|
33
33
|
export { GITHUB_OPERATIONS, GITHUB_OPERATION_SPECS, GITHUB_DROPDOWN_OPERATIONS, GITHUB_ITERABLE_OPERATIONS, isGithubOperation, } from './github-operations.js';
|
|
34
34
|
export { JIRA_OPERATIONS, JIRA_OPERATION_SPECS, JIRA_DROPDOWN_OPERATIONS, JIRA_ITERABLE_OPERATIONS, isJiraOperation, } from './jira-operations.js';
|
|
35
|
+
export { BUCKET_OPERATIONS, BUCKET_OPERATION_SPECS, BUCKET_ITERABLE_OPERATIONS, isBucketOperation, } from './bucket-operations.js';
|
|
35
36
|
export { SLACK_OPERATIONS, SLACK_OPERATION_SPECS, SLACK_CAPACIDADES_POR_CREDENCIAL, operacionesDeSlackPara, slackPuedeEjecutar, camposDeSlackNoDisponibles, isSlackOperation, } from './slack-operations.js';
|
|
36
37
|
/* Misma pareja que en Discord: `SlackOperationSpec` es el formulario,
|
|
37
38
|
`SlackToolkitSpec` es la herramienta que ve el LLM. */
|
package/dist/esm/registry.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* all per-node maps (colors, URLs, Redux keys, palette, delete, etc.)
|
|
6
6
|
* from this registry. No more 18+ touch points.
|
|
7
7
|
*/
|
|
8
|
-
import type { NodeType } from
|
|
9
|
-
export type NodeGroup =
|
|
8
|
+
import type { NodeType } from "./types.js";
|
|
9
|
+
export type NodeGroup = "Sources" | "Flow Control" | "Actions" | "Annotations";
|
|
10
10
|
export interface NodeRegistryEntry {
|
|
11
11
|
/** Canonical type (e.g., "httpAction") */
|
|
12
12
|
type: NodeType;
|
|
@@ -69,7 +69,7 @@ export interface NodeVersionSpec {
|
|
|
69
69
|
* `current` is what a new node is born on — exactly one per type.
|
|
70
70
|
* `legacy` still runs but is on its way out. `beta` is opt-in.
|
|
71
71
|
*/
|
|
72
|
-
status:
|
|
72
|
+
status: "current" | "legacy" | "beta";
|
|
73
73
|
/**
|
|
74
74
|
* The config fields this version understands.
|
|
75
75
|
*
|
|
@@ -106,7 +106,7 @@ export declare const NODE_TYPE_TO_PREFIX: Record<string, string>;
|
|
|
106
106
|
* pass it, and the tests can exercise a versioned type without waiting
|
|
107
107
|
* for a real one to exist.
|
|
108
108
|
*/
|
|
109
|
-
export type VersionCatalog = Record<string, Pick<NodeRegistryEntry,
|
|
109
|
+
export type VersionCatalog = Record<string, Pick<NodeRegistryEntry, "type" | "versions">>;
|
|
110
110
|
/** True when this type ships more than one version. False for every type today. */
|
|
111
111
|
export declare function isVersioned(type: string, catalog?: VersionCatalog): boolean;
|
|
112
112
|
/**
|