/** * El nodo de bucket: mirar, leer, guardar, firmar y borrar objetos en un * almacenamiento compatible con S3. * * ## Por qué se llama `bucket` y no `r2` * * Porque el proveedor es un ENDPOINT, no un tipo de nodo. La credencial * `aws_s3` ya guarda `endpoint`, `bucket` y `region`, así que el mismo nodo * habla con Cloudflare R2, con AWS S3, con MinIO o con Backblaze sin cambiar * una línea. Llamarlo `r2Action` habría obligado, el día que llegue AWS, a * tener dos nodos casi idénticos o a renombrar un tipo — y el prefijo del tipo * vive DENTRO de los ids de nodo ya guardados en la base de cada cliente, así * que renombrar es migrar datos. * * ## La operación que motiva el nodo * * `presignDownload`. La plataforma sabe firmar peticiones S3 desde el nodo * HTTP —`common/s3-signer.ts`— pero **por cabecera**, y una cabecera no cabe en * un enlace que se manda por correo. Sin esto no había forma de entregarle a un * comprador una descarga temporal desde un flujo. * * ## Por qué siete, y qué sigue fuera * * Las cuatro primeras —`presignDownload`, `putObject`, `headObject`, * `deleteObject`— actúan todas sobre un objeto que ya sabes nombrar. Faltaba lo * contrario: **no había forma de mirar dentro del bucket**, ni de traerse el * contenido de un objeto al flujo, ni de dejar que un tercero SUBA sin darle la * credencial. Eso son las tres nuevas: * * - `listObjects` — qué ficheros y qué CARPETAS hay bajo un prefijo. S3 no * tiene carpetas de verdad; con `delimiter` te las sintetiza como prefijos * comunes, que es exactamente lo que una persona quiere ver. * - `getObject` — el contenido, no un enlace al contenido. `presignDownload` * da una URL para que la abra OTRO; cuando el paso de abajo necesita los * bytes, una URL no sirve. * - `presignUpload` — el simétrico de `presignDownload`. * * Aquí se decía que listar «pedía el SDK de AWS de verdad». No lo pide: * `ListObjectsV2` contesta XML plano y un raspador corto lo lee. Lo que sí * sigue pidiendo el SDK es la **subida multiparte** —reanudación, partes, * reintentos por parte— y por eso ésa no está. Traer `@aws-sdk/*` el día que * aparezca la operación que lo justifique sigue siendo más barato que al revés. * Y un nodo con veinte operaciones es un nodo que nadie entiende. */ export declare const BUCKET_OPERATIONS: readonly ["presignDownload", "putObject", "headObject", "deleteObject", "listObjects", "getObject", "presignUpload"]; export type BucketOperation = (typeof BUCKET_OPERATIONS)[number]; export declare function isBucketOperation(value: unknown): value is BucketOperation; /** * Sólo `listObjects`. * * Una operación iterable es la que devuelve una COLECCIÓN sobre la que el nodo * de abajo repite. Las otras seis actúan sobre UN objeto —o devuelven UN * enlace—, así que el que viene detrás recibe un resultado, no una lista. * * ⚠️ Dos cosas que hay que saber antes de implementarla, porque descubrirlas * por las malas cuesta una tarde: * * 1. **Se itera `objects`, y sólo `objects`.** `folders` viaja en el * contenedor junto a `truncated`, `nextToken`, `prefix` y `count`. Una * operación tiene un campo iterable, y aquí es el de los ficheros; si las * carpetas se iteraran también, el aviso de «hay más» se perdería justo en * la operación que existe para darlo. * 2. **Un prefijo sin nada da `count: 0`, y el nodo de abajo corre CERO * veces**, sin error. Es la semántica correcta de una lista vacía, y es * también la trampa clásica: parece que el flujo «no hizo nada» cuando en * realidad hizo lo que debía. */ export declare const BUCKET_ITERABLE_OPERATIONS: readonly BucketOperation[]; export type BucketParamType = /** La clave del objeto dentro del bucket. Con autocompletado de * `{{payload.*}}`, porque el 90% de los casos la construye del evento: * `cuadernillos/{{payload.orderId}}.pdf`. */ "template" /** Área de texto larga, también con autocompletado. */ | "textarea" /** `` de `''` / `'true'` / `'false'` que se guarda como BOOLEANO, o * no se guarda si es `''`. "— sin tocar —" tiene que significar que la clave * no viaja, no que viaja en `false`. */ | "booleanSelect"; export interface BucketParamSpec { /** La clave de `operationConfig`. Es lo que lee la api, no un nombre de UI. */ name: string; label: string; type: BucketParamType; required?: boolean; /** Ayuda bajo el campo. Texto plano: el paquete no lleva React. */ description?: string; placeholder?: string; /** Prerrellenado cuando la config guardada no trae valor para esta clave. */ default?: string | number; /** Obligatorio en `select` y `booleanSelect`. */ options?: ReadonlyArray<{ value: string; label: string; }>; min?: number; max?: number; /** Se pinta en la pestaña "Advanced" en vez de en "Config". */ advanced?: boolean; } export interface BucketOperationSpec { /** Etiqueta de la fila en el desplegable de operación. */ label: string; /** Sub-línea bajo la etiqueta. */ description: string; /** La llamada S3 a la que mapea, para poder cotejarla con los docs. */ apiRoute: string; /** Esquema de parámetros. El orden ES el orden en pantalla. */ params: BucketParamSpec[]; } export declare const BUCKET_OPERATION_SPECS: Record;