Un guardián para los fallos que solo ocurren en la plataforma
Dos cosas habían derribado producción, y ninguna podía fallar en local: un import sin extensión que un bundler oculta y Node rechaza, y un patrón de vercel.json que no produce ninguna implementación. Ambas se comprueban ahora antes del build, y el guardián se puso a prueba reintroduciendo cada error.
Los tipos pasan, el bundler compila, el servidor de desarrollo responde — y el despliegue contesta 500 a cada petición. Este script existe para esa brecha. Las tres herramientas anteriores resuelven módulos y leen configuración como lo hace un bundler; la función desplegada no hace ninguna de las dos cosas, y el script comprueba exactamente esa diferencia. Se ejecuta dentro de npm run build y termina con un código de error, para que ninguno de los dos fallos vuelva a llegar a un push.
Lo que rechaza
Un import relativo sin extensión. La API se ejecuta como ESM sobre Node, donde ./faq no resuelve y ./faq.js sí. Una sola línea así, alcanzable desde el propio grafo de imports del servidor, hizo que cada ruta /api respondiera con FUNCTION_INVOCATION_FAILED.
Un import de .json en ese grafo. import { version } from '../package.json' pasa la comprobación de tipos, compila y funciona en el servidor de desarrollo. El paquete desplegado contiene módulos y no el repositorio, así que el archivo simplemente no está, y el import lanza un error al cargar el módulo — lo que ocurre en cada petición, así que toda la API devolvía 500.
Un patrón source que el enrutador de la plataforma no puede interpretar. El síntoma aquí no es un despliegue que falla: un patrón inválido se rechaza antes de que empiece un build, así que no hay ningún despliegue en absoluto, y producción se queda en silencio en el commit anterior. Los patrones se interpretan con la misma librería con la que los interpreta la plataforma.
Una versión que se contradice a sí misma. shared/version.ts debe coincidir con package.json. Es una copia precisamente porque un import de JSON es el fallo de arriba, y una copia que nadie comprueba se queda desactualizada; el manifiesto de la extensión y la etiqueta de versión leen una, el connector lee la otra.
Cómo decide dónde mirar
La regla se aplica a los archivos que la función desplegada carga de verdad, y ese conjunto no es «todo lo que hay bajo server/» — sigue los imports adonde lleven, que es como un archivo bajo src/lib acabó formando parte del servidor. Así que empieza en el punto de entrada de la función y recorre desde ahí. Un import que solo trae tipos se salta: se elimina al compilar, así que su especificador nunca llega a ser algo que un runtime tenga que resolver.
Lo que no es
No es una suite de pruebas ni un linter. Conoce cuatro diferencias concretas entre la plataforma y un portátil y nada más; no notará un error de lógica, y avisa en vez de fallar si la librería con la que interpreta los patrones no está instalada, porque el objetivo es atrapar el error en la máquina donde se está cometiendo. Cada regla se puso a prueba reintroduciendo su error y comprobando que la verificación fallaba.
Relacionado: documentación que vive en el repositorio, y publicar Markdown desde GitHub Actions.