imagekit-probe.js

Overview

services/api/src/modules/reconciliation/imagekit-probe.js defines a read-only probe over the ImageKit SDK for the erasing reconciliation flow. It exists to observe file state without exposing any delete capability, and it only exposes getFile through a frozen object. The file is part of the reconciliation path used by reconcileErasingClaim in services/api/src/modules/reconciliation/erasing-claim-reconciliation.service.js fileciteturn0file10turn0file7

The module treats every lookup as an observation. It disables automatic retries with maxRetries: 0, applies an explicit timeout, and only translates a NotFoundError with HTTP 404 into not_found. All other failures become structured error observations instead of being treated as absence. fileciteturn0file7turn0file9

[!NOTE] The probe depends on an injected getClient factory. The module does not construct the ImageKit client itself.

How it works

flowchart TB
    A[createImageKitProbe] --> B[Validate getClient]
    B --> C[Freeze adapter]
    C --> D[getFile]
    D --> E[Call getClient]
    E --> F[client files get]
    F --> G[exists]
    F --> H[not found]
    F --> I[error]
    I --> J[errorClass]

createImageKitProbe first checks that getClient is a function. If not, it throws immediately. When the returned probe receives fileId, it calls getClient, then client.files.get with maxRetries: 0 and the configured timeout. Successful reads become kind: "exists" observations, while failures are normalized into not_found or error results. fileciteturn0file7turn0file9

Key components

{
    "title": "createImageKitProbe",
    "content": "Funci\u00f3n f\u00e1brica que crea un adaptador de solo lectura sobre un cliente ImageKit inyectado. Devuelve un objeto congelado con getFile.",
    "type": "function",
    "filePath": "services/api/src/modules/reconciliation/imagekit-probe.js",
    "badges": [
        "public"
    ]
}
{
    "title": "errorClass",
    "content": "Normaliza errores del SDK de ImageKit en clases observables como TIMEOUT, NETWORK, AUTHENTICATION, PERMISSION, RATE_LIMIT, SERVER, HTTP_xx y UNEXPECTED.",
    "type": "function",
    "filePath": "services/api/src/modules/reconciliation/imagekit-probe.js",
    "badges": [
        "public"
    ]
}

Data & fields

[
    {
        "name": "options",
        "type": "object",
        "description": "Configuración para crear el probe.",
        "children": [
            {
                "name": "getClient",
                "type": "() => { files: { get: Function } }",
                "required": true,
                "description": "Fábrica que entrega el cliente ImageKit usado por getFile."
            },
            {
                "name": "timeoutMs",
                "type": "number",
                "description": "Timeout usado en client.files.get. Su valor por defecto es 15000."
            }
        ]
    }
]
[
    {
        "name": "fileId",
        "type": "string",
        "required": true,
        "description": "Identificador del archivo consultado."
    },
    {
        "name": "kind",
        "type": "string",
        "required": true,
        "description": "Estado observado. Los valores usados por el módulo son exists, not_found y error."
    },
    {
        "name": "status",
        "type": "number | null",
        "description": "Código HTTP observado cuando la respuesta es un error."
    },
    {
        "name": "errorClass",
        "type": "string",
        "description": "Clase normalizada del error cuando kind es error."
    },
    {
        "name": "file",
        "type": "object",
        "description": "Metadatos normalizados cuando kind es exists.",
        "children": [
            {
                "name": "fileId",
                "type": "string",
                "required": true,
                "description": "fileId del objeto devuelto por ImageKit, convertido a string."
            },
            {
                "name": "filePath",
                "type": "string",
                "required": true,
                "description": "filePath del objeto devuelto por ImageKit, convertido a string."
            }
        ]
    }
]

Behaviors

  • errorClass(error) — clasifica errores del SDK en categorías observables.
  • createImageKitProbe({ getClient, timeoutMs }) — crea un adaptador congelado con un único método público.
  • getFile(fileId) — obtiene una observación del archivo y devuelve un resultado estructurado.
  • Si getClient no es función, createImageKitProbe lanza imagekit-probe: getClient es obligatorio.
  • Si getClient() lanza un error, getFile devuelve kind: "error" con NOT_CONFIGURED cuando error.code === "IMAGEKIT_NOT_CONFIGURED", o CLIENT_UNAVAILABLE en cualquier otro caso.
  • Si client.files.get responde correctamente, getFile devuelve kind: "exists" y normaliza fileId y filePath a cadenas. fileciteturn0file7turn0file9
  • Si client.files.get lanza NotFoundError con status === 404, getFile devuelve kind: "not_found" y status: 404. fileciteturn0file7turn0file11
  • Cualquier otro error se traduce en kind: "error" y un errorClass calculado por errorClass. fileciteturn0file7turn0file11

Error classification

errorClass interpreta el tipo de fallo de forma determinista:

  • APIConnectionTimeoutError → TIMEOUT
  • APIConnectionError → NETWORK
  • APIError con status 401 → AUTHENTICATION
  • APIError con status 403 → PERMISSION
  • APIError con status 429 → RATE_LIMIT
  • APIError con status >= 500 → SERVER
  • APIError con cualquier otro status → HTTP_<status>
  • cualquier otro error → UNEXPECTED fileciteturn0file7turn0file11

Workflows

1. Validar la fábrica | createImageKitProbe exige un getClient funcional antes de construir el probe.
2. Obtener el cliente | getFile invoca getClient dentro de un bloque protegido.
3. Consultar el archivo | client.files.get se ejecuta con maxRetries: 0 y timeout explícito.
4. Normalizar la observación | el resultado se convierte en exists, not_found o error.
5. Clasificar el fallo | los errores no 404 pasan por errorClass para producir una clase estable.

[!IMPORTANT] Este módulo no implementa borrado. El objeto retornado solo expone getFile, y el código de prueba verifica que no hay acceso a delete. fileciteturn0file9turn0file11

Gotchas & edge cases

[!WARNING] NotFoundError solo se traduce en not_found cuando status === 404. Otros errores con status 404 no reciben ese tratamiento especial.

[!WARNING] Si getClient() falla, el módulo no intenta distinguir todas las causas. Solo reconoce IMAGEKIT_NOT_CONFIGURED como NOT_CONFIGURED; el resto cae en CLIENT_UNAVAILABLE.

[!CAUTION] El probe fuerza maxRetries: 0. Cada lectura se comporta como una observación única, no como una operación con reintentos automáticos. fileciteturn0file7turn0file9

createImageKitProbe alimenta el flujo de reconciliación de reconcileErasingClaim, que consume un objeto con getFile(fileId) para clasificar evidencia del proveedor antes de decidir si una asignación erasing puede pasar a deleted.

Los tests de services/api/test/erasing-reconciliation.test.js confirman su comportamiento observado: 404 produce not_found, otros errores se clasifican por clase, el timeout es explícito, y el adaptador solo expone getFile.