Arquivos (GridFS)

files grava arquivos no MongoDB do App (bucket oon_files), isolados por tenant e compartilhados entre réplicas.

O módulo files substitui a pasta local uploads, que é de cada pod: com várias réplicas, um arquivo gravado em uma delas não aparecia nas outras e se perdia no reinício. Agora os arquivos ficam em GridFS no banco do próprio App, no bucket oon_files, sempre com escopo de tenant.

Uso em uma rota

const { defineRoutes, files, GenericError } = require("@oondemand/oon-core-back");

defineRoutes("/anexos", (router) => {
  router.private.post("/", { permission: "anexos.write" }, async (req, res) => {
    const { filename, contentType, base64 } = req.body ?? {};
    if (!filename || !base64) throw new GenericError("Envie o arquivo.", { statusCode: 422, code: "ANEXO_INVALIDO" });
    const saved = await files.forRequest(req).save({
      data: Buffer.from(base64, "base64"),
      filename,
      contentType,
      metadata: { origem: "upload" },
    });
    res.status(201).json(saved);
  });

  router.private.get("/:id", { permission: "anexos.read" }, async (req, res) => {
    await files.forRequest(req).send(res, req.params.id, { download: true });
  });

  router.private.get("/", { permission: "anexos.read" }, async (req, res) => {
    res.json(await files.forRequest(req).list({ limit: 50 }));
  });
});

files.forRequest(req) usa o tenant de req.accessContext; sem tenant (Apps none), o escopo é global.

API

Função Descrição
saveFile({ data, filename, contentType?, metadata?, maxBytes?, tenantId | global }) Grava Buffer, string ou Readable; devolve os metadados
getFileInfo(id, owner) Metadados no escopo
openFile(id, owner) { file, stream } para leitura em stream
readFile(id, owner) { file, data: Buffer }
listFiles(owner, { limit?, filename? }) Lista do mais recente ao mais antigo (limite até 500)
deleteFile(id, owner) Remove; { deleted: true, id }
sendFile(res, id, owner, { download? }) Responde com Content-Type, Content-Length, nosniff e Content-Disposition
forRequest(req) Atalho com save, info, open, read, list, remove, send

Metadados retornados:

{ "id": "…", "filename": "nota.pdf", "length": 48213, "contentType": "application/pdf", "tenantId": "t-1", "metadata": { "origem": "upload" }, "uploadDate": "…" }

Limites e erros

Código Status Causa
FILE_TENANT_REQUIRED 400 Operação sem tenant e sem global: true
FILE_NOT_FOUND 404 ID inexistente ou de outro tenant
FILE_TOO_LARGE 413 Acima de maxBytes (padrão 25 MB)
FILE_NAME_INVALID 422 Nome vazio, maior que 255 caracteres ou com /, \ ou NUL
FILE_STORAGE_UNAVAILABLE 503 Banco indisponível