Builtins & Globals
Weld has no importable standard library — the useful primitives are built into the language. This page is the exhaustive reference: every builtin function, every builtin statement, and every builtin type/global the compiler recognises. Signatures are written in Weld type notation (T? optional, [T] list, [K: V] map, T! fallible).
Everything here is checked by the compiler: a wrong argument type or arity is a compile-time error, not a runtime surprise.
String functions
All string builtins are pure and total (they never fail).
| Signature | Returns | Description |
|---|---|---|
upper(s: string) -> string | uppercased copy | ASCII upper-case. |
lower(s: string) -> string | lowercased copy | ASCII lower-case. |
trim(s: string) -> string | trimmed copy | Strip leading and trailing ASCII whitespace. |
trimPrefix(s: string, prefix: string) -> string | s without prefix | If s starts with prefix, drop it; otherwise return s unchanged. |
contains(s: string, needle: string) -> bool | bool | Is needle a substring of s? |
startsWith(s: string, prefix: string) -> bool | bool | Does s begin with prefix? |
endsWith(s: string, suffix: string) -> bool | bool | Does s end with suffix? |
parseInt(s: string) -> int | int | Parse a base-10 integer (invalid input yields 0). |
route GET "/normalize/:raw" (raw: string) -> string {
let name = trim(lower(raw))
let tag = trimPrefix(name, "user-") # "user-ada" -> "ada"
respond "name={name} tag={tag} isuser={startsWith(name, "user-")} n={parseInt("42")}"
}For building strings, use + concatenation and {expr} interpolation — see Expressions & Control Flow. For string → enum, use the enum reinterpreter below.
Conversion functions
| Signature | Returns | Description |
|---|---|---|
str(x: int | float | bool | string | Enum) -> string | string | Render any primitive or enum as text. On an enum it yields the variant's string label. |
int(e: Enum) -> int | int | The enum variant's underlying number. (For string -> int, use parseInt.) |
hash(x: int | float | bool | string | Enum) -> int | int | A stable 64-bit hash (Wyhash). The building block for hash maps written in Weld. |
Enum(x: int | string) -> Enum | the enum | Enum reinterpreter — turn a number or string back into an enum value; an unknown input becomes the zero Unspecified variant. Enum is the name of any enum you declared. |
enum Role { Admin = 1 : "admin", User = 2 : "user" }
route GET "/role/:name" (name: string) -> string {
let r = Role(name) # string -> enum (unknown -> Unspecified)
respond "label={str(r)} number={int(r)} again={str(Role(int(r)))} hash={hash(r)}"
}See Enums & Sum Types for the full enum model.
List functions
[T] is a mutable list (a Zig slice). Indexing (xs[i]) is bounds-checked — an out-of-range index is a recoverable error that fails the request rather than crashing the server.
| Signature | Returns | Description |
|---|---|---|
len(xs: [T]) -> int | int | Number of elements. |
push(xs: [T], v: T) -> [T] | a new list | Append v, returning the grown list. push returns the result — assign it back: xs = push(xs, v). |
filled(n: int, v: T) -> [T] | [T] of length n | Preallocate a list of n copies of v. |
slice(xs: [T], start: int, end: int) -> [T] | [T] | The sub-range [start, end), clamped to bounds (a bad range yields an empty list, never a crash). |
pop(xs: [T]) -> [T] | [T] | The list without its last element; an empty list stays empty. |
concat(a: [T], b: [T]) -> [T] | [T] | The two lists joined; element types must match. |
reverse(xs: [T]) -> [T] | [T] | The list reversed. |
contains(xs: [T], v: T) -> bool | bool | Is v an element of xs? For primitive or enum element types (strings compared by value). |
sort(xs: [T]) -> [T] | [T] | The list sorted ascending. T must be int, float, or string. |
insert(xs: [T], i: int, v: T) -> [T] | [T] | A new list with v inserted at index i (clamped to [0, len]). |
removeAt(xs: [T], i: int) -> [T] | [T] | A new list without the element at index i (out-of-range: unchanged). |
map(xs: [T], f: x => U) -> [U] | [U] | Each element transformed by the closure f. |
filter(xs: [T], p: x => bool) -> [T] | [T] | The elements for which the predicate p is true. |
reduce(xs: [T], init: A, f: (acc, x) => A) -> A | A | Fold left: start from init, combine each element into the accumulator. |
All of these are also methods — xs.op(…) is the same as op(xs, …), and reads better when chained: xs.filter(x => x > 0).map(x => x * 2).sort(). The higher-order ops take closures: a one-parameter x => … for map/filter, and a two-parameter (acc, x) => … combiner for reduce.
route GET "/build/:n" (n: int) -> string {
var xs = filled(3, 0) # [0, 0, 0]
xs = push(xs, n) # [0, 0, 0, n]
xs = concat(xs, [1, 2]) # [0, 0, 0, n, 1, 2]
xs = slice(xs, 2, len(xs)) # drop the first two
xs = reverse(pop(xs)) # drop the last, then reverse
xs[0] = 100 # index-assign (bounds-checked)
var total = 0
for i, x in xs { total = total + x + i } # indexed iteration
respond "len={len(xs)} first={xs[0]} has100={contains(xs, 100)} total={total}"
}The higher-order ops read best as a method chain:
route GET "/stats" -> string {
let xs = [5, 3, 8, 1, 9, 2]
let bigs = xs.filter(x => x > 3).map(x => x * 10) # [50, 80, 90]
let total = xs.reduce(0, (acc, x) => acc + x) # 28
let ranked = xs.sort() # [1, 2, 3, 5, 8, 9]
respond "n_big={len(bigs)} total={total} min={ranked[0]} max={ranked[len(ranked) - 1]}"
}An empty list literal takes its element type from context — a declared type, a return type, filled, or the left of a ??: let seen = maybe ?? [].
Map functions
[K: V] is a hash map with string or int keys. A lookup m[k] yields V? (null when the key is absent); m[k] = v inserts or overwrites.
| Signature | Returns | Description |
|---|---|---|
len(m: [K: V]) -> int | int | Number of entries. |
has(m: [K: V], k: K) -> bool | bool | Is k present? |
remove(m: [K: V], k: K) -> bool | bool | Remove k; returns whether it was present. |
Iterate with for k, v in m { … }. Maps are commonly stored in state so they persist across requests.
state counts { var hits: [string: int] = [:] }
route GET "/hit/:page" (page: string) -> string {
let n = (counts.hits[page] ?? 0) + 1 # m[k] -> V?, ?? gives a default
counts.hits[page] = n
if has(counts.hits, "admin") { let _ = remove(counts.hits, "admin") }
respond "{page}={n} total_pages={len(counts.hits)}"
}Environment & time
| Signature | Returns | Description |
|---|---|---|
env(name: string) -> string | string | Read an environment variable (empty string if unset). Used for configuration — database URLs, secrets, upstream bases. |
now_ms() -> int | int | Current Unix time in milliseconds. Available anywhere. |
ready() -> bool | bool | true normally, false once the server is draining (SIGTERM received). Serve it from a readiness probe so the load balancer stops routing before shutdown — see Graceful shutdown. |
env() is the idiomatic way to configure the resource blocks:
database db { url env("DATABASE_URL") }
upstream api { base env("BACKEND_URL") }
grpc Svc { addr env("GRPC_ADDR") }Request context
These read from the in-flight HTTP request, so they are only valid inside a route handler or a decorator (using them elsewhere is a compile-time error).
| Signature | Returns | Description |
|---|---|---|
request_header(name: string) -> string? | string? | A request header value, or null if absent. Case-insensitive name. |
request_cookie(name: string) -> string? | string? | A cookie value from the request's Cookie header, or null if absent. |
client_ip() -> string | string | The client IP, honouring X-Forwarded-For / X-Real-IP when present. |
route GET "/whoami" -> string {
let ua = request_header("User-Agent") ?? "unknown"
let sid = request_cookie("session") ?? "anonymous"
respond "ip={client_ip()} agent={ua} session={sid} at={now_ms()}"
}These are the primitives that rate limiting and auth are built from — in Weld itself, with no dedicated middleware.
Form bodies & file uploads
Read a submitted HTML form or file upload from the request body. All return an optional (null when the field is absent), so pair them with ?? or else.
| Signature | Returns | Description |
|---|---|---|
form_field(name: string) -> string? | string? | A field from a application/x-www-form-urlencoded or multipart/form-data body (auto-detected by Content-Type; urlencoded values are %/+-decoded). |
upload(name: string) -> string? | string? | A multipart file part's raw bytes (binary-safe). |
upload_filename(name: string) -> string? | string? | The filename of a multipart file part. |
route POST "/upload" -> string {
let file = upload("file") else { fail 400 "no file part" }
let name = upload_filename("file") ?? "upload.bin"
let note = form_field("note") ?? ""
respond "stored {name} ({len(file)} bytes), note: {note}"
}The buffered body (JSON body params, form_field, upload) is capped by MAX_BODY_SIZE (default 8 MB). For larger inputs, stream instead.
Streaming the request body
| Signature | Returns | Description |
|---|---|---|
request_body() -> Stream<string> | a stream of chunks | The raw request body as a stream of byte chunks, consumed by for chunk in request_body() { … }. Read in constant memory — the whole body is never buffered, so it handles inputs far larger than MAX_BODY_SIZE. |
route POST "/measure" -> string {
var bytes = 0
for chunk in request_body() { # each chunk is a slice of raw bytes
bytes = bytes + len(chunk)
}
respond "received {bytes} bytes"
}A streaming route cannot also declare a JSON body parameter (that needs the whole body); read what you need from the chunks instead.
JWT
HS256 JSON Web Tokens. The first argument is a record type naming the claims to decode the payload into; the compiler checks it and produces a value of that type.
| Signature | Returns | Description |
|---|---|---|
jwt_sign(claims: Record, secret: string) -> string | string | Sign a claims record as an HS256 token. The record's fields become the payload — include exp/iat/nbf as int fields (Unix seconds) to set the standard claims. |
jwt_verify(Type, token: string, secret: string) -> Type! | Type! (fallible) | Verify the HS256 signature (constant-time) and decode the payload into Type. A bad signature, a malformed token, an expired exp, or a not-yet-valid nbf all fail — combine with try/else. |
jwt_decode(Type, token: string) -> Type? | Type? (optional) | Decode the payload without verifying. null on a malformed token. Use only when another layer already established trust. |
When the claims Type carries exp/nbf as plain int fields, jwt_verify enforces them automatically (an expired token becomes a 401).
type Claims = { sub: string, exp: int }
route GET "/login/:user" (user: string) -> string {
let claims = Claims { sub: user, exp: now_ms() / 1000 + 3600 }
respond jwt_sign(claims, env("JWT_SECRET")) # issue a 1-hour token
}
route GET "/me" (query token: string) -> Claims {
let claims = try jwt_verify(Claims, token, env("JWT_SECRET")) # rejects expired/tampered
respond claims
}Unknown JSON fields in the payload are ignored, so your Claims record only needs the fields you use.
Crypto & encoding
Hashing, HMAC, secure randomness, password hashing, and encodings — the building blocks of tokens, sessions, and signatures. Hex/base64 outputs are lowercase; decoders return "" on malformed input (like parseInt returning 0).
| Signature | Returns | Description |
|---|---|---|
password_hash(pw: string) -> string | string | A bcrypt hash (cost 10) with a random salt — the $2b$… string to store. |
password_verify(pw: string, hash: string) -> bool | bool | Check a password against a stored bcrypt hash (constant-time). |
random_bytes(n: int) -> bytes | bytes | n cryptographically-secure random bytes. Encode (hex/base64) before storing or sending as text. |
uuid() -> string | string | A random v4 UUID, e.g. 2f1f4051-1790-443d-bc97-86daac32cbec. |
sha256(data) -> string | string | Lowercase-hex SHA-256 digest (64 chars). data is a string or bytes. |
hmac_sha256(msg, key) -> string | string | Lowercase-hex HMAC-SHA-256 (64 chars). Args are string or bytes. |
base64_encode(data) -> string / base64_decode(s: string) -> bytes | — | Standard Base64 (with padding). Encoders take string/bytes; decoders yield bytes. |
base64url_encode(data) -> string / base64url_decode(s) -> bytes | — | URL-safe Base64, no padding (as used in JWTs). |
hex_encode(data) -> string / hex_decode(s) -> bytes | — | Lowercase hex. |
base32_encode(data) -> string / base32_decode(s) -> bytes | — | RFC 4648 Base32 (for TOTP secrets, authenticator apps). |
encrypt(key, data) -> bytes | bytes | AES-256-GCM authenticated encryption. key is hashed to 32 bytes; output is nonce ‖ ciphertext ‖ tag. |
decrypt(key, data) -> bytes? | bytes? | Decrypt & authenticate; null on a wrong key or tampered data. |
seal(key, data) -> string / unseal(key, token) -> bytes? | — | Like encrypt/decrypt but the token is compact base64url — handy for signed+encrypted cookies. |
totp(secret) -> string | string | Current 6-digit TOTP code (RFC 6238, 30 s window, HMAC-SHA1). |
totp_verify(secret, code) -> bool | bool | Check a code against the current window ±1 (clock-skew tolerant). |
es256_keygen() -> string / es256_public(priv) -> string | string | Generate an ECDSA P-256 private key (hex), and derive its SEC1 public key (hex). |
jwt_sign_es256(claims, priv) -> string | string | Sign a claims record as an ES256 (asymmetric) JWT with a hex private key. |
jwt_verify_es256(T, token, pub) -> T! | T! | Verify an ES256 JWT with the hex public key and decode into T (enforces exp/nbf). |
pem_key(pem) -> string | string | Extract a P-256 key from PEM (SEC1/PKCS#8 private, or SPKI public) into the hex the es256_*/jwt_*_es256 builtins accept; "" on a malformed PEM. |
to_bytes(s: string) -> bytes / to_string(b: bytes) -> string | — | Reinterpret text ⇄ raw bytes (no copy). |
read_file(path: string) -> bytes? | bytes? | Read a file's contents (up to 16 MiB) as bytes; null if it can't be read. Serve a file with respond read_file(...) else { … } plus type/header. Beware path traversal — never pass unvalidated request input as the path. |
read_file_stream(path: string) -> Stream<bytes> | a stream of chunks | Stream a file's bytes chunk-by-chunk (constant memory, any size), consumed by for chunk in read_file_stream(path) { emit chunk } — for chunked file downloads. No chunks if the file can't open. Same path-traversal caveat as read_file. |
ice_servers(id: string, ttl: int) -> string | string (JSON) | Browser-ready RTCConfiguration JSON with a short-lived TURN-REST credential (valid ttl seconds) for the turn relay. Requires a turn { } block. |
type Creds = { username: string, password: string }
state accounts { var hashes: [string: string] = [:] }
route POST "/register" (body creds: Creds) -> string {
accounts.hashes[creds.username] = password_hash(creds.password) # bcrypt
respond "token={hex_encode(random_bytes(24))} id={uuid()}" # opaque token + id
}
route POST "/login" (body creds: Creds) -> string {
let stored = accounts.hashes[creds.username] ?? ""
if !password_verify(creds.password, stored) { fail 401 "invalid credentials" }
respond "signature={hmac_sha256(creds.username, env("HMAC_KEY"))}"
}hash() (above, under Conversion) is Wyhash — fast but not cryptographic; never use it for passwords or signatures. Reach for password_hash or hmac_sha256/sha256 instead.
Files & directories (std)
Low-level file I/O and filesystem queries, namespaced under std. Paths are resolved relative to the server process's working directory. File descriptors are plain ints (< 0 means the open failed). Reads and writes stream, so you can move files of any size in constant memory. For a self-contained whole-file download, read_file/read_file_stream (above) are simpler; these are the building blocks when you manage the descriptor yourself (e.g. writing an upload straight to disk).
| Signature | Returns | Description |
|---|---|---|
std.open_file_write(path: string) -> int | fd, or -1 | Create/truncate path for writing and return its descriptor. |
std.open_file_read(path: string) -> int | fd, or -1 | Open path for reading and return its descriptor. |
std.write(fd: int, data: bytes) -> int | bytes written, or -1 | Write data (a string or bytes) to the descriptor. |
std.read_stream(fd: int) -> Stream<bytes> | a stream of chunks | Read the descriptor chunk-by-chunk, consumed by for chunk in std.read_stream(fd) { … }. Closes fd when the stream is exhausted. |
std.close(fd: int) | — | Close a descriptor (a no-op for fd < 0). |
std.file_exists(path: string) -> bool | bool | Does path exist and is it reachable? |
std.is_file(path: string) -> bool | bool | Is path a regular file? |
std.is_dir(path: string) -> bool | bool | Is path a directory? |
std.make_dir(path: string) -> bool | bool | Create a directory and any missing parents (like mkdir -p); true on success or if it already exists. |
std.delete_file(path: string) -> bool | bool | Delete a file; true if it was removed, false if it was missing or couldn't be deleted. |
std.list_dir(path: string) -> [string] | [string] | The entry names in a directory (empty if it can't be read). |
Stream an upload straight to disk, then stream it back — constant memory in both directions:
route POST "/files/:name" (name: string) -> string {
let fd = std.open_file_write("uploads/{name}")
if fd < 0 { fail 500 "cannot open file" }
for chunk in request_body() { # raw body, chunk by chunk
if std.write(fd, chunk) < 0 { std.close(fd) fail 500 "write failed" }
}
std.close(fd)
respond "stored {name}"
}
route GET "/files/:name" (name: string) -> bytes {
let path = "uploads/{name}"
if !std.file_exists(path) { fail 404 "no such file" }
let fd = std.open_file_read(path)
type "application/octet-stream"
for chunk in std.read_stream(fd) { emit chunk } # closes fd at EOF
}WARNING
path is used verbatim — never pass unvalidated request input (a caller could send ../etc/passwd). Confine writes to a directory you control and validate or replace the name, as the upload route does by only using the :name segment inside uploads/.
Statements
Weld handlers are made of statements. These keywords are the statement vocabulary.
Response statements
Valid inside a route handler.
| Statement | Effect |
|---|---|
respond Expr | Send the value and finish the handler. A record/list/sum encodes as JSON (application/json); a string is sent as text; a number/bool is rendered. |
status <int | HttpStatus> | Set the HTTP status code (default 200). Takes an int (status 404) or a value of the built-in std.HttpStatus enum (status std.HttpStatus.NotFound). |
type <string | MimeType> | Set the Content-Type header (default text/plain). Takes a literal string (type "application/json") or a value of the built-in std.MimeType enum (type std.MimeType.Json) to avoid mis-spelling common types. |
header Name Value | Add an arbitrary response header (both strings), e.g. header "Cache-Control" "no-store". Use for CORS, caching, or a raw Set-Cookie. Also valid in a decorator. |
cookie Name Value | Set a Set-Cookie with secure session defaults (Path=/; HttpOnly; SameSite=Lax). For full control (Max-Age, Secure) use header "Set-Cookie" "…". |
emit Expr | Stream one chunk (a string or bytes) via HTTP chunked transfer; the body is never fully buffered. Repeatable — e.g. for chunk in read_file_stream(path) { emit chunk } for a chunked download. Any type/header/cookie (and configured CORS headers) set before the first emit are carried in the chunked reply's head; a respond before the first emit is a terminal early bail-out (sends a normal buffered reply and returns). |
serve BASE SUB | Send the file at BASE/SUB; content type inferred from the extension, 404 if missing, 403 on a .. traversal. |
fail STATUS MESSAGE | Short-circuit with an error response. STATUS is any int expression (a literal, a variable, or a std.HttpStatus value like std.HttpStatus.NotFound); MESSAGE is any string expression. Also usable in decorators, hubs, and transactions. In a typed-error function, fail Variant(…) raises a typed value instead. |
route GET "/report" {
type std.MimeType.Text # or: type "text/plain; charset=utf-8"
status 200
emit "line 1\n"
emit "line 2\n" # each emit is flushed immediately
}
route GET "/assets/*path" (path: string) {
serve "public" path # ./public/<path>
}The std namespace
std is the built-in standard-library namespace. Its members are ordinary proto-style enums, referenced with the std. prefix (there is no bare MimeType — only std.MimeType). They need no import, work with str() / int() / Mime(s)-style reinterpretation like any enum, and only appear in the generated code when you reference them.
std.MimeType — well-known content types, so you write type std.MimeType.Json instead of a mis-spellable "application/json". Each variant's string is the MIME type (str(std.MimeType.Html) → "text/html; charset=utf-8"). std.MimeType.Bytes (application/octet-stream) is the zero/fallback.
| Variant | Content type | Variant | Content type |
|---|---|---|---|
.Json | application/json | .Bytes | application/octet-stream |
.Html | text/html; charset=utf-8 | .Text | text/plain; charset=utf-8 |
.Css | text/css; charset=utf-8 | .Js | text/javascript; charset=utf-8 |
.Xml | application/xml | .Yaml | application/yaml |
.Csv | text/csv; charset=utf-8 | .EventStream | text/event-stream |
.Form | application/x-www-form-urlencoded | .Multipart | multipart/form-data |
.Png | image/png | .Jpeg | image/jpeg |
.Gif | image/gif | .Webp | image/webp |
.Svg | image/svg+xml | .Ico | image/x-icon |
.Pdf | application/pdf | .Wasm | application/wasm |
.Zip | application/zip | .Gzip | application/gzip |
.Woff2 | font/woff2 | .Mp4 | video/mp4 |
.Mpeg | audio/mpeg |
std.HttpStatus — named status codes, so you write status std.HttpStatus.NotFound instead of 404. Each variant's number is the code (used by status) and its string is the reason phrase (str(std.HttpStatus.NotFound) → "Not Found"). Covers the common 1xx–5xx codes: .Continue, .SwitchingProtocols, .Ok, .Created, .Accepted, .NoContent, .PartialContent, .MovedPermanently, .Found, .SeeOther, .NotModified, .TemporaryRedirect, .PermanentRedirect, .BadRequest, .Unauthorized, .Forbidden, .NotFound, .MethodNotAllowed, .NotAcceptable, .RequestTimeout, .Conflict, .Gone, .PayloadTooLarge, .UnsupportedMediaType, .UnprocessableEntity, .TooManyRequests, .InternalServerError, .NotImplemented, .BadGateway, .ServiceUnavailable, .GatewayTimeout.
Bindings & assignment
| Statement | Effect |
|---|---|
let name [: T] = Expr | Immutable binding. Optional explicit type. |
var name [: T] = Expr | Mutable binding. |
name = Expr | Reassign a var. |
obj.field = Expr | Assign a record field (through a mut self or a state field). |
xs[i] = Expr | List index-assign (bounds-checked). |
m[k] = Expr | Map insert / overwrite. |
let _ = Expr | Evaluate for effect and discard (e.g. an ignored fallible result). |
Control flow
| Statement | Effect |
|---|---|
if C { … } else if C2 { … } else { … } | Conditional. else if / else are optional. |
for x in Iterable { … } | Iterate a list, a stream, or any type with a next(mut self) -> T? method. |
for i, x in List { … } | Iterate a list with a 0-based int index i and the element x. |
for k, v in Map { … } | Iterate a map's key/value pairs. |
return [Expr] | Return from a fn (bare return in a void fn). |
assert Cond | In a test block, assert a boolean; a failing assert fails the test run. |
transaction db { … } | Run the body inside a Postgres BEGIN/COMMIT, rolling back on any failure. |
match is an expression, not a statement — see below.
Fallible & optional handling
| Form | Effect |
|---|---|
try Expr | Evaluate a fallible T!; on failure, propagate (auto error response in a route, .err in a fallible fn). Yields the unwrapped T. |
let x = Expr else e { … } | Handle a fallible failure: e is bound to the error (Error, or the declared typed error) and the block must diverge (respond/fail/return). |
let x = Expr else { … } | Unwrap an optional T?; the block runs (and must diverge) when the value is null. |
route GET "/u/:id" (id: int) -> User {
let u = db.findUser(id) else e { # fallible: bind the Error
status 404
respond "not found: {e.message}"
}
let email = u.email else { fail 400 "no email on file" } # optional: unwrap or fail
respond User { id: u.id, name: u.name, email: email }
}See Error Handling for the full model.
Hub surface
These are only meaningful inside a WebSocket hub. They manage a connection's identity/membership and let you push server-initiated events.
Per-connection operations
Valid inside a hub's connect block or a method. Each acts on the current connection.
| Signature | Effect |
|---|---|
identify(id: string) | Tag this connection with an identity (e.g. a user id) so it can be targeted by c.identity. |
join(group: string) | Add this connection to a named listener group. |
leave(group: string) | Remove this connection from a group. |
Broadcasting to clients
Hub.clients (where Hub is your hub's name) is a queryable set of live connections. Filter it, then push an event to the survivors.
| Expression | Meaning |
|---|---|
Hub.clients | The set of all connected clients. |
.filter(c => Bool) | Keep connections matching a predicate. Chainable. |
.send(Record) | Push a record to each connection as {"event":"<TypeName>","data":{…}}. |
.count() -> int | The number of live connections (after any .filter). Also valid in a plain route handler. |
A hub may also declare a disconnect { … } block that runs when a socket drops — the connect-time injected bindings stay in scope, so it can broadcast a departure, but it has no client to reply to. See WebSocket Hubs.
Inside a filter predicate the parameter (c) is a connection handle:
| Field / method | Type | Meaning |
|---|---|---|
c.identity | string | The connection's identify(…) tag. |
c.id | int | A stable per-connection id. |
c.subscribed(group: string) -> bool | bool | Is the connection in group? |
c.<injected> | injected type | Any binding from the hub's connect (…) injects (x: T) clause, e.g. c.user. |
type Notice = { text: string }
hub Chat {
connect (query token: string, query room: string) injects (user: Claims) {
user = try jwt_verify(Claims, token, env("JWT_SECRET"))
identify(user.sub) # target by user id later
join(room) # add to the room group
Chat.clients.filter(c => c.subscribed(room))
.send(Notice { text: "{user.sub} joined" })
}
method dm(to: string, text: string) {
Chat.clients.filter(c => c.identity == to) # a direct message
.send(Notice { text: text })
}
}Builtin types & globals
| Name | Kind | Description |
|---|---|---|
int | primitive | 64-bit signed integer. Arithmetic wraps on overflow. |
float | primitive | 64-bit floating point. |
bool | primitive | true / false. |
string | primitive | UTF-8 text (a byte slice). |
T? | type former | Optional — the value or null. |
[T] | type former | Mutable list. |
[K: V] | type former | Map (K is string or int). |
T! | type former | Fallible result (carries Error or a declared typed error). |
Error | builtin record | { status: int, message: string }. The error a bare else e { … } binds, and the shape of the automatic error response. You can construct and read it like any record. |
Self | builtin type | Inside an interface method signature or a generic method, refers to the implementing type. |
null | literal | The absent value of any T?. |
| injected bindings | value | Names introduced by a decorator's or hub's injects (…) clause (e.g. user), typed and in scope in the handler/method body. |
Sum-type variants are constructed qualified — Shape.Circle(2.0), Role.Admin — and matched unqualified. Sum types and the Error type together power typed errors.
Quick index
- Strings:
upper·lower·trim·trimPrefix·contains·startsWith·endsWith·parseInt - Conversion:
str·int·hash·Enum(x) - Lists:
len·push·filled·slice·pop·concat·reverse·contains·sort·insert·removeAt·map·filter·reduce(all callable asxs.op(…)) - Maps:
len·has·remove - Env & time:
env·now_ms - Request:
request_header·request_cookie·client_ip·form_field·upload·upload_filename·request_body - JWT:
jwt_sign·jwt_verify·jwt_decode(HS256) ·jwt_sign_es256·jwt_verify_es256·es256_keygen·es256_public·pem_key(ES256) - Crypto & encoding:
password_hash·password_verify·random_bytes·uuid·sha256·hmac_sha256·encrypt·decrypt·seal·unseal·totp·totp_verify·base64_encode·base64_decode·base64url_encode·base64url_decode·hex_encode·hex_decode·base32_encode·base32_decode - Bytes & files:
to_bytes·to_string·read_file·read_file_stream(see thebytestype) - Files & dirs (
std):std.open_file_write·std.open_file_read·std.write·std.read_stream·std.close·std.file_exists·std.is_file·std.is_dir·std.make_dir·std.delete_file·std.list_dir - Hub:
identify·join·leave·Hub.clients.filter(…).send(…)·.count() - WebRTC:
ice_servers(with aturn { }block) - Statements:
respond·status·type·header·cookie·emit·serve·fail·let·var·if·for·match·return·assert·transaction·try·else