Scopes — el contrato
Declara una vez a dónde va un archivo, quién puede leerlo, qué tamaño admite y qué reemplaza. Ambos lados validan contra la misma definición.
Scopes — el contrato
Un scope es un destino con nombre: la única fuente de verdad sobre dónde aterriza un archivo, quién puede leerlo y qué se acepta ahí. El registro es un objeto plano que importan el cliente y el servidor, y eso es lo que hace que las dos validaciones coincidan por construcción.
Definir scopes
import { defineScopes, MB } from 'uploaderkit'
export const scopes = defineScopes({
'user-avatar': {
path: userId => `Users/${userId}/avatar`,
visibility: 'public',
accept: ['png', 'jpg', 'jpeg', 'webp'],
maxBytes: 5 * MB,
category: 'image',
compress: { maxWidth: 512, quality: 0.8, stripExif: true },
},
})| Campo | Significado |
|---|---|
path | (entityId, file) => string — la key de almacenamiento. Tú controlas colisiones y forma de carpetas. |
visibility | 'public' (URL directa) o 'private' (solo URL firmada con expiración). |
accept | Extensiones permitidas aquí. Más angosto que el preset de la categoría, nunca más ancho. |
maxBytes | Tope duro. Se exportan los helpers KB / MB / GB. |
category | 'image' | 'pdf' | 'document' | 'data' | 'video' | 'audio' | 'certificate' | 'key' | 'any'. Elige el preset que decide si se leen los magic numbers. |
encrypt | Entrega los bytes al cipher de la app antes de que salgan del servidor. |
compress | Pipeline de imagen en el cliente: maxWidth, maxHeight, quality, stripExif (por defecto true). |
maxFiles | Cuántos archivos puede tener una entidad aquí. Default 1; el uploader deriva multiple de esto. |
replace | Qué borra una subida. Derivado por default — ver Replace. |
prefix | (entityId) => string — objetos que un replace 'entity' puede borrar. Default: la carpeta de la key resuelta. |
metadata | Etiquetas libres que se reenvían al provider cuando las soporta. |
defineScopes devuelve un ScopeRegistry: names, get(name), has(name) y
accept(name) — este último es el string listo para <input accept>.
Replace — nunca dejar un archivo muerto
El object storage no limpia solo. Un scope cuya key incluye el nombre del
archivo escribe un objeto NUEVO cada vez, así que re-subir un logo deja el
anterior pagando renta para siempre. replace decide eso, y su default se
deriva para que no haya prop que olvidar:
| El scope | replace derivado | Por qué |
|---|---|---|
maxFiles: 1 (default), la key lleva file.name | 'entity' | Cada subida cae en una key nueva — hay que barrer la anterior. |
maxFiles: 1, la key ignora file.name | 'key' | La key es estable; el provider ya sobrescribe en su lugar. |
maxFiles > 1 | 'key' | Es una colección: los hermanos son el punto. |
Declararlo explícito solo sirve para salirse: replace: false conserva todas
las versiones.
El barrido 'entity' corre después de un put exitoso y borra todo lo que
esté bajo el prefijo de la entidad y no sea la key nueva. Dos guardas evitan
que alcance de más, ambas al momento de defineScopes:
replace: 'entity'junto conmaxFiles > 1truena. Un scope no puede guardar una colección y borrarla en cada subida.- Dos scopes cuyas carpetas se solapan truenan si alguno barre, así que subir
un avatar nunca puede borrar los documentos del mismo usuario. Dale a cada
uno su carpeta, o acota uno con
prefix.