Services
The builtin services are always available - no import of an instance, no construction. The
ADM service manager starts them before application.new runs and stops them on
shutdown, so calling one is just Cache.get("k"). For the language rules behind
service declarations, see Services in the docs.
A service's public surface is exactly its annotated methods. Fields are always private, and a
def with no annotation is internal to the service: it can be called by the
service's own methods (method "helper" is internal to service
Counter, field "count" is internal to service Counter). Only the members
the manager relies on are exempt: the ServiceDescriptor fields
(description, dependencies, lifecycle,
permissions, status) and the ServiceHooks methods (config,
start, stop, restart). Every public method is one of
three kinds:
| query | Reads a snapshot of the service's state. Never async. |
| commit | Mutates state and emits a typed event. Implicitly atomic; may be async. |
| emit |
Describes an event's shape only - you subscribe to it with
@on(Service.method) and never call it.
|
use std.services::(Cache, Diagnostics)
use std.metrics::(Counter)
def warm(email string) !none {
Cache.set("user.{email}", email, ttl = 5m)
let hits = try Diagnostics.register<Counter>("cache.warm")
hits.inc()
return none
}
@on(Cache.expired)
def onExpiry(evt Event<string>) {
println("expired {evt.result}")
}
Events and observers
Every @commit() call emits an event; there is no way to run a commit silently.
The event is named after the method, carries the arguments it was called with, and carries
what it returned. It is an ordinary value, Event<T> from the prelude:
struct Event<T> {
source service // the service that emitted it
name string // the method name: "open"
params map<string, any> // the call's named arguments: {"path": "data.txt"}
result T // the method's return value, exactly its declared type (T, ?T or !T)
time time.Time // reserved; not populated yet
}
So Storage.open("data.txt") hands the caller the file and hands every observer
an Event<os.File> with name = "open",
params["path"] = "data.txt" and result set to that same file. An
@emit() method is the secondary form: the service calls it from inside a commit
(opened(file)) to publish a named event whose result is the
value it was given and whose params are empty. @query() methods
never emit. Emitting an event that no method declares is a compile error.
@on(Service.method) subscribes a handler: a free function or a method, taking
exactly one argument, the Event<T> for that method's return type. Handlers
run synchronously inside the commit, after the method body returns and before the caller
gets the result, so by the time Storage.open returns every observer has seen the
event. A handler cannot change the commit's result. A second argument filters:
@on(Storage.open, audit) with def audit(ev Event<os.File>) bool
runs the handler only for events the filter accepts; the filter sees the same event record.
A method handler on a service runs on that service's singleton; a method handler on any other
type runs on one lazily created instance of it.
The Event is read straight through its fields: ev.result,
ev.params["path"], ev.name. Commits are serialized per service
(implicitly atomic), so observers only ever see completed state, and events are
not stored: a handler registered after a commit does not see it.
The service manager owns lifecycle. Services whose lifecycle.start is
StartMode.Automatic are started before application.new runs, in
the order their dependencies require; StartMode.Manual services
wait for code to call start(). lifecycle.restart decides what a
failed start gets: Never, OnFailure (retried) or
Always (retried more), and the outcome lands in the service's
status field as a ServiceStatus
(Starting, Started, Stopping, Stopped,
Restarting, Failed). Calling start/stop/
restart yourself goes through the manager too, so status stays
truthful. Services are singletons that never expire and cannot be constructed with
new; all of them stop at shutdown.
Services also ship annotations - @cache,
@metric, @measureTime and friends - that wrap a declaration instead
of being called. Import them by name (use std.services::(cache)). An annotation
that accepts more than one kind of target must be written qualified
(use std.services then @services.trace()), because a by-name import
narrows it to a single target.
Signatures on this page are generated from the standard library source. Some services are still filling in method bodies; annotations whose behavior is not wired up yet are marked planned.
Builtin services
Application
Identity and lifecycle of the running application.
-
query
def files(name string = "") !stringThe folder holding a package's shipped files, its
[package] files: the calling package's whennameis empty, else the library namednamespace:name(local:namefor one installed from a file). Once the program is installed that isshare/<namespace>/<name>beside the executable, or the install root for the application itself; while it runs from its source tree it is the package cache for a library and the tree for the application. Fails when no folder exists in either layout. -
query
def filePath(path string) !stringResolves a package path:
package://assets/logo.pngis a file the calling package shipped,acme:imaging://assets/logo.pngone a library shipped. Any other path comes back unchanged. EveryStoragemethod, and so everystd.oscall, resolves its path this way, soos.readFile("package://assets/logo.png")works fromadm run, from a build in the tree and from an installed program alike. Fails when the package has no shipped files. -
query
def pid() intReturns process id of the application
-
query
def executablePath() stringReturns path to the application executable.
-
query
def startTime() TimeReturns time when the application process started.
-
query
def name() stringReturns the name the application is known by: the
adm.tomlslug when one is configured, else the declared application name. -
commit
def home() !stringReturns the application's home folder, creating it on first use and bringing it up to date with this version: the
versionmarker, a snapshot ofdata/and the@migrationchain. Fails on a downgrade without@allowDowngrade, on a foreign folder at the same path, or when no home directory is known. See Application home & migrations. -
query
def version() stringReturns application version, or an empty string if the application is not versioned.
-
query
def build() stringReturns application build number, or an empty string if unavailable.
-
query
def instanceId() stringReturns identifier of the current application instance.
The identifier is unique to this running instance and changes between runs.
-
query
def arguments() string[]Returns command-line arguments passed to the application.
-
query
def uptime() durationReturns how long the application has been running.
-
commit
def shutdown(code int = 0) !noneRequests graceful application shutdown.
-
query
def shuttingDown() boolReturns whether graceful application shutdown has been requested.
-
emit
def shutdownRequested(code int) intEmitted when graceful application shutdown is requested.
-
commit
def exit(code int)Terminates the application using the specified exit code.
Cache
Fast in-memory cache with TTL, idle expiration, glob selectors, and size limits.
-
commit
atomic def set(key string, value any, ttl ?duration = none, idle ?duration = none)Stores a value under the key.
ttl caps how long the key lives; idle is how long it may go unread before it expires. Either may be left off.
-
query
atomic def get(key string) ?anyThe value under the key, or none when there is none or it has expired.
Reading restarts the idle timer.
-
query
atomic def get(keys string[]) map<string, any>The values under the given keys; missing and expired keys are left out.
Reading restarts each key's idle timer.
-
query
atomic def get(selector Glob) map<string, any>The values under every key the selector matches.
Reading restarts each key's idle timer.
-
commit
atomic def delete(key string)Removes the key.
-
commit
atomic def delete(keys string[])Removes the keys.
-
commit
atomic def delete(selector Glob) intRemoves every key the selector matches and returns how many went.
-
commit
atomic def renew(key string, ttl ?duration = none, idle ?duration = none)Gives the key a new ttl, idle time, or both.
A ttl counts from now; an idle time restarts the idle timer.
-
commit
atomic def renew(selector Glob, ttl ?duration = none, idle ?duration = none) intRenews every key the selector matches and returns how many.
A ttl counts from now; an idle time restarts each idle timer.
-
commit
atomic def take(key string) ?anyRemoves the key and returns what it held, or none when nothing live was there.
-
commit
atomic def touch(key string)Restarts the key's idle timer; the ttl is untouched.
-
commit
atomic def touch(keys string[])Restarts the idle timer of each key; ttls are untouched.
-
commit
atomic def touch(selector Glob) intRestarts the idle timer of every key the selector matches and returns how many.
-
query
atomic def has(key string) boolWhether the key is live.
-
query
atomic def has(keys string[]) map<string, bool>Whether each key is live.
-
query
atomic def has(selector Glob) boolWhether any live key matches the selector.
-
query
atomic def ttl(key string) ?durationHow long the key has left to live, or none when it is gone or has no ttl.
-
query
atomic def ttl(keys string[]) map<string, ?duration>How long each key has left to live; none for a key that is gone or has no ttl.
-
query
atomic def ttl(selector Glob) map<string, ?duration>How long each matching key has left to live; none for one with no ttl.
-
query
atomic def idle(key string) ?durationHow long the key may still go unread, or none when it is gone or has no idle time.
-
query
atomic def idle(keys string[]) map<string, ?duration>How long each key may still go unread; none for a key that is gone or has no idle time.
-
query
atomic def idle(selector Glob) map<string, ?duration>How long each matching key may still go unread; none for one with no idle time.
-
query
atomic def keys() string[]Every live key.
-
query
atomic def keys(selector Glob) string[]Every live key the selector matches.
-
query
atomic def size() intHow many keys are live.
-
query
atomic def size(selector Glob) intHow many live keys the selector matches.
-
commit
atomic def clear()Empties the cache.
-
emit
def expired(key string) stringEmitted when a key expires.
-
emit
def deleted(key string) stringEmitted when a key is removed by a call rather than by expiry.
-
emit
def created(key string) stringEmitted when a key is stored for the first time.
Clipboard
Text copy and paste through the system clipboard. The service drives the desktop's clipboard program: wl-copy and wl-paste on Wayland, xclip or xsel on X11, pbcopy and pbpaste on macOS. A machine without one reports nothing available and the calls fail. Reading needs adm.clipboard.read, writing adm.clipboard.write, and both run the program through Runtime.run, so adm.runtime.spawn as well. copy, paste and clear are commits, so @on(Clipboard.copy), @on(Clipboard.paste) and @on(Clipboard.clear) observe them. The programs run through the shell, which the OS sandbox refuses.
-
commit
def copy(text string) !nonePuts the text on the clipboard, replacing what was there.
Fails when the policy denies it, this machine has no clipboard program, or the program fails.
-
commit
def paste() !stringReturns the text on the clipboard, "" when it holds none.
Fails when the policy denies it, this machine has no clipboard program, or the program fails.
-
commit
def clear() !noneEmpties the clipboard.
-
query
def has() !boolWhether the clipboard holds any text. Needs the read permission.
-
query
def capabilities() ClipboardCapabilitiesReports whether this machine has a clipboard program and which one:
wl-clipboard,xclip,xselorpbcopy. -
commit
def watch(period duration = 500ms) !noneStarts watching the clipboard: a task reads it every
periodand emitschangedwhen the text differs from what it saw last, whichever program changed it. Calling it while watching only changes the period.Fails when the policy denies reading or this machine has no clipboard program.
-
commit
def unwatch()Stops the watcher task; nothing happens when none runs.
-
query
def watching() boolWhether the watcher task runs.
-
emit
def changed(change ClipboardChange) ClipboardChangeEmitted by the watcher when the clipboard text changed.
ClipboardChangecarries the text ("" when emptied), whether this program put it there throughcopy, and when the watcher noticed.
Config
Layered configuration with profiles, typed reads, and reload events.
-
commit
def switchProfile(profile ?string) !noneSwitches to the profile and reloads every source.
When the reload fails the old profile and its values stay in place.
-
query
def profile() ?stringThe active profile, or none when no profile is selected.
-
query
def get(key string) ?anyThe value the key resolves to, or none when no source defines it.
-
query
def get<T>(key string) !?TThe value the key resolves to, converted to T; none when no source defines it, an error when it does not convert.
-
query
def has(key string) boolWhether some source defines the key.
-
commit
def set(key string, value any)Overrides the key for this process.
An override wins over every source and is never written back to one.
-
commit
def reset(key string)Drops the override on the key.
The key goes back to whatever the sources say.
-
commit
def reload() !noneReloads every source.
-
query
def sources() ConfigSourceConfig[]The sources, highest precedence first.
-
query
def source(name string) ?ConfigSourceConfigThe source with that name, or none.
-
query
def sourceOf(key string) ?ConfigSourceThe source the key's value comes from; none for an override or an unknown key.
-
query
def lastLoaded() time.TimeWhen the sources last loaded without error.
-
emit
def changed(change ConfigChange) ConfigChangeEmitted when a key's value changes.
A reload that leaves the value as it was emits nothing.
-
emit
def reloadFailed(event ConfigReloadError) ConfigReloadErrorEmitted when a source fails to reload.
The values from the last good load stay in place.
Debugger
Profiling, tracing, heap snapshots, and debug control.
-
commit
def profileStart(kind ProfileKind) !ProfileIdStarts a profile of the given kind and returns its id.
-
commit
def profileStop(id ProfileId) !ProfileStops the profile and returns what it collected.
-
commit
def traceStart() !TraceIdStarts a trace and returns its id.
-
commit
def traceStop(id TraceId) !TraceStops the trace and returns what it recorded.
-
commit
def gc() !noneTriggers a garbage collection cycle.
-
query
def stackTrace() errors.StackTraceThe stack trace of the calling task.
-
query
def heapSnapshot() !HeapSnapshotTakes a heap snapshot.
-
commit
def pause() !noneBreaks into the debugger when one is attached; otherwise does nothing.
-
emit
def watched(event WatchEvent) WatchEventEmitted when a watched field or variable is read or written.
Which accesses count is the watch's mode.
Devices
Cameras, microphones, USB, and other attached hardware.
Planned - no public methods yet.
Diagnostics
Named metric registry - counters, gauges, histograms, and toggles.
-
commit
def register<T: Metric>(name string) !TRegisters a metric under the specified name.
If a metric with the same name and type already exists, it is returned. Fails if the name is already registered with a different metric type.
-
query
def get(name string) ?MetricReturns the metric registered under the specified name.
Returns none if no metric with that name exists.
-
query
def has(name string) boolReturns whether a metric with the specified name is registered.
-
query
def list() map<string, Metric>Returns all registered metrics.
-
query
def names() string[]Returns all registered metric names.
I18n
Locale selection and message catalogs.
Planned - no public methods yet.
IPC
Inter-process communication between ADM applications.
Planned - no public methods yet.
Logging
Leveled logging with structured fields.
-
commit
def debug(message string, fields map<string, any> = {}) !noneWrites a log entry at debug level.
-
commit
def info(message string, fields map<string, any> = {}) !noneWrites a log entry at info level.
-
commit
def warning(message string, fields map<string, any> = {}) !noneWrites a log entry at warning level.
-
commit
def error(message string, fields map<string, any> = {}) !noneWrites a log entry at error level.
-
commit
def fatal(message string, fields map<string, any> = {}) !noneWrites a log entry at fatal level.
-
commit
def log(level LogLevel, message string, fields map<string, any> = {}) !noneWrites a log entry at the given level.
-
query
def level() LogLevelThe lowest level that is written.
-
commit
def setLevel(level LogLevel)Sets the lowest level that is written.
Entries below it are dropped before they reach any writer.
Messaging
In-memory queues and topics.
Planned - no public methods yet.
Network
Sockets, addressing, name resolution, and socket options.
-
commit
def socket(domain net.SocketDomain, typ net.SocketType) !net.SocketOpens a socket for the domain and type; the protocol follows from them. The socket owns its descriptor and must be closed. Errors carry the errno as `error.code` (`std.net.EAddrInUse`) and name the failing operation.
-
commit
def socketFd(domain net.SocketDomain, typ net.SocketType) !intOpens a socket and returns its raw descriptor, for code that works with descriptors rather than `std.net.Socket`.
-
commit
def bind(fd int, addr Endpoint) !noneBinds a socket to a local address: `host:port` or `:port` for IPv4, `[host]:port` or `[]:port` for IPv6, an absolute path for a Unix socket. An empty host binds every interface, port 0 picks a free one (`localAddr` tells which). An existing Unix socket path is not removed.
-
commit
def connect(fd int, addr Endpoint, timeout duration = 30s) !noneConnects a socket to a remote endpoint, waiting at most `timeout` for the handshake; a timeout fails with `ETIMEDOUT` and leaves the socket open for the caller to close or retry.
-
commit
def accept(fd int) !intAccept a new connection from a listening stream socket FD.
Returns the accepted connection as a new file descriptor; the caller owns the returned FD and must close it.
-
commit
def close(fd int) !noneClose a socket FD.
Closing an already-closed FD is an OS error; `std.net` wrappers typically expose `close()` and forward to this method.
-
commit
def listen(fd int, backlog int) !noneMark a bound stream socket as a listener.
`backlog` is passed through to the OS; its effective value may be clamped by the platform.
-
commit
def write(fd int, data byte[], timeout duration = 30s) !intWrite bytes to a connected stream socket FD.
Returns the number of bytes written; short writes are normal and callers must loop if they need to send the full buffer (see `std.net.Connection.writeAll`).
`timeout` bounds the wait for the FD to become writable, not an end-to-end "flush to peer" guarantee.
-
commit
def read(fd int, data byte[], timeout duration = 30s) !intRead bytes from a connected stream socket FD.
Returns the number of bytes read (0 indicates EOF / peer shutdown).
`timeout` bounds the wait for the FD to become readable.
-
commit
def resolve(dns string) !string[]Resolve a DNS name to IP literals (IPv4 and/or IPv6).
The returned strings never include ports. For "host:port" parsing and socket endpoint construction, see `std.net.Address`.
-
commit
def dialStream(addr Endpoint, timeout duration = 30s) !intResolve + connect a stream socket and return a connected file descriptor.
This is the lowest-level "dial" helper: it returns a raw FD so higher-level wrappers (`std.net.dialStream`, connection pools, etc.) can build on it.
-
commit
def sendTo(fd int, data byte[], addr Endpoint, timeout duration = 30s) !intSend a datagram to a remote address (UDP / Unix datagram).
Returns the number of bytes sent. For datagrams this is usually either `data.len()` or an error.
-
commit
def recvFrom(fd int, data byte[], timeout duration = 30s) !(int, string)Receive a datagram and return the byte count and sender address string.
The returned address uses the same string format accepted by `sendTo` and `std.net.Address.parse`.
-
commit
def shutdown(fd int, how int = 2) !noneShutdown one or both halves of a connection.
`how` values: - 0: read half (further reads fail/EOF) - 1: write half (further writes fail) - 2: both (full shutdown)
-
commit
def setReuseAddr(fd int, enabled bool = true) !noneEnable or disable SO_REUSEADDR.
This is typically required for servers that need to restart quickly.
-
commit
def setNoDelay(fd int, enabled bool = true) !noneEnable or disable TCP_NODELAY (TCP only).
For non-TCP sockets this may fail with an OS error.
-
commit
def setKeepAlive(fd int, enabled bool = true) !noneEnable or disable SO_KEEPALIVE.
Keepalive behavior is OS-configured; this only toggles it.
-
commit
def setReusePort(fd int, enabled bool = true) !noneEnable or disable SO_REUSEPORT when supported by the platform.
Some OSes do not expose this option; in that case this returns an error.
-
commit
def setLinger(fd int, enabled bool, seconds int = 0) !noneControl SO_LINGER.
When enabled, `seconds` controls how long the OS may block during `close` in an attempt to deliver queued data.
-
commit
def setRecvBuf(fd int, bytes int) !noneSet SO_RCVBUF.
-
commit
def setSendBuf(fd int, bytes int) !noneSet SO_SNDBUF.
-
commit
def setSockOptInt(fd int, level int, opt int, val int) !noneSets an integer socket option by its `setsockopt` level and name, for options `std.net.Socket` does not wrap.
-
commit
def getSockOptInt(fd int, level int, opt int) !intRead an integer socket option.
-
query
def localAddr(fd int) !stringReturn the local endpoint of a socket FD, formatted as an address string.
For stream sockets, this is useful after binding `:0` to discover the chosen ephemeral port. For Unix sockets, this is typically the bound path.
-
query
def remoteAddr(fd int) !stringReturn the remote endpoint of a connected socket FD, formatted as an address string.
-
query
def publicAddr() !stringReturns the host's public address as seen from outside the local network.
-
query
def netIface() !net.NetInterface[]Lists the host's network interfaces with their addresses and `std.net.NetIface*` flags.
-
query
def sockets() SocketInfo[]Returns runtime information for all sockets owned by the Network service.
-
query
def socketInfo(fd int) ?SocketInfoReturns runtime information for the specified socket.
Notifications
Desktop notifications through the platform's notification server. On Linux this is the freedesktop server on the D-Bus session bus; other platforms report nothing available yet. Showing one needs the adm.notifications.show permission.
-
commit
def show(notification Notification) !NotificationIdShows a notification and returns the id the server gave it.
Notificationcarries the title, body, an icon name or absolute image path, the level (Info to Critical), action buttons, a timeout and an id to replace.Fails when the policy denies it, there is no notification server, or the server refuses it.
-
commit
def show(title string, body string = "") !NotificationIdShows a notification with a title and an optional body and returns its id.
-
commit
def close(id NotificationId) !noneTakes a shown notification off the screen.
Fails when there is no connection or the server does not know the id.
-
commit
def ask(notification Notification, wait duration = 60s) !stringShows a notification whose buttons are a question and waits for the answer: the pressed action's id, or "" when the user dismissed it or nobody answered within
wait(the notification is then closed).Fails when there is no notification server or it refuses the notification.
-
query
def capabilities() NotificationCapabilitiesReports what the notification server can do: actions, body text, markup, images, sound, persistence. Nothing is available when there is no server.
-
query
def shown() NotificationId[]The ids of the notifications shown by this program that the server has not closed yet.
-
emit
def action(event NotificationAction) NotificationActionEmitted when the user presses one of a notification's buttons; the event names the notification and the action id.
-
emit
def closed(id NotificationId) NotificationIdEmitted when a notification leaves the screen: dismissed, expired or closed.
Policy
Permissions and policy decisions.
-
commit
def registerSpec(name string, factory PolicySpecFactory) !noneRegisters the spec type a permission names, so the file's rules for it can be checked against arguments.
-
commit
def registerResolver(handler PolicyResolver) !noneRegisters the resolver that answers `ask` rules. Without one an `ask` prompts through a desktop notification (Allow, Always allow, Deny); with prompts off (`ADM_POLICY_PROMPT=0`) it denies.
-
commit
def configure(text string) !noneLoads rules from policy-file text instead of the file, replacing what was loaded. Fails on an unknown permission, field or kind, or a malformed line, naming the line.
-
query
def requirePermissions(permissions string[]) !noneFails unless every package on the call chain holds each permission.
-
commit
def revokePermissions(permissions string[]) !noneDrops permissions from the application's own grants for the rest of the run.
-
query
def hasPermissions(permissions string[]) boolWhether every package on the call chain holds each permission.
-
commit
def register(registration PolicyRegistration) !noneRegisters an owner's rules and validators for one action.
-
query
def evaluate(request PolicyRequest) !PolicyDecisionDecides a request and reports why: which package lacks the permission, or the merged rules that apply.
-
query
def explain(request PolicyRequest) !PolicyDecisionExplains a request: the decision, the rule and layer behind it.
-
query
def require(request PolicyRequest) !noneEvaluates the specified policy request against the compiled grant table for every package on the current call chain, the application first.
Returns successfully when allowed. When denied, fails with a `PolicyDenied` naming the permission and the package lacking it.
-
query
def text() stringThe policy file as it would be written from the loaded rules and settings: one table per subject and permission, the comment preamble kept.
-
query
def validate(permission string, spec string, value string) !noneChecks one constrained argument of a gated function against the merged rule for its permission: the file's rules for the program and for every package on the chain, then the registered spec's own check. An `ask` outcome goes to the resolver, else to a desktop notification the user answers; unanswered denies. The policy state itself is denied to every subject.
-
query
def list() Permission[]Lists every permission the program's services declare.
-
emit
def decided(entry PolicyLogEntry) PolicyLogEntryEmitted for every denial, ask and live answer.
Runtime
The ADM runtime itself - host info, memory, environment, service registry, and the one door to other programs: run starts a command through the system shell behind the adm.runtime.spawn permission, whose description says what granting it means: trusting the package completely. Foreign code (@c, @link, @native, @extern) is not a permission: a dependency binding it is accepted by the developer at install and refused by the build otherwise, see Policy.
-
query
def systemInfo() SystemInfoReturns information about the host system running the ADM runtime.
-
query
def workingDir() stringReturns current process working directory.
-
query
def memoryUsage() MemoryUsageReturns memory usage statistics for the current ADM runtime.
-
query
def sizeOf(val any) intReturns the value's deep retained footprint in bytes. Runtime object and allocation headers, collection capacity, and recursively retained values are included; shared allocations are counted once. UTF-8 string storage is counted even for literals, while unrelated static/external storage is not.
-
query
def getEnv(key string) ?stringReturns value of the specified environment variable.
Returns none when the variable is not defined.
-
query
def services() ServiceInfo[]Returns runtime information for all registered services.
-
query
def serviceInfo(name service) ?ServiceInfoReturns runtime information for the specified service.
Returns none if the service is not registered with the runtime.
-
commit
def run(command string, input string = "") !ProcessResultRuns a command through the system shell with
inputas its standard input and returns what it printed and its exit code (128 + signal when killed, 127 when the shell could not start it). Needsadm.runtime.spawn.std.os.runandstd.os.outputwrap it.Fails when the policy denies it or the process could not be started, which the OS sandbox causes; a command that exited with an error is reported through the code.
-
commit
def setEnv(key string, value string) !noneSets value of the specified environment variable for the current process.
-
emit
def serviceStatusChanged(change ServiceStatusChange) ServiceStatusChangeEmitted when runtime status of a registered service changes.
Scheduler
Cron, one-shot, and repeating schedules.
-
commit
def cron(cronExpression string, name string = "") !ScheduleIdAdds a schedule that fires on the cron expression and returns its id.
-
commit
def runAt(timestamp time.Time, name string = "") !ScheduleIdAdds a schedule that fires once at the given time and returns its id.
The time must be in the future.
-
commit
def runAfter(dur duration, name string = "") !ScheduleIdAdds a schedule that fires once after the duration and returns its id.
The duration must be positive.
-
commit
def runEvery(interval duration, name string = "") !ScheduleIdAdds a schedule that fires every interval and returns its id.
The interval must be positive.
-
commit
def cancel(id ScheduleId) !noneRemoves the schedule.
Fails when there is no such schedule.
-
commit
def pause(id ScheduleId) !nonePauses the schedule.
Its timing is untouched; firings that fall due while it is paused are skipped.
Fails when there is no such schedule.
-
commit
def resume(id ScheduleId) !noneResumes a paused schedule.
It carries on with its original timing.
Firings skipped while it was paused are not made up.
Fails when there is no such schedule.
-
query
def list() Schedule[]Every schedule.
-
query
def get(id ScheduleId) ?ScheduleThe schedule with that id, or none.
-
query
def next(id ScheduleId) ?time.TimeWhen the schedule next fires; none when there is no such schedule or it is paused.
-
emit
def trigger(id ScheduleId) ScheduleIdEmitted when a schedule becomes due.
The service only keeps time; an observer does the work.
Storage
Files, directories, disks, and I/O metrics.
-
commit
def open(path string, mode string) !intOpen a file or folder at the given path with the specified mode.
-
emit
def fileOpened(path string) stringEmitted after a file is opened.
-
commit
def close(fd int) !noneCloses an open file handle.
-
commit
def write(fd int, data byte[]) !intWrites bytes at the handle's current position and returns how many were written.
-
commit
def read(fd int, data byte[]) !intReads into the buffer from the handle's current position and returns how many bytes were read.
-
commit
def readFile(path string) !byte[]Reads a whole file into memory.
-
commit
def writeFile(path string, data byte[]) !noneWrites the bytes to a file, replacing any existing content.
-
commit
def seek(fd int, offset int64, whence int) !int64Moves the handle's position and returns the new absolute offset.
Whence follows the Whence enum: start, current, or end.
-
commit
def readAt(fd int, data byte[], offset int64) !intReads into the buffer starting at an absolute offset, leaving the handle's position unchanged.
-
commit
def writeAt(fd int, data byte[], offset int64) !intWrites bytes at an absolute offset, leaving the handle's position unchanged.
-
commit
def truncate(fd int, size int64) !noneResizes the file to the given size, padding with zero bytes when it grows.
-
commit
def exists(path string) !boolReturns whether a file or directory exists at the path.
-
commit
def remove(path string) !noneRemoves a file.
-
commit
def rename(oldPath string, newPath string) !noneRenames or moves a file or directory.
-
commit
def mkdir(path string) !noneCreates a directory, including any missing parents.
-
commit
def rmdir(path string) !noneRemoves an empty directory.
-
query
def readDir(path string, depth int = 0) !os.DirEntry[]Lists the entries of a directory.
Depth 0 lists the directory itself; a larger depth descends that many levels.
-
commit
def delete(path string) !noneDelete a file or a folder at the given path
-
query
def stat(path string) !os.FileInfoReturns size, mode, and timestamps for a path.
-
query
def openedFiles()Return a list of opened file descriptors.
-
commit
def chmod(file string, mode int64) !noneChanges a file's permission bits.
-
query
def metrics(fd ?int)Return read/write metrics for a file descriptor if a fd is provided or for all if not
-
query
def freeSpace(disk string)Get the free space on a specific disk.
-
query
def disks()List of all available disks.
Telemetry
Telemetry export.
Planned - no public methods yet.
UI
Windows, the renderer, and input events.
-
commit
def openWindow(cfg r.WindowConfig) !r.WindowOpens a window on the configured renderer. The handle stays valid until the window closes.
-
commit
def openWindow<T: component>(root T, cfg r.WindowConfig) !r.WindowOpens a window with root as the component it renders.
-
commit
def openDefaultWindow() !r.WindowOpens a window with the `UIConfig.defaultWindow` settings.
-
commit
def openDefaultWindow<T: component>(root T) !r.WindowOpens a window with the `UIConfig.defaultWindow` settings and root as the component it renders.
-
commit
def closeWindow(win r.Window) !noneCloses the window.
-
commit
def setWindowTitle(win r.Window, title string) !noneSets a window's title.
-
commit
def setWindowIcon(win r.Window, icon image.Image) !noneSets a window's icon.
-
query
def windows() r.Window[]The open windows.
-
query
def pollPlatformEvents(win r.Window) !r.PlatformEvent[]Reads the raw platform events waiting on the window. Nothing is emitted; pumpEvents turns them into `std.ui` events.
-
commit
async def run<T: component>(root T, cfg r.WindowConfig) !noneOpens a window for `root` and returns when the user closes it. The whole of a single-window application's main.
-
commit
async def run<T: component>(root T) !noneOpens a window for `root` with the `UIConfig.defaultWindow` settings and returns when the user closes it.
-
commit
def pumpEvents(win r.Window) !r.PlatformEvent[]Reads the platform events waiting on the window and emits the `std.ui` event for each. Returns the raw events it consumed.
-
commit
def pumpAll() !nonepumpEvents for every open window.
-
emit
def click(evt ui.ClickEvent) ui.ClickEventEmitted for a click, resolved to the component under it.
-
emit
def mouseMove(evt ui.MouseMoveEvent) ui.MouseMoveEventEmitted when the pointer moves, resolved to the component under it.
-
emit
def mouseWheel(evt ui.MouseWheelEvent) ui.MouseWheelEventEmitted for a wheel or trackpad scroll.
-
emit
def resize(evt ui.ResizeEvent) ui.ResizeEventEmitted when a window is resized.
-
emit
def close(evt ui.CloseEvent) ui.CloseEventEmitted when the user asks to close a window.
-
emit
def keyDown(evt ui.KeyEvent) ui.KeyEventEmitted when a key goes down.
-
emit
def keyUp(evt ui.KeyEvent) ui.KeyEventEmitted when a key comes up.
-
emit
def textInput(evt ui.TextInputEvent) ui.TextInputEventEmitted for typed text.
Vault
Encrypted storage for secrets.
Planned - no public methods yet.
Annotations
Each entry shows the annotation as it is written at a use site - the meta context parameter and any type parameter inferred from the target are not spelled out.
@migration
Application · targets functions of the application block
@migration(from string, to string = "")
Marks a step that upgrades the application's home folder from one version to another; see Application.home() and Application home & migrations.
from is the version whose data the step understands; to is the version it produces, or the next declared step's from when omitted. Steps run in ascending order, and only those newer than the version that last ran the folder. The annotated function takes the home folder path and returns !none; a failing step restores the snapshot taken before the first step.
application MyApp {
@migration(from = "3.54", to = "4.0")
def settingsToJson(home string) !none { ... }
@migration(from = "4.0", to = "5.63")
def splitCache(home string) !none { ... }
}
@allowDowngrade
Application · targets the application block
@allowDowngrade()
Lets the application open a home folder last written by a newer version of itself. Without it, a downgrade fails in Application.home().
@allowDowngrade()
application MyApp { ... }
@cache
Cache · targets methods
@cache(key string, ttl ?duration = none, idle ?duration = none, refresh = false)
Serves the method's result from the cache under key.
A live entry is returned and the body does not run; otherwise the body runs and its result is stored. With refresh the body always runs and replaces the entry.
ttl and idle go to Cache.set.
use std.services::(cache)
@cache("user.{email}", ttl = 5m)
def loadUser(email string) !User {
return try db.fetchUser(email)
}
@cacheInvalidate
Cache · targets methods
@cacheInvalidate(key ...Glob)
@cacheInvalidate(key ...string)
Removes every key the selectors match once the method has run.
A pattern may interpolate the method's arguments.
@cacheInvalidate("user.{email}")
def renameUser(email string, name string) !none {
return try db.rename(email, name)
}
@config planned
Config · targets variables, fields
@config(key string, defaultValue ?any = none)
Fills the variable from the configuration key.
The value is converted to the variable's type. An optional variable reads none when the key is missing; a non-optional one with no default makes configuration loading fail.
use std.services::(config)
@config("server.port", 8080)
let port = 0
@trace planned
Debugger · targets functions, methods
@trace()
Records the function's calls while a trace is running.
Each call logs when it started, how long it took, who called it and what error it returned.
Tracing itself is started with Debugger.traceStart and stopped with Debugger.traceStop.
use std.services
@services.trace()
def handleRequest(id string) !none {
return try route(id)
}
@noInline planned
Debugger · targets functions, methods
@noInline()
Keeps the compiler from inlining the function.
@services.noInline()
def hotPath(n int) int {
return n * 2
}
@noOptimize planned
Debugger · targets functions, methods
@noOptimize()
Compiles the function without optimisation.
It is not inlined either, so a debugger sees it as written.
@services.noOptimize()
def underInvestigation(n int) int {
return n * 2
}
@trackCaller
Debugger · targets functions, methods
@trackCaller()
Reports the caller's location instead of the function's own in diagnostics.
For helpers that fail on the caller's behalf, so the message points at the call, not at the helper.
@services.trackCaller()
def logHere(message string) {
println("{__file_name__}:{__line__} {message}")
}
@watch planned
Debugger · targets fields, variables
@watch(mode WatchMode = WatchMode.Write)
Emits Debugger.watched on every access to the field.
mode picks reads, writes or both.
Every access becomes a call, so leave it out of release builds.
type Session {
@services.watch(WatchMode.Write)
token string
}
@metric
Diagnostics · targets fields
@metric(name string)
Registers a metric using the annotated field's metric type and assigns the resulting metric handle to the field.
If a metric with the same name and type already exists, the existing metric is used. Registration fails if the name is already registered with a different metric type.
The field’s own type selects the metric kind - no type argument is written.
use std.services::(metric)
use std.metrics::(Counter, Gauge)
type Uploads {
@metric("uploads.total")
total Counter
@metric("uploads.inflight")
inflight Gauge
}
@measureCount
Diagnostics · targets methods
@measureCount(name string)
Tracks how many times the annotated method is invoked.
Registers a Counter under the specified metric name and increments it once for every method invocation.
@measureCount("uploads.calls")
def upload(data byte[]) !none {
return try store(data)
}
@measureTime
Diagnostics · targets methods
@measureTime(name string)
Tracks the execution duration of the annotated method.
Registers a Histogram under the specified metric name and records the duration of every completed method invocation.
@measureTime("uploads.latency")
def upload(data byte[]) !none {
return try store(data)
}
@measureErrors
Diagnostics · targets methods
@measureErrors(name string)
Tracks failed executions of the annotated method.
Registers a Counter under the specified metric name and increments it when the method returns an error. The original error is propagated unchanged.
@measureErrors("uploads.failures")
def upload(data byte[]) !none {
return try store(data)
}
@measureConcurrency
Diagnostics · targets methods
@measureConcurrency(name string)
Tracks the number of concurrently executing invocations of the annotated method.
Registers a Gauge under the specified metric name. The gauge is incremented when the method begins execution and decremented when the method completes, including when the method returns an error.
@measureConcurrency("uploads.active")
def upload(data byte[]) !none {
return try store(data)
}
@log planned
Logging · targets functions, methods
@log(level LogLevel = LogLevel.Debug)
Writes a log entry each time the function is called.
The arguments go in as fields.
use std.services
use std.services::(LogLevel)
@services.log(LogLevel.Info)
def createOrder(id string) !none {
return try persist(id)
}
@logContext planned
Logging · targets types, functions, methods
@logContext(fields map<string, any>)
Attaches fields to every log entry written from the type's methods.
A closer @logContext or a field passed to the call itself wins on the same key.
@sensitive planned
Logging · targets parameters, fields, properties
@sensitive()
Marks a value that must not show up in developer output.
Logs, traces, watches, crash reports and the IDE inspector print it redacted.
struct Credentials { username string @sensitive() password string }
@log() def login(username string, @sensitive password string) {}
def login(email string, @services.sensitive() password string) !Session {
return try authenticate(email, password)
}
@requires planned
Policy · targets functions, methods
@requires(permissions string[])
@services.requires(["net.connect"])
def fetch(url string) !Response {
return try http.get(url)
}
@cron planned
Scheduler · targets functions
@cron(cronExpression string, name string = "")
Calls the function whenever the cron expression fires.
use std.services::(cron)
@cron("0 3 * * *")
def nightlyCleanup() {
purgeTempFiles()
}
@at planned
Scheduler · targets functions
@at(timestamp time.Time, name string = "")
Calls the function once, at the given time.
@after planned
Scheduler · targets functions
@after(interval duration, name string = "")
Calls the function once, after the duration.
@after(30s)
def warmUp() {
primeCaches()
}
@runEvery planned
Scheduler · targets functions
@runEvery(interval duration, name string = "")
Calls the function every interval.
@runEvery(5m)
def heartbeat() {
Logging.info("alive")
}