Runtime APIs
Use built-in runtime APIs inside actions to perform side effects such as logging and outbound HTTP requests.
Overview
Titan provides a small, intentional set of runtime APIs that are available inside actions.
These APIs allow actions to perform controlled side effects while preserving Titan’s performance, determinism, and Rust-backed execution model.
Runtime APIs are exposed through the global t object.
Runtime APIs are not available in routes.
They are designed exclusively for use inside actions.
t.log() — Structured logging
t.log() is Titan’s built-in logging API.
It allows actions to emit logs that are collected and handled by the native Rust server.
t.log("User login started")Logging structured data
t.log() accepts any serializable JavaScript value.
t.log({
action: "login",
userId: req.params.id,
})- Objects are logged as structured data
- Logs are serialized safely
- No
console.logdependency
Why t.log exists
- Logs are routed through Rust (not stdout hacks)
- Consistent formatting across environments
- Safe to use in production
- Zero Node.js dependency
Use t.log() instead of console.log() in all actions.
t.fetch() — Outbound HTTP requests
t.fetch() allows actions to make outbound HTTP requests.
It follows a familiar fetch-style API while executing through Titan’s Rust networking layer.
const res = t.fetch("https://api.example.com/users")Basic usage
export default function example(req) {
const res = t.fetch("https://api.example.com/data")
return res
}- Executes via Rust-native HTTP client
- No Node.js networking stack
- Predictable performance
Sending a JSON request
t.fetch("https://api.example.com/login", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: {
email: req.body.email,
},
})- Objects passed as
bodyare serialized automatically - Headers are optional
- No manual JSON handling required
Reading the response
t.fetch() returns a parsed response object.
const res = t.fetch("https://api.example.com/user/1")
return {
status: res.status,
data: res.body,
}res.status→ HTTP status coderes.body→ parsed response body- Errors propagate naturally to the caller
Error behavior
If a request fails:
- Network errors throw immediately
- Non-2xx responses are still returned
- You control how failures are handled
const res = t.fetch(url)
if (res.status !== 200) {
t.log("Upstream service failed")
}t.jwt — JSON Web Tokens
t.jwt provides Rust-backed JSON Web Token (JWT) signing and verification.
All cryptographic operations are executed natively in Rust.
There is no Node.js JWT library, no JS crypto, and no async behavior.
t.jwt.sign()
Creates and signs a JWT.
const token = t.jwt.sign(
{ userId: 1, email: "admin@ez.app" },
processe.env.JWT_SECRET,
{ expiresIn: "1m" }
)Parameters
- payload — Object to encode into the token
- secret — HMAC secret key
- options (optional)
Supported expiresIn formats
| Value | Meaning |
|---|---|
60 | 60 seconds |
"1m" | 1 minute |
"1h" | 1 hour |
"30d" | 30 days |
Expiration is converted into a JWT exp claim inside Rust.
If
expiresInis omitted, the token does not expire.
t.jwt.verify()
Verifies a JWT and returns its decoded payload.
const payload = t.jwt.verify(token, processe.env.JWT_SECRET)Behavior
- Signature is validated
exp(expiration) is enforced- Expired tokens throw immediately
- Time comparison is done in Rust
try {
const payload = t.jwt.verify(token, processe.env.JWT_SECRET)
} catch {
// invalid or expired token
}jwt.io may decode expired tokens, but Titan correctly rejects them.
Error log on expired token
t.password — Password hashing
t.password provides secure password hashing and verification using Rust-native cryptography.
Passwords are never processed by JavaScript libraries.
t.password.hash()
Hashes a plaintext password.
const hash = t.password.hash("admin123")- Uses a secure adaptive hashing algorithm
- Safe to store in a database
- Deterministic and production-ready
t.password.verify()
Verifies a password against a stored hash.
const ok = t.password.verify("admin123", hash)- Returns
trueif the password matches - Returns
falseotherwise - No timing-sensitive logic in JavaScript
Security guarantees
- No plaintext passwords stored
- No JS-side cryptography
- No implicit expiration handling
- All verification enforced in Rust
Where Runtime APIs can be used
| Location | Allowed |
|---|---|
| Routes | ❌ No |
| Actions | ✅ Yes |
| Build time | ❌ No |
Runtime APIs execute only at request time.
Design philosophy
Titan’s runtime APIs are:
- Minimal by design
- Explicitly scoped
- Rust-backed
- Production-safe
There is no hidden magic and no implicit globals beyond t
Mental model
Routes define structure Actions define behavior Runtime APIs perform side effects Rust executes everything
This keeps Titan applications predictable, fast, and maintainable.
Example Actions
{
"email": "admin@ez.app",
"password": "mypassword123"
}Login to the account
export function login(req) {
const { email, password } = req.body || {}
if (!email || !password) {
return {
status: 400,
json: { error: "Email and password required" }
}
}
// ⚠️ Mock DB
const user = {
id: 1,
email: "admin@ez.app",
passwordHash: "$2b$12$MJwttSgptEQJCkPJ.J8mce1xxtmxlJPCsISvc1WEzR6mqdD/ZJyOC"
}
if (email !== user.email) {
return {
status: 401,
json: { error: "Invalid credentials" }
}
}
const ok = t.password.verify(password, user.passwordHash)
if (!ok) {
return {
status: 401,
json: { error: "Invalid credentials" }
}
}
const token = t.jwt.sign(
{ userId: user.id, email: user.email },
processe.env.JWT_SECRET,
{ expiresIn: "1m" } // 👈 1 minute token
)
return {
status: 200,
json: {
token,
expiresIn: "1 minute"
}
}
}Register a account
export function register(req) {
const { email, password } = req.body || {}
if (!email || !password) {
return {
status: 400,
json: { error: "Email and password are required" }
}
}
// ⚠️ Mock DB
// IMPORTANT: store passwordHash, never password
const passwordHash = t.password.hash(password)
// pretend we saved this
const user = {
id: 1,
email,
passwordHash
}
return {
status: 201,
json: {
message: "Account created",
user: {
id: user.id,
email: user.email,
passwordHash: user.passwordHash
}
}
}
}Get the user details
export function getUser(req) {
const { token } = req.body || {}
const payload = t.jwt.verify(token, processe.env.JWT_SECRET)
return {
status: 200,
json: {
user: payload
}
}
}