Toda la documentación

Empezar

  1. 01Primeros pasos
  2. 02Instalación
  3. 03Seguimiento

Funciones

  1. 04El panel
  2. 05Objetivos
  3. 06Enlaces cortos
  4. 07Fuentes y agentes de IA
  5. 08Informes por email
  6. 09Comprobación programada
  7. 10Pregunta a tu IA

Referencia

  1. 11Configuración
  2. 12API HTTP

Plataformas

  1. 13Servidor independiente
  2. 14PHP
  3. 15WordPress
  4. 16Drupal
  5. 17Craft CMS
  6. 18Python
  7. 19Rails
  8. 20Ruby
  9. 21Go
  10. 22Java
  11. 23.NET
  12. 24Elixir
  13. 25Rust

Confianza

  1. 26Privacidad

Referencia

Configuración

Esta página trata todas las opciones de runlight() y routes(), incluidos los almacenes y los sitios.

ts

import { runlight } from "@runlight/sdk";

export const rl = runlight({ store, site, /* ...options */ });
export const routes = rl.routes({ /* ...route options */ });

Esta página usa los nombres de la biblioteca de TypeScript. Todos los demás lenguajes aceptan las mismas opciones, escritas como ese lenguaje escribe los nombres, como muestra su página, de PHP a Rust.

Almacenes

Runlight guarda todo en unas pocas tablas con el prefijo rl_, que se crean la primera vez que se usan y se actualizan in situ. Cada almacén acepta una opción prefix para usar en lugar de rl_, como wp_rl_, para que dos aplicaciones que comparten una base de datos tengan cada una sus propias tablas. Admite hasta 32 letras, dígitos y guiones bajos y no empieza por un dígito, y tables() de un almacén lista sus tablas por nombre, para una aplicación que quiera quitar Runlight.

SQLite

ts

import { sqlite } from "@runlight/sdk/sqlite";

sqlite({ path: "./data/runlight.db" });

SQLite necesita better-sqlite3 y es adecuado para un solo servidor, donde el archivo puede estar junto a la base de datos de tu aplicación. En un hosting serverless sin disco persistente, usa Postgres. Un archivo que crea Runlight solo lo pueden leer y escribir su propietario y su grupo (0660), así que una tarea programada que se ejecute como otro usuario del mismo grupo también puede usarlo.

Postgres

ts

import { postgres } from "@runlight/sdk/postgres";

postgres({ url: process.env.DATABASE_URL });

Postgres necesita pg. Pasa url, o pasa pool para compartir un pool que tu aplicación ya tenga (Runlight nunca cierra un pool que no creó). Un pool necesita al menos 2 conexiones. Cuando Runlight crea el pool, max fija sus conexiones y por defecto es 10, una petición espera como mucho 10 segundos a que quede una libre (un hit del tracker lo intenta dos veces más antes de descartarse), y statementTimeout detiene cualquier consulta tras ese número de milisegundos, 120000 por defecto (0 lo desactiva). Si varios procesos arrancan a la vez, las tablas se siguen creando una sola vez. Un proceso espera como mucho 30 segundos a otro que esté creando o actualizando las tablas, y después una petición responde 503 con el código tables_busy, y un hit del tracker espera como mucho 10 segundos y después se descarta.

MySQL y MariaDB

ts

import { mysql } from "@runlight/sdk/mysql";

mysql({ url: process.env.DATABASE_URL });

Este almacén necesita mysql2 y funciona con MySQL 8.0.20 o posterior y MariaDB 11.4 o posterior. Pasa una URL mysql:// o mariadb:// como url, o pasa pool para compartir un pool de mysql2/promise que tu aplicación ya tenga (Runlight nunca cierra un pool que no creó). Un pool necesita al menos 2 conexiones. Cuando Runlight crea el pool, max fija sus conexiones y por defecto es 10, una petición espera como mucho 10 segundos a que quede una libre (un hit del tracker lo intenta dos veces más antes de descartarse), y statementTimeout detiene cualquier consulta tras ese número de milisegundos, 120000 por defecto (0 lo desactiva). En MySQL ese límite cubre las lecturas, y en MariaDB cubre todas las sentencias. Si varios procesos arrancan a la vez, las tablas se siguen creando una sola vez. Un proceso espera como mucho 30 segundos a otro que esté creando o actualizando las tablas, y después una petición responde 503 con el código tables_busy, y un hit del tracker espera como mucho 10 segundos y después se descarta.

Las tablas usan utf8mb4 con la intercalación utf8mb4_0900_bin. El texto se compara y se ordena por punto de código, conservando mayúsculas y espacios finales, así que cada informe se lee igual que en SQLite o Postgres.

libSQL y Turso

ts

import { libsql } from "@runlight/sdk/libsql";
import { createClient } from "@libsql/client"; // or "@libsql/client/web" on the edge

libsql({ client: createClient({ url: process.env.TURSO_URL, authToken: process.env.TURSO_TOKEN }) });

Este almacén necesita @libsql/client. Turso por HTTP funciona en cualquier lugar donde funcione fetch, incluidos Vercel Edge y Deno Deploy, y una URL file: apunta a un archivo SQLite local.

Cloudflare D1

ts

import { d1 } from "@runlight/sdk/d1";

d1({ database: env.DB });

Pasa el binding de D1 desde el entorno de tu Worker. D1 no tiene transacciones interactivas, así que una importación de enlaces escribe cada enlace por separado; si una falla a medias, al ejecutar de nuevo la importación se omiten los enlaces ya escritos.

Bun

ts

import { bunSqlite } from "@runlight/sdk/bun";

bunSqlite({ path: "./data/runlight.db" });

Este almacén usa el SQLite integrado de Bun, para aplicaciones en Bun, donde better-sqlite3 no se carga.

Opciones de runlight()

Opción Por defecto Qué hace
store (obligatoria) Dónde viven las cifras, uno de sqlite, postgres, mysql, libsql, d1 o bunSqlite.
site {} El sitio que cuenta esta instalación.
sites Varios sitios en una instalación, cada uno con sus nombres de host, en lugar de site.
geo Tu propia búsqueda de ubicación, para hostings que no envían cabeceras de ubicación.
trustProxy true Lee la dirección del visitante de las cabeceras del proxy.
linkPath "/go" Dónde viven los enlaces cortos en el dominio propio de tu aplicación.
rateLimit 120 Peticiones al tracker permitidas desde una dirección cada minuto, o false o 0 para no tener límite.
mail El servicio de correo para los informes por email, definido en el código, o el sistema de envío propio de tu aplicación, que un servicio guardado en el panel puede reemplazar.
mailServices todos los servicios Los servicios de correo que ofrece Ajustes, por id, como todos menos smtp. Guardar otro se rechaza con el código mail_service, y un servicio guardado antes que no esté en la lista cuenta como ninguno, así que los envíos vuelven al sistema propio de la aplicación.
managedSites false Guarda los sitios en la base de datos y los gestiona desde el panel, como hace el servidor independiente, en lugar de site y sites.
secret RUNLIGHT_SECRET, y si no RUNLIGHT_TOKEN Cifra las claves guardadas en la base de datos, para el servicio de correo, el asistente de IA y las instalaciones conectadas.

Sitios

Campo Por defecto Qué hace
id "default" para el primer sitio Id estable que se guarda con cada fila, hecho de letras, dígitos, puntos, guiones y guiones bajos.
name el primer nombre de host Se muestra en el panel y se puede editar en Ajustes.
hostnames [] (cualquiera) Qué nombres de host cuentan para este sitio, sin tener en cuenta www.. Con varios sitios, cada uno necesita al menos uno.
timezone "UTC" Zona horaria IANA para los días, las semanas y las horas del panel, como "America/Toronto", y se puede editar en Ajustes.

Una visita desde un nombre de host que ningún sitio reclama se ignora, así que una copia de staging de tu sitio no cuenta a menos que añadas su nombre de host.

Límite de peticiones

Cada proceso cuenta las peticiones al tracker por dirección de visitante durante un minuto y descarta en silencio las demás, para que un script no pueda inundar un sitio con visitas inventadas. Un visitante real envía unas pocas peticiones por minuto, muy por debajo del valor predeterminado de 120. La cuenta vive en memoria bajo una dirección en forma de hash y se borra cada minuto, así que ninguna dirección se guarda nunca. En hostings que ejecutan muchas copias efímeras de tu aplicación, como Cloudflare Workers, cada copia cuenta por su cuenta, así que allí el límite es más laxo.

Ubicación

El país, la región y la ciudad salen de las cabeceras de tu hosting en Vercel, Cloudflare y Netlify, sin configurar nada. En otros lugares, pasa geo, una función que convierte una dirección IP en una ubicación. Este ejemplo usa un archivo MMDB.

ts

runlight({
  store,
  geo: async (ip) => {
    const found = reader.get(ip); // your MMDB reader
    return found ? { country: found.country?.iso_code, city: found.city?.names?.en } : null;
  },
});

La dirección se descarta después de la búsqueda, así que solo se guarda el lugar.

Opciones de routes()

Opción Por defecto Qué hace
basePath "/runlight" Dónde se montan las rutas, con el script en {basePath}/s.js.
token RUNLIGHT_TOKEN Protege el panel y la API. Envíalo como Authorization: Bearer <token>, o abre el panel una vez con ?token= para obtener una cookie. null lo deja todo abierto, por ejemplo detrás de tu propia autenticación.
accounts false Cuentas de inicio de sesión para el panel, con invitaciones por rol. Consulta Cuentas más abajo.
authorize Tu propia comprobación, en lugar de un token. Devuelve true para acceso total, "member" para alguien que puede cambiarlo todo salvo el servicio de correo, los ajustes del asistente y eliminar un sitio, "read" para alguien que solo puede leer, o false, desde una función o una promesa.
cronSecret CRON_SECRET Un segundo secreto que la comprobación programada acepta además del token.
origin La dirección pública de tu aplicación, como https://example.com. Un dominio de enlaces nunca puede ser su host, y los enlaces de los informes por email apuntan a ella, sea cual sea la cabecera Host que indique una petición. Sin ella, se usa el host de la propia petición, y un hub conectado no puede añadir dominios de enlaces ni informes por email.
ownHosts Una función que devuelve más nombres en los que responde tu aplicación, como ["app.example.com"], que tampoco pueden convertirse nunca en dominios de enlaces.
signIn Tu propia página de inicio de sesión. Una aplicación que se conecta por OAuth envía allí a un propietario sin sesión con ?next=, y el panel enlaza a ella cuando termina una sesión.
signOut Un enlace para cerrar sesión, que se muestra en el pie del panel.
geoCredit false Menciona a DB-IP en el pie del panel, como piden sus datos de ubicación gratuitos.
cms El CMS que añade el script a cada página, como "WordPress", cuando Runlight funciona dentro de uno. El panel se abre entonces con sus cifras incluso antes de la primera visita, Ajustes, Instalación indica que el CMS añade el script, y las páginas del mismo origen, como la administración del CMS, pueden mostrar el panel en un marco. Los plugins de WordPress, Drupal y Craft la definen.
observeKey RUNLIGHT_OBSERVE_KEY Una clave para toda la instalación que un sitio de WordPress, Drupal o Craft puede usar para informar de los accesos de agentes de IA a POST /api/observe para cualquier sitio. Cada sitio tiene además su propia clave de agentes, que se muestra en Ajustes, Instalación, que solo informa para ese sitio y es la mejor opción.

Las opciones accountOf y tokenMade conectan las rutas con las cuentas propias del servidor independiente y son internas de él.

Sin token, el panel y la API responden 503 hasta que definas uno, salvo que NODE_ENV sea development. Recoger visitas, el script, los enlaces cortos, los enlaces para compartir y los enlaces para darse de baja nunca necesitan el token.

Cuentas

Activa las cuentas para que varias personas puedan iniciar sesión en el panel, cada una con su propio correo, contraseña y rol, igual que en el servidor independiente.

ts

export const { GET, POST, PUT, PATCH, DELETE } = rl.routes({ accounts: true });

El panel pide entonces a todos que inicien sesión en /runlight/login. Para crear la primera cuenta, abre /runlight/setup y escribe tu RUNLIGHT_TOKEN junto con tu correo y tu contraseña, de modo que solo pueda hacerlo quien gestiona la aplicación. Esa cuenta es el propietario. En desarrollo sin token, o con token: null, que lo deja todo abierto, la primera cuenta no necesita token, así que créala antes de que nadie más pueda llegar a la página.

El propietario y los administradores invitan a más personas en Ajustes, Personas, como administrador, miembro o lector, y la invitación sale por correo cuando hay un servicio de correo configurado. Cualquiera puede activar el inicio de sesión en dos pasos en Cuenta. El token sigue funcionando como bearer token para los scripts.

Las sesiones se firman con RUNLIGHT_SECRET, o con el token cuando no está definido, así que mantenlo igual entre reinicios y despliegues. Las contraseñas se guardan como hash con scrypt cuando el runtime lo tiene, como Node, Bun y Deno, y con PBKDF2 en runtimes edge como Cloudflare Workers.

Si alguien olvida su contraseña, el propietario o un administrador puede quitarlo e invitarlo de nuevo. Si el propietario olvida la suya, dale a la cuenta una nueva desde un script que use tu Runlight.

ts

import { Accounts } from "@runlight/sdk";
import { rl } from "./lib/runlight";

const accounts = new Accounts(rl.store, process.env.RUNLIGHT_SECRET ?? process.env.RUNLIGHT_TOKEN!);
const user = await accounts.setPassword("you@example.com", "a new long password", Date.now());
await accounts.disableTwoFactor(user.id);

Variables de entorno

Variable Se usa para
RUNLIGHT_TOKEN El token del panel y de la API.
RUNLIGHT_SECRET Cifrar las claves guardadas del correo, del asistente de IA y de las instalaciones conectadas (si no está, se usa el token).
CRON_SECRET Llamar a la comprobación programada.
RUNLIGHT_OBSERVE_KEY Los plugins de CMS que informan de los accesos de agentes de IA.