Skip to main content

Crate runlight

Crate runlight 

Source
Expand description

Runlight: privacy friendly web analytics that lives inside your app.

This crate is the Rust version of Runlight, a port of the TypeScript SDK that answers every request the way it does and uses the same tables, so either one can read the other’s database.

Re-exports§

pub use routes::Routes;
pub use routes::RoutesOptions;
pub use routes::TokenOption;
pub use runlight::AppMailer;
pub use runlight::AppSend;
pub use runlight::Runlight;
pub use runlight::RunlightOptions;
pub use runlight::SiteOptions;
pub use runlight::TrustProxy;

Modules§

accounts
Accounts: who may sign in, two-factor, invites, the throttle on sign-in tries, and the pages they use.
adapters
The routes as a tower Service, for hyper, axum, and most Rust HTTP stacks (node.ts’s adapter, for Rust): the request read into a runlight::http::Request, with its body capped, and the answer written back as an http::Response.
assets
The dashboard, its locales and map, the tracker, and the element picker: the TypeScript SDK’s built files, copied into assets/ by scripts/rust-assets.mts, so this crate serves the very same bytes.
assistant
The dashboard’s assistant: questions about the stats, answered by a model the owner chooses, through the same read-only tools as the MCP server. The model runs on the server, so the key never reaches a browser, and each tool reads the API with the asking person’s own access.
brand
The Runlight mark.
connect
Connecting another Runlight to this one (a hub) without copying a token: this server registers itself with the install’s OAuth server, sends the owner to that install’s consent page, and on the way back swaps the code for a manage token, limited there to the one site the owner picked.
data
Data every implementation reads the same: known traffic sources and AI agents.
funnels
Funnels: steps a visit is expected to take in order, checked as the dashboard sends them.
geo
Where a visitor is, from the headers a hosting platform adds or a lookup of the app’s choosing. Only the country, region, and city are kept.
goals
Goals: what is worth counting, checked as the dashboard sends them, and the click rules the tracker applies.
hash
Hashes and random ids.
http
The Fetch API’s types, as the routes and everything that calls out use them: Request, Response, Headers, URL, URLSearchParams, and an injected fetch.
icon
A site’s icon, for the dashboard header: the best icon its home page links to, or /favicon.ico. Fetched from the site’s own configured origin (never from request input), cached in memory for a day.
importers
Imports from other tools: short links with their clicks from other shorteners, and visit history from Umami or a CSV file (importers/index.ts).
intl
The pieces of JavaScript’s Intl the email reports use, for the dashboard’s languages (en, de, es, fr, and pt), written out so they read as Node’s do: Intl.NumberFormat for counts, percents, one decimal place, and money, Intl.DateTimeFormat for a month and year or a short day, and Intl.DisplayNames for region names. Region names and each currency’s symbol come from assets/intl.json, which scripts/rust-intl.mts writes from Node’s own ICU.
journeys
Journeys: the paths visits take through a site, page by page. Each visit’s pages are read in order, a page seen twice in a row (a refresh) counts once, and the path is cut to a number of steps, from a start page and to an end page when those are chosen. The answer lines the paths up in columns, one per step, with the flows between them.
js
What the port needs of JavaScript’s own behaviour, so that every value the SDK writes, compares, or counts is written, compared, and counted the same way here: numbers as Number.prototype.toString prints them, JSON.stringify and JSON.parse (objects keep JavaScript’s key order), string lengths and cuts in UTF-16 code units, the characters \s matches, Date’s calendar arithmetic, and how String(), Number(), and truthiness read a JSON value.
limit
The tracker’s rate limit, and turns taken one at a time per key.
links
Short links: create, change, delete, and import, with the rules every route shares.
mail
Mail: the services Runlight sends reports through (Amazon SES, SMTP, the HTTP ones, and a webhook), and the sealing of the keys kept for them.
mcp
The MCP server at {base}/mcp: Streamable HTTP without sessions or a stream, JSON-RPC in and JSON out. Every tool is a read of the HTTP API, made with the caller’s own credentials, so the MCP server can see exactly what the token can and nothing more.
messages
The dashboard’s translations, for text the server writes (email reports). Same keys, same placeholders, so every language stays in one place.
mmdb
A reader for MaxMind DB files (the MMDB format that MaxMind’s GeoLite2 and DB-IP’s free databases use), so location needs no other crate. It answers what the TypeScript server’s mmdb-lib answers: the record for an address as a JSON value, or None when the address is not in the database.
oauth
OAuth for the MCP server, so apps that connect only through OAuth (the Claude and ChatGPT web connectors) can reach it. Runlight is both the resource and the authorization server:
payload
What the tracker sends, after validation. Anything malformed is dropped.
query
Report queries: which dimensions exist, where each lives, and how filters are read from a URL. Shared by every store.
reports
Email reports: the period one covers, and the subject, HTML, and text of one site’s report in a language.
routes
The dashboard, its HTTP API, the tracker endpoint, and the pages around them (routes.ts), framework-free: Routes::handle(Request) -> Response.
runlight
The Runlight: sites, the tracker’s hits, short links, AI agent fetches, and the scheduled upkeep (runlight.ts).
safefetch
Fetches from addresses that other people’s input names, such as the icon links on a site’s home page or a link domain, and only from the public internet. Only https is fetched, never a private, loopback, link-local, or metadata address, and redirects are followed by hand under the same rules. The name is resolved and every address it gives is checked before each hop, and the request is pinned to the checked addresses (the Fetcher’s resolve), so a name that answers differently a moment later gets nowhere.
sources
Where a visit came from: the page’s own tags, the referrer, and the channel they add up to.
store
Runlight’s tables: the database driver a store needs (Db), the rows it keeps, and SqlStore, the same tables and statements as the TypeScript SDK’s store on SQLite, Postgres, and MySQL or MariaDB. The drivers over sqlx are the runlight-sqlx crate.
time
Dates in a site’s timezone. Ranges are computed here as epoch milliseconds so the database only ever compares integers.
ua
User agents: AI agents, bots, and the browser, system, and device a person uses.
version
The SDK’s version and the HTTP API’s, as the TypeScript SDK’s version.ts has them.
zip
A ZIP file of text files, stored without compression, and CSV rows.

Macros§

arr
Builds a JSON array: arr![1, "two"].
obj
Builds a JSON object in the order its keys are written, as a JavaScript object literal is: obj! { "ok" => true, "count" => 3 }.
params
Builds a parameter list: params![site, from, to].

Enums§

Error
An error from Runlight: a database that failed, or something refused with a code the dashboard says in its own words.

Type Aliases§

BoxError
Any error, boxed.
BoxFuture
A boxed future that can be sent between threads, as the crate’s traits return.