npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@existo/middlewares

v1.2.0

Published

Express middlewares

Readme

@existo/middlewares

Colección de middlewares de Express diseñados para usarse con Astro en modo SSR.

Índice


Descripción general

Este repositorio contiene una colección de middlewares de Express diseñados para usarse con Astro en modo SSR. Y con el adaptador de node en modo middleware.

Para empesar a usarlos, se debe importar el middleware deseado y registrarlo en la aplicación de Express.

Instalación

Estos middlewares vienen todos en un solo paquete @existo/middlewares y se pueden instalar con npm install @existo/middlewares.

Para usarlos en express se debe importar el middleware deseado y registrarlo en la aplicación de Express.

import { routeIgnorer } from '@existo/middlewares';

app.use(routeIgnorer({ ... }));

Ejemplo de configuración

Ahora veremos un ejemplo de configuración de los middlewares de @existo/middlewares.

En nuestro archivo server.js se debe importar el middleware deseado y registrarlo en la aplicación de Express.

El orden en que se registran los middlewares es importante. Este puede depender de la configuración de la aplicación y de las necesidades de la misma.

El orden recomendado es:

import express from 'express';
import { cors, cookieParser } from 'express';
import { geolocation, routeIgnorer, trailingSlash, redirect, cacheControl, notFound, routeAnouncer } from '@existo/middlewares';
import { astroHandler } from 'dist/server/entry.mjs';


const app = express(); // Instancia de Express

/**
* Middlewares de Express necesarios para el funcionamiento de los middlewares de @existo/middlewares
*/
app.set('trust proxy', true);
app.use(cookieParser());

/**
* Middlewares de @existo/middlewares
*/
app.use(geolocation({ ... })); // Middleware de geolocalización
app.use(routeAnouncer({ ... })); // Middleware para anunciar las rutas a nivel de Express globalmente
app.use(routeIgnorer({ ... })); // Ignorador de rutas a nivel de Express globalmente
app.use(trailingSlash({ ... })); // Middleware para redirigir las rutas con y sin trailing slash
app.use(redirect({ ... })); // Middleware para redireccionar las rutas
app.use(cacheControl({ ... })); // Middleware para establecer el cache control

/**
* Middlewares de Astro
*/
app.use() // Servidor de estaticos de Astro
app.use(astroHandler); // Handler de Astro

/**
* Middleware 404 de@existo/middlewares
*/
app.use(notFound(astroHandler, { ... })); // Middleware para manejar el 404

// Arrancar el servidor
app.listen(3000, () => {
  console.log('Server is running on port 3000 (http://localhost:3000)');
});

Para el uso del middleware redirect se debe crear un archivo _redirects en la raíz del proyecto, de lo contrario se arrojara un error.


Requisitos

Para usar los middlewares de @existo/middlewares se deben tener instalados los siguientes paquetes:

  • express
  • micromatch
  • cookie-parser
  • dotenv

Middlewares

routeIgnorer

Este middleware se encarga de ignorar rutas a nivel de Express globalmente. Sirve para ignorar rutas a nivel de Express globalmente (Devuelve un 404 forzado a nivel de Express). La idea es no ensuciar los logs y ahorrar procesamiento en los middlewares posteriores.

Opciones

| Opción | Tipo | Por defecto | Descripción | |--------|------|-------------|-------------| | ignoredPaths | string[] | [] | Patrones de rutas a ignorar (soporta glob con micromatch) |

Ejemplo

import { routeIgnorer } from '@existo/middlewares';

app.use(routeIgnorer({
  ignoredPaths: ['/favicon.ico', '/*.txt', '/api/**'],
}));

/**
* En este caso por nuestro servidor no pasaran la ruta /favicon.ico, la ruta /archivo.txt y todas las rutas que coincidan con el patrón /api/**
* Esto aplica para todos los métodos HTTP (GET, POST, PUT, DELETE, etc.)
*/

geolocation

Geolocation es un middleware que se encarga de detectar la geolocalización del usuario y asignar las cookies de país y idioma. La idea es que este middleware se ejecute antes de los middlewares como redirects ya que necesita las cookies de país y idioma.

Su funcionamiento es el siguiente:

  • Si ya tiene las cookies de país y idioma, pasa al siguiente middleware
  • Si no tiene la cookie de país, intenta obtener el país del IP del usuario usando la API de geolocalización de https://geoip.dnsproxymanager.com/ con la IP del usuario
  • Si no tiene la cookie de idioma, intenta obtener el idioma del usuario usando el header accept-language
  • En caso de que no se pueda obtener el país o el idioma, se usa el valor por defecto
  • También asigna las cookies a req.cookies para que esté disponible en middlewares posteriores

Variables de entorno requeridas

| Variable | Descripción | |----------|-------------| | GEOLOCATION_BEARER | Token de autenticación para la API de geolocalización |

Opciones

| Opción | Tipo | Por defecto | Descripción | |--------|------|-------------|-------------| | defaultCountry | string | 'unknown' | País por defecto si no se puede detectar | | defaultLocale | string | 'es' | Idioma por defecto si no se puede detectar |

Cookies que genera

| Cookie | Descripción | |--------|-------------| | country | Código de país ISO 3166-1 alpha-2 (ej: es, us) | | locale | Código de idioma ISO 639-1 (ej: es, en) |

Ejemplo

import { geolocation } from '@existo/middlewares';

app.use(geolocation());

/**
* En este caso se usará el valor por defecto decidido por existo para el país y el idioma
*/

trailingSlash

Este middleware se encarga de redirigir las rutas con y sin trailing slash.

Opciones

| Opción | Tipo | Por defecto | Descripción | |--------|------|-------------|-------------| | trailingMode | 'always' \| 'never' \| 'ignore' | 'always' | Comportamiento del trailing slash (Ver documentacion de Astro (https://docs.astro.build/en/reference/configuration-reference/#trailingslash)) | | excludedPaths | string[] | [] | Patrones de rutas a excluir en las que no queremos que actue el middleware (soporta glob con micromatch) | | internalRewrite | boolean | false | Si activar el rewrite interno (la URL con / se mantiene en el navegador pero internamente Express trabaja sin ella creando un proxy interno) | | redirectStatus | number | 301 | Status de la redirección |

Ejemplo

import { trailingSlash } from '@existo/middlewares';

app.use(trailingSlash({
  trailingMode: 'always',
  excludedPaths: ['/api/**'],
  redirectStatus: 301,
}));

/**
* En este caso se usará el modo 'always' para redirigir las rutas con trailing slash ("/ al final de la ruta")
* Se excluirán las rutas que coincidan con el patrón /api/** ya que provoara errores si hemos declarado los fetchs sin trailing slash
* No se activará el rewrite interno 
* Se usará el status code 301 por defecto para las redirecciones
*/

redirect

Este middleware se encarga de manejar las redirecciones de las rutas. Su funcionamiento es el siguiente:

  • Si encuentra una redirección, se redirige a la URL de destino
  • Si no encuentra una redirección, pasa al siguiente middleware
  • También maneja los query parameters de las redirecciones
  • También maneja las condiciones de país y idioma de las redirecciones
  • También maneja las redirecciones externas
  • También maneja las redirecciones internas
  • También maneja las redirecciones con y sin trailing slash

IMPORTANTE: Para que este middleware funcione correctamente se debe crear un archivo _redirects en la raíz del proyecto, de lo contrario se arrojara un error.

NOTA: En caso de error de parseo del archivo _redirects se arrojara un error con la linea y el mensaje de error correspondiente. NOTA2: Ten encuenta los trailing slash en la ruta de origen y destino.

Opciones

| Opción | Tipo | Por defecto | Descripción | |--------|------|-------------|-------------| | redirectsFilePath | string | '_redirects' | Ruta al archivo de redirecciones (Ruta relativa a la raíz del proyecto) |

Formato del archivo _redirects

# Sintaxis: <from> [queryParams] <to> <status> [Country=xx,yy | Locale=xx,yy]

/old-path             /new-path         301
/productos/**         /products/:slug   302
/page                 /other            301   Country=us,gb
/page                 /otra             301   Locale=es,ca

# Con query parameters
/search  q=:query     /resultados/:query  302
/legacy  ref=promo    /nueva-promo        301
/test    q=1          /test/:query        302

Ejemplo

import { redirect } from '@existo/middlewares';

app.use(redirect({
  redirectsFilePath: '_redirects',
}));

/**
* En este caso se usará el archivo _redirects en la raíz del proyecto
*/

Ejemplo de redirecciónes válidas:

  1. Redirección clásica:
/sitio-viejo             /sitio-nuevo         301
  1. Redirecion externa:
/sitio-viejo             https://www.sitio-nuevo.com         301
  1. Redirección de con patron de wildcard:
/sitio-viejo/**             /sitio-nuevo/:slug         301

En este caso se redirigira a la ruta /sitio-nuevo/slug-del-sitio-viejo

  1. Mediante redirecciones internas:
/sitio-viejo             /sitio-nuevo/:slug         200
/sitio-viejo             /sitio-nuevo/:slug         404
/sitio-viejo             /sitio-nuevo/:slug         500

Al poner un status code diferente crearas un proxy interno (rewrite) a la ruta /sitio-nuevo/slug-del-sitio-viejo por lo que la url del navegador no cambiara pero internamente Express/Astro trabajara con la ruta /sitio-nuevo/slug-del-sitio-viejo

  1. Mediante parametros de geolocalización:
/sitio-viejo             /sitio-nuevo/:slug         301   Country=us,gb
/sitio-viejo             /sitio-nuevo/:slug         301   Locale=es,ca

En este caso se redirigira a la ruta /sitio-nuevo/slug-del-sitio-viejo solo si el país es US o GB y el idioma es ES o CA

  1. Mediante query parameters:
/sitio-viejo  q=:query     /sitio-nuevo/:query         302

En este caso se redirigira a la ruta /sitio-nuevo/query-del-sitio-viejo solo si el query es igual a query-del-sitio-viejo

  1. Usan query parameters como placeholder:
/sitio-viejo  q=:query     /sitio-nuevo/:query         302

En este caso se capturará el valor del query y se usará como placeholder en la ruta de destino

  1. Combinación de todas las opciones:
/sitio-viejo/**  q=:query   /sitio-nuevo/:slug   200   Country=us,gb  

En este caso se creará un proxy interno (rewrite) a la ruta /sitio-nuevo/slug-del-sitio-viejo solo si el país es US o GB y el query es igual a query-del-sitio-viejo y si la ruta coincide con el patrón /sitio-viejo/**


cacheControl

Este middleware se encarga de establecer el cache control en las respuestas de Astro. La idea es tener dos tipos de cache:

  • Cache-Control: max-age=0 por defecto; por defecto (Paginas que no son estáticas como las de blog, productos, etc.)
  • Cache-Control: max-age=31536000 y immutable para rutas en options (Paginas estáticas como las de landing, etc. y/o archivos estáticos)

Opciones

| Opción | Tipo | Por defecto | Descripción | |--------|------|-------------|-------------| | longCacheRoutes | string[] | [] | Patrones de rutas que recibirán cache de larga duración (max-age=31536000, immutable) (soporta glob con micromatch) |

El resto de rutas reciben public, max-age=0, must-revalidate por defecto.

Ejemplo

import { cacheControl } from '@existo/middlewares';

app.use(cacheControl({
  longCacheRoutes: ['/_astro/**', '/fonts/**'],
}));

/** 
* En este caso las rutas que coincidan con el patrón /_astro/** y /fonts/** recibirán cache de larga duración
* El resto de rutas reciben `public, max-age=0, must-revalidate` por defecto.
*/

notFound

Este middleware se encarga de manejar los errores 404 de Astro.

Parámetros

| Parámetro | Tipo | Por defecto | Descripción | |-----------|------|-------------|-------------|
| astroHandler | Function | - | El handler de Astro (primer argumento posicional) (Necesario) | | options.redirectOn404 | boolean | false | Si es true, hace un redirect a /404; si es false (por defecto), hace un rewrite interno sirviendo la página /404 de Astro |

Ejemplo

import { notFound } from '@existo/middlewares';

app.use(notFound(astroHandler));


/**
* En este caso se usará el rewrite interno para servir la página /404 de Astro por defecto
* Si se desea hacer un redirect a `/404` se debe pasar el parametro `redirectOn404: true`
*/

routeAnouncer

Este middleware se encarga de anunciar las rutas a nivel de Express globalmente. Sirve para anunciar las rutas a nivel de Express globalmente (Imprime un log en consola).

Opciones

| Opción | Tipo | Por defecto | Descripción | |--------|------|-------------|-------------| | announcedPaths | string[] | [] | Patrones de rutas a anunciar (soporta glob con micromatch) |

Ejemplo

import { routeAnouncer } from '@existo/middlewares';

app.use(routeAnouncer({
  announcedPaths: ['/api/**'],
}));

/**
* En este caso se anunciarán las rutas que coincidan con el patrón /api/**
* Esto aplica para todos los métodos HTTP (GET, POST, PUT, DELETE, etc.)
*/