Atlas API Reference#
@atlas/billing#
createBilling({ secretKey, webhookSecret, prices, store, accountMetadataKey?, apiVersion? }) → Billing
.checkout({ accountId, plan, successUrl, cancelUrl }) → Promise<{ url }>
.portal(accountId, returnUrl) → Promise<{ url }>
.subscription(accountId) → Promise<Subscription | null> persisted state
.sync(accountId) → Promise<Subscription | null> fetch current Stripe state and persist
.webhook(rawBody, signature) → Promise<{ received: true, duplicate?, ignored? }>
verifySignature(rawBody, signature, secret, { now?, tolerance? }) → Promise<boolean>
isBillingError(error) → error is BillingError
BillingStore: get(id), findByCustomer(id), save(next, expectedRevision), hasEvent(id), recordEvent(id)
App-owned authorization and storage. save must atomically compare revisions, persist the
complete next account and any entitlement projection, and return false on conflict.
Persist checkout attempts and idempotent event receipts. Each account owns a dedicated
customer with at most one nonterminal subscription. See packages/billing/AGENTS.md.
@atlas/config#
env(name, opts?) → EnvRef<T> opts: { parse: (s)=>T, default: string }
defineConfig(schema) → Readonly<T> resolves all EnvRef values, freezes
@atlas/db#
from(schema, alias?) → Chainable<RowOf<schema>> typed Ecto-style chain
from(table: string, alias?) → Chainable<any> dynamic / cross-table chain
.select(...keys) narrows row to Pick<Row, K>
.where(cb) .join(t, on) .leftJoin(t, on) .innerJoin(t, on)
.orderBy(col, dir?, nulls?) .groupBy(...cols) .having(cb)
.limit(n) .offset(n) .distinct(...cols)
.insert(data) .insertMany(data[]) .update(data) .del() .truncate(cascade?)
.returning(...keys) .onConflict(spec) .cte(name, sub) .recursiveCte(name, sub)
.toSql(dialect?) → SqlResult<Selected>
raw(sql, ...values) → Fragment
defineSchema(table, columns) → Schema<T>
column.serial() → number .text() → string .integer() → number
.bigint() → bigint .real() → number .boolean() → boolean
.timestamp() → Date .json<T>() → T .uuid() → string
modifiers: .primaryKey() .unique() .nullable() (widens to T|null)
.default(val) .defaultRaw(sql) .ref(table, col)
RowOf<typeof schema> extract row TS type
changeset(schema, { cast, required?, validate? }) → (data) => ChangesetResult
connect({ driver, path|url, pool? }) → Connection
Connection: .execute<Row>(q) → Row[]
.one<Row>(q) → Row | null
.all<Row>(q) → Row[]
.transaction(fn) .close()
row type is inferred from the chain when from(schema) is used
@atlas/migrate#
migrate.create(dir, name) creates timestamped up.sql/down.sql
migrate.up(db, dir) runs pending migrations
migrate.down(db, dir) rolls back last migration
migrate.status(db, dir) lists migration status
migrate.plan(db, schemas) → DiffPlan compute up/down SQL (read-only)
migrate.diff(db, schemas, { name?, dir? }) → DiffWriteResult
introspect live DB, write a new migration
folder with up/down SQL — { noop: true }
when in sync. Type/nullability mismatches
emit `-- ALTER` comments for review.
@atlas/server#
createConn(req, params?) → Conn immutable connection from Request
assign(conn, data) → Conn merge into conn.assigns
putHeader(conn, key, val) → Conn add response header
halt(conn, status, body?) → Conn stop pipeline
setStatus(conn, status) → Conn
pipe(fn) → PipeFn type-inference wrapper
pipeline(...pipes)(handler) → PipeFn compose pipes, halt short-circuits
get|post|put|patch|del|head|options(path, handler) → Route
router(...routes) → fetch handler
serve({ port, routes, hostname?, websocket? })
json(conn, status, data) → Conn
text(conn, status, body) → Conn
redirect(conn, location, status?) → Conn
stream(conn, status, readable) → Conn
parseJson | parseForm | parseMultipart built-in parser pipes
onError(handler) → error pipe
createAdapter(name, start) → ServerAdapter
compose(adapters) → ComposedServer
route(method, path, schemas, handler) → Route validated, typed route
getR | postR | putR | patchR | delR(path, schemas, handler) → Route
schemas: { params?, body?, query?, before?, assigns? }
- params/body/query: Validator<T> = (input) => T | { parse(input): T }
(Zod, plain functions, or any Standard-Schema-shape qualify)
- before: PipeFn[] (run ahead of validation; e.g., requireAuth)
- assigns: phantom — `{} as MyClaims` types c.assigns for the handler
body schema auto-parses JSON; rejects non-application/json content-types.
validation failures → unprocessable("Invalid <where>", VALIDATION_FAILED)
httpError(status, message, { code?, details?, headers? }) → HttpError
isHttpError(value) → bool type guard
haltWith(conn, error) → Conn halt with HttpError
notFound | unauthorized | forbidden | badRequest | conflict | gone |
unprocessable | tooManyRequests | methodNotAllowed | internal |
serviceUnavailable(message?, opts?) → HttpError
router catches `throw httpError(...)` and renders { error, code?, details? }
@atlas/edge#
defineEdge(config) → { ...config, listen() → Promise<RunningEdge> }
runEdge(config) → Promise<RunningEdge> { mode: "tls"|"plain", stop() }
proxy(upstream, { preserveHost? }) → EdgeHandler reverse proxy with X-Forwarded-*
forward(req, options, ctx) → Promise<Response> low-level proxy primitive
files({ root, index?, stripPrefix? }) → EdgeHandler static file serving via Bun.file
compressResponse(res, accept, allow) → Response apply gzip/zstd
matchHost(host, pattern) → bool literal or "*.x.com"
matchRoute(req, url, matcher?) → bool path (regex|string|*) + method
isLocalHost(host) → bool localhost / 127.0.0.1 / ::1 / *.localhost
provisionCertificate({ directoryUrl, accountKey, contactEmail, hosts, challenge }) → { certPem, keyPem }
generateKeyPair() → AcmeKeyPair ECDSA P-256 via Web Crypto
importKeyPair(jwk) | jwkThumbprint(jwk)
LETSENCRYPT_PROD | LETSENCRYPT_STAGING directory URLs
issueCert({ directoryUrl, contactEmail, hosts, store, challenge }) → CertRecord
loadOrCreateAccount(store) → AcmeKeyPair
fileStore(root) | memoryStore() → CertStore .load .save .loadAccountJwk .saveAccountJwk
certKey(hosts) → string stable map key for a host list
createRenewalScheduler(onRenew) → { schedule, cancel, stop }
renewAt(record) → number unix ms; 30 days before expiry, clamped
EdgeConfig: { acme?, sites: Site[], insecure?, httpPort?, httpsPort? }
Site: { host, routes: Route[], compress?: ("gzip"|"zstd")[] }
Route: { match?: { path?, method? }, handler: (req, ctx) => Promise<Response> }
ForwardContext: { remoteIp, tls, host }
@atlas/server/ws#
ws(config) → { websocket, rooms, upgrade }
channel(name, handlers) → Channel
createRooms() → { join, leave, leaveAll, broadcast, members }
WsConn<T>: wrapped ws with auto-JSON send
@atlas/server/sse#
createSseChannel() → { broadcast, pipe, clients }
eventStream(conn, generator) → SSE response
SseClient: { id, send, close }
@atlas/auth#
hash(password) → Promise<string> Argon2id via Bun.password
verify(password, hashed) → Promise<bool>
token.sign(payload, secret, opts?) → Promise<string> opts: { expiresIn: seconds }
token.verify(jwt, secret) → Promise<TokenPayload>
createMemoryStore({ ttl? }) → SessionStore dev/testing session store; ttl seconds expires entries
signup({ db, table, fields, onSuccess }) → PipeFn
login({ db, table, identity, password, onSuccess }) → PipeFn
requireAuth({ secret }) → PipeFn reads Bearer token, sets conn.assigns.auth
passwordReset({ db, table, secret, transport, expiresIn? }) → PipeFn
@atlas/auth/social#
socialAuth({ secret, providers, cookie? }) → SocialAuth
SocialAuth: { providers,
authorize(name, { scopes?, returnTo?, extraParams? }?) → { url, cookie },
complete(name, conn) → { provider, tokens, profile, returnTo? },
start(name, opts?) → PipeFn, 302s + sets state cookie
callback(name, { onSuccess, onError? }) → PipeFn validates state, exchanges code, clears cookie }
Provider factories — each returns a `SocialProvider`:
google({ clientId, clientSecret, redirectUri, hostedDomain?, prompt? })
github({ clientId, clientSecret, redirectUri, allowSignup? })
apple({ clientId, teamId, keyId, privateKey, redirectUri, responseMode? })
mints ES256 client_secret JWT per exchange; default response_mode=form_post
microsoft({ clientId, clientSecret, redirectUri, tenant?, prompt? }) tenant defaults to "common"
facebook({ clientId, clientSecret, redirectUri, apiVersion?, profileFields? })
twitter({ clientId, clientSecret?, redirectUri, userFields? }) Basic auth for confidential clients
tiktok({ clientKey, clientSecret, redirectUri, userFields? }) uses `client_key`, comma-joined scopes, id is open_id
SocialProfile: { provider, id, email?, emailVerified?, name?, picture?, username?, raw }
TokenSet: { accessToken, tokenType?, expiresIn?, refreshToken?, idToken?, scope?, raw }
State + PKCE verifier live in a signed, HttpOnly, SameSite=lax cookie
(`_atlas_oauth_state`, 10 min TTL). Override via cookie: { name?, path?, secure?, sameSite? }.
@atlas/share#
shareUrl(channel, content) → string throws on unknown channel or missing url
share(content) → Record<ShareChannel, string> all eight URLs at once
listChannels() → { channel, label }[] ordered list with display labels
channels readonly ShareChannel[]
ShareChannel = "twitter" | "facebook" | "linkedin" | "reddit" | "whatsapp" | "telegram" | "sms" | "email"
ShareContent: { url, title?, text?, hashtags?, via?, phone?, to?, cc?, bcc? }
url required; unknown fields ignored per channel.
Provider re-exports (each is a `ShareProvider { channel, label, build }`):
twitter, facebook, linkedin, reddit, whatsapp, telegram, sms, email
shareEmail({ emailer, to, from?, replyTo?, sharerName?, product?, message?, content, brand?, accent? })
→ Promise<SendResult> dispatches a branded HTML email through @atlas/email
renderShareEmailMessage(opts) → { subject, html, text } pure preview/render
@atlas/email#
createEmailer({ apiKey?, from? }) → Emailer auto-picks Resend if both set, else console
createResendEmailer({ apiKey, from }) → Emailer
createConsoleEmailer() → Emailer dev fallback; logs and returns ok:true
Emailer: { enabled, send(msg) → Promise<SendResult> }
EmailMessage: { to, subject, html, text?, replyTo?, from? }
SendResult: { ok: true, id?, logged? } | { ok: false, error }
inviteEmail(opts) | passwordResetEmail(opts) → { subject, html, text }
layout({ title, body, brand?, footer?, accent? }) → string
escapeHtml(s) → string always wrap untrusted input
@atlas/oauth#
oauthRoutes(cfg, { basePath?, adminBasePath? }) → Route[] all OAuth endpoints
oauthAuthorizeRoutes(cfg, base) | oauthTokenRoutes | oauthRevokeRoutes
oauthDeviceRoutes | oauthDiscoveryRoutes | oauthClientRoutes(cfg, adminBase)
findClient(db, id) | verifyClientCredentials(db, id, secret)
sweepExpired(cfg) | sweepExpiredAuthCodes | sweepExpiredRefreshTokens | sweepExpiredDeviceCodes(cfg)
helpers: parseScope, formatScope, includesScopes, isAllowedRedirect,
verifyPkceS256, randomId, shortId, sha256, newUserCode, normalizeUserCode
constants: ACCESS_TOKEN_TTL_SECONDS, REFRESH_TOKEN_TTL_SECONDS,
AUTH_CODE_TTL_SECONDS, DEVICE_CODE_TTL_SECONDS, DEVICE_POLL_INTERVAL_SECONDS
types: OAuthConfig, OAuthUser, ClientRow, AuthCodeRow, RefreshTokenRow,
DeviceCodeRow, OAuthAuditEvent, RequestContext
@atlas/sso#
mountSso(cfg: SsoConfig) → readonly Route[] mount /login + /callback + /backchannel-logout
ensureSsoStateTable(db, table?) idempotent CREATE TABLE IF NOT EXISTS
sweepExpiredSsoState(db, table?) prune expired state rows (10m TTL)
clearDiscoveryCache() for tests / hot-reload
SsoConfig: { db, issuerUrl, clientId, clientSecret,
onAuthenticated(db, claims) → { localUserId, displayName? },
issueSession(conn, user, claims) → Conn,
redirectUri?, scopes?, basePath?, defaultPostLoginPath?, stateTable?,
findLocalUserBySub?(db, sub), invalidateSessions?(db, { sub, localUserId }) }
IdTokenClaims: { sub, iss, aud, email?, email_verified?, name?, preferred_username?, picture?, ... }
DiscoveryDoc: { issuer, authorization_endpoint, token_endpoint, jwks_uri, userinfo_endpoint?, end_session_endpoint? }
@atlas/security#
withSecurityHeaders(fetch, { dev?, csp?, disableCsp? }) → fetch HSTS/CSP/COOP/CORP + req.peerIp shim
developmentCsp | productionCsp string CSP presets
decideInline(mime, name, wantInline) → { contentType, disposition } safe-MIME allowlist for inline
createDbRateLimit({ db }) | createMemoryRateLimit() → RateLimit .check(bucket, max, windowSec) .reset(bucket) .sweep(olderThanSec)
clientIp(req, { trustedProxies? }) → string honors X-Forwarded-For only via trusted proxy
userAgent(req) → string | undefined
parseTrustedProxies(env) → string[]
createAuditLogger({ db }) → { log(event), ... } fire-and-forget; never throws
createSessionStore<U>({ db, secret, ttlSeconds }) → SessionStore DB-backed JWT sessions
.issue(user, ctx) .isActive(jti) .touch(jti) .revoke(jti, userId) .revokeAll(userId, keep?) .sweepExpired()
newJti() → string
generateSecret() → string TOTP base32 secret
totpAt(secret, epochSec) → string 6-digit code at time
verifyTotp(secret, code, { window? }) → bool window=1 accepts ±30s
otpauthUrl({ secret, account, issuer }) → string
generateBackupCodes(n?) → string[] store hashed
base32Encode(bytes) | base32Decode(str)
@atlas/storage#
createStore({ endpoint, bucket, region, accessKey, secretKey }) → Store
upload(store, { key, body, contentType }) → Promise
download(store, key) → Promise<Response>
list(store, prefix?) → Promise<ListResult>
remove(store, key) → Promise
presign(store, key, { expires?, method? }) → string
@atlas/cache#
createCache({ url }) → Cache Redis-backed
createMemoryCache() → Cache in-memory for dev
cached(cache, prefix, fn, { ttl? }) → cached function
invalidate(cache, prefix, ...args) → Promise
@atlas/request#
request(url, opts?) → Promise<Response> opts: { json, headers, method, body, retry, timeout (ms) }
createClient({ baseUrl, headers?, retry?, interceptors?, timeout? }) → Client
Client: .get .post .put .patch .del .request — all return Promise<Response>
withRetry(fn, { attempts?, delay?, backoff?, retryOn? })
github({ token }) | stripe({ key }) | openai({ key }) | resend({ key })
preconfigured clients — import from @atlas/request/providers
@atlas/cli#
cli(name, commands) run CLI with command definitions
command(name, { flags?, run }) define a command
flag(short, { type, default? }) define a flag
parseArgs(argv, flags) → ParsedArgs
foreman(procs) | parseProcfile(str) process manager
initCommand | addCommand | docsCommand built-in atlas commands
questions | applyDefaults | generateProject scaffolding
CLI surface:
atlas init [-y] [-n name] scaffold a new project
atlas add <pkg>... install @atlas/* packages
atlas dev foreman → Procfile
atlas mcp start MCP server
atlas docs [<pkg>|<doc>|<root>] print canonical documentation to stdout
@atlas/ui#
@atlas/ui/provider: AtlasProvider, AppShell
@atlas/ui/forms: createForm, TextField, SelectField, SubmitButton
@atlas/ui/table: createTable, TextColumn, DateColumn, ActionColumn
@atlas/ui/auth: LoginPage, SignupPage, ResetPasswordPage
@atlas/ui/storage: FileUpload, ImagePreview
@atlas/ui/nav: Sidebar, NavLink, Breadcrumb
@atlas/ui/cache: CacheInspector, CacheStatus
@atlas/ui/ai: ChatWindow, MessageBubble, PromptInput, AiSearch, GenerateButton
@atlas/admin#
admin({ db, models, basePath?, auth? }) → { mount, routes }
model({ schema, listFields?, searchFields?, filterFields?, relations?, actions?, bulkActions?, readOnly? }) → ModelConfig
Components: AdminApp, AdminSidebar, Dashboard, ModelList, Detail, Create, FilterBuilder, QueryBuilder, BulkBar
@atlas/mcp#
createContext(opts?) → AtlasMcpContext opts: { db?, cache?, routes?, config?, storage?, migrationsDir?, logBuffer? }
collectTools(ctx) → Tool[] tools auto-register from what's in ctx
createMcpServer(tools, ctx) → McpServer
defineTool({ name, description, inputSchema, handler }) → Tool
McpServer: .start() .stop()
Always-on tools (independent of context):
docs.list list package, guide, and root documentation sources
docs.read({ package?, doc?, root? }) read one canonical source; docs/agents.md is the grounding guide
@atlas/ai#
createProvider({ provider, key?, baseUrl? }) → AiProvider provider: "openai"|"anthropic"|"ollama"
createConversation(system?) → Conversation
addMessage(conv, msg) → Conversation
send(provider, conv, content, opts?) → { conversation, response }
userMessage|assistantMessage|systemMessage(content) → Message
toolMessage(toolCallId, content) → Message
chatStream: provider.chatStream(opts) → AsyncIterable
collectStream(stream) → ChatResponse
streamToSse(stream) → ReadableStream
parseSSE(text) → events
embed(provider, input) → number[][] input: string | string[]
cosineSimilarity(a, b) → number
createVectorStore() → { add, search, size }
generateJson<T>(provider, prompt, opts?) → T
tool(name, desc, parameters) → ToolDef
index(rag, id, text, metadata?) → Promise rag: { ai, store, topK? }
query(rag, question) → { answer, sources }
runAgent({ ai, system?, tools, maxIterations? }, prompt) → { response, messages, iterations }
withAi(provider) → PipeFn adds ai to conn.assigns
Dependency baseline#
Atlas 0.3 uses Zod 4, React 19.3, Mantine 9, and TanStack Table 9.
Table column helpers return TanStack v9 column definitions. Pass object or array
rows to createTable; its search, sorting, and pagination options are unchanged.