# calog script API reference Every function below is a **native** that calog registers into each engine, so a script in any language can call it. This reference covers the natives the `calog` runner and its libraries expose. (For the C embedding API -- `calogCreate`, `calogRegister`, `calogFnInvoke`, etc. -- see the README and `src/calog.h`.) ## Conventions - **Calling syntax per engine.** Most engines call a native by its bare name -- `cryptoUuid()`, `kvSet("k", 1)`. Two differ: - **Wren**: `Calog.call("name", [args])`, e.g. `Calog.call("kvSet", ["k", 1])`. - **Scheme (s7)**: s-expression form, `(kvSet "k" 1)`. - **Output & exit** (provided by the `calog` runner): `calogPrint(...)` writes to stdout; `calogExit([code])` tears everything down and exits. calog is event-driven, so a script must call `calogExit` (or be interrupted) to end -- a finished top level does not exit. - **Values.** Arguments and results marshal through one canonical type: nil, bool, integer, real, string, list, and map (keyed record). Strings are **binary-safe** (may contain embedded NULs) everywhere the underlying library allows it. - **Handles** (db connections, sockets, ssh sessions) are opaque values owned by the context that created them; do not share a live handle across contexts. - **Callbacks.** Natives that take a *function* argument (`psSubscribe`, `timerAfter`, `timerEvery`, `calogExport`) accept a first-class function value. All engines support this, including my-basic (a top-level `def` or `lambda`; see `vendor/ourbasic`). - **Availability.** Every library in this reference is compiled into `bin/calog`: crypto, json, kv, fs, time, timer, export, pubsub, task, net (TCP / UDP / ENet), db (SQLite / PostgreSQL / MySQL), http, and ssh. ssh needs a reachable server; http needs a reachable endpoint. --- ## Runner (`calog` binary) | Function | Description | |---|---| | `calogPrint(...)` | Write each argument to stdout, space-separated, with a trailing newline. | | `calogExit([code])` | Tear down the runtime and exit the process with `code` (default `0`). | ## crypto Binary-safe cryptographic primitives over OpenSSL. | Function | Description | |---|---| | `cryptoHashSha256(data) -> hex` | SHA-256 as a 64-char lowercase hex digest. | | `cryptoHashSha1(data) -> hex` | SHA-1 as a 40-char lowercase hex digest. | | `cryptoHmacSha256(key, data) -> hex` | HMAC-SHA-256 as 64-char lowercase hex. | | `cryptoRandomBytes(count) -> bytes` | `count` cryptographically-random bytes (binary string). | | `cryptoBase64Encode(data) -> text` | Base64-encode. | | `cryptoBase64Decode(text) -> data` | Base64-decode (trailing whitespace tolerated). | | `cryptoHexEncode(data) -> text` | Lowercase hex encode. | | `cryptoHexDecode(hexText) -> data` | Hex decode (case-insensitive). | | `cryptoUuid() -> string` | A random RFC 4122 version-4 UUID string. | ## db SQL over SQLite, PostgreSQL, and MySQL/MariaDB. Parameters are always **bound** (never string-spliced), so queries are injection-safe. Values marshal as: NULL <-> nil, integers/ reals as-is, text and BLOBs as binary-safe strings. | Function | Description | |---|---| | `dbOpen(driver, conn) -> handle` | Open a connection. `driver` is `"sqlite"`, `"postgres"`, or `"mysql"`. `conn` is a SQLite path or `":memory:"`, a libpq conninfo, or a MySQL `key=value ...` string. | | `dbExec(handle, sql, ...params) -> rowsAffected` | Run a non-query statement with bound params; returns rows affected. | | `dbQuery(handle, sql, ...params) -> rows` | Run a query; returns a list of `{column: value}` row maps. | | `dbClose(handle)` | Close the connection. | ## export Share a function by name across contexts and engines. | Function | Description | |---|---| | `calogExport(name, fn)` | Publish function `fn` under a global `name`. | | `calogUnexport(name)` | Remove an exported name. | | `calogCall(name, ...args) -> result` | Call an exported function by name -- works in **every** engine. (On hook engines -- Lua/JS/Squirrel/s7 -- an export is also reachable by its bare name.) | ## fs POSIX filesystem access. A failed operation raises a catchable script error carrying `strerror(errno)`. | Function | Description | |---|---| | `fsRead(path) -> string` | Read a whole file (binary-safe). | | `fsWrite(path, data)` | Create/truncate and write `data`. | | `fsAppend(path, data)` | Create if absent, append at the end. | | `fsExists(path) -> bool` | Whether the path exists. | | `fsRemove(path)` | Unlink a file. | | `fsMkdir(path)` | Create one directory level (existing dir is OK). | | `fsList(path) -> list` | Entry name strings, excluding `.` and `..`. | | `fsStat(path) -> map` | `{size, isDir, isFile, mtime}`, or nil if the path is absent. | ## http Minimal HTTP/1.1 client over `http://` and `https://`. Each call is its own connection (`Connection: close`); redirects are not followed. `https://` verifies the server certificate against the system CA store by default. | Function | Description | |---|---| | `httpGet(url) -> map` | GET a URL. Returns `{status, body, headers}` (headers keyed by lowercased name). | | `httpRequest(opts) -> map` | `opts` is `{method (default "GET"), url, headers (map), body, insecure (bool)}`. `insecure=true` skips TLS verification. Returns `{status, body, headers}`. | ## json | Function | Description | |---|---| | `jsonParse(text) -> value` | Parse JSON: object -> map, array -> list, number -> int or real, string, true/false, null -> nil. | | `jsonStringify(value) -> text` | Serialize a value to compact JSON text. | ## kv A process-wide, thread-safe store shared by every context and engine. Holds **data only** (a function value is rejected). Keys are binary-safe. | Function | Description | |---|---| | `kvSet(key, value)` | Store a deep copy of `value` under `key` (replaces any existing). | | `kvGet(key) -> value` | A deep copy of the stored value, or nil if absent. | | `kvHas(key) -> bool` | Whether the key is present. | | `kvDelete(key)` | Remove the key (no error if absent). | | `kvKeys() -> list` | A list of the stored keys (strings). | ## net Three first-class transports -- **TCP**, **UDP**, and **ENet** (reliable/ordered delivery over UDP) -- all always available. Payloads are binary-safe strings. Blocking calls (`tcpAccept`/`tcpRecv`/`udpRecvFrom`/`enetService`) stall only the calling context's thread. TCP and UDP: | Function | Description | |---|---| | `tcpConnect(host, port) -> handle` | Connect to a TCP server. | | `tcpListen(port) -> handle` | Listen on a TCP port. | | `tcpAccept(handle) -> handle` | Block for a client; returns a connection handle. | | `tcpSend(handle, data) -> bytesSent` | Send all of `data`. | | `tcpRecv(handle, maxBytes) -> data` | Read up to `maxBytes`; nil at end of stream. | | `tcpClose(handle)` | Close a socket. | | `udpOpen(port) -> handle` | Open a UDP socket (`port` 0 = ephemeral). | | `udpSendTo(handle, host, port, data) -> bytesSent` | Send a datagram. | | `udpRecvFrom(handle, maxBytes) -> map` | Receive one datagram: `{data, host, port}`. | | `udpClose(handle)` | Close a UDP socket. | ENet (reliable UDP -- ordered, reliable channels over UDP): | Function | Description | |---|---| | `enetHost(port, maxPeers) -> hostHandle` | Create an ENet host. | | `enetConnect(hostHandle, host, port, channels) -> peerHandle` | Initiate a connection to a peer. | | `enetService(hostHandle, timeoutMs) -> event` | Poll for one event within `timeoutMs`. Returns `{type, ...}` where `type` is `"none"`, `"connect"`, `"receive"` (with `peer`, `channel`, `data`), or `"disconnect"`. | | `enetSend(peerHandle, channel, data, reliable)` | Queue a packet on a channel; `reliable` is a bool. | | `enetDisconnect(peerHandle)` | Begin disconnecting a peer. | | `enetClose(hostHandle)` | Destroy an ENet host. | ## pubsub Deliver a message to every subscriber of a topic, across contexts and engines. Delivery is synchronous; each subscriber runs on its own context's thread and gets a deep copy of the message. Keep publish graphs acyclic. | Function | Description | |---|---| | `psSubscribe(topic, fn) -> id` | Register `fn` to receive messages published on `topic`. | | `psUnsubscribe(id)` | Drop the subscription with that id. | | `psPublish(topic, msg) -> count` | Deliver a copy of `msg` to every subscriber; returns how many were invoked. | ## ssh SSH/SFTP over libssh2. Requires a reachable SSH server. Payloads are binary-safe. | Function | Description | |---|---| | `sshConnect(host[, port]) -> handle` | Connect (port defaults to 22). | | `sshAuthPassword(handle, user, password) -> bool` | Password authentication. | | `sshAuthKey(handle, user, privateKeyPath[, publicKeyPath, passphrase]) -> bool` | Public-key authentication. | | `sshExec(handle, command) -> map` | Run a remote command: `{stdout, stderr, exitCode}`. | | `sshClose(handle)` | Close the session. | | `sftpGet(handle, remotePath) -> data` | Read a remote file whole (binary-safe). | | `sftpPut(handle, remotePath, data)` | Create/truncate a remote file (mode 0644). | | `sftpList(handle, path) -> list` | `[{name, size, isDir}, ...]`. | | `sftpStat(handle, path) -> map` | `{size, isDir}`, or nil if the path is missing. | | `sftpRemove(handle, path)` | Remove a remote file. | | `sftpMkdir(handle, path)` | Create a remote directory (mode 0755). | ## task Launch and manage other calog script contexts. Tasks are fire-and-forget: a spawned context runs on its own thread; results come back through host natives or the shared kv/pubsub. A task is owned by the context that spawned it, and only that owner may `taskEval`/`taskClose`. | Function | Description | |---|---| | `taskSpawn(engine, code) -> handle` | Run a code string on a named engine (`"lua"`, `"javascript"`, `"squirrel"`, `"mybasic"`, `"berry"`, `"scheme"`, `"wren"`). | | `taskLoad(baseName) -> handle` | Launch a script *file* (engine chosen by extension). | | `taskEval(handle, code)` | Feed more code into a running task (runs on its thread). | | `taskClose(handle)` | Stop a task (cooperative: waits for its thread to exit). | | `taskSelf() -> id` | The calling script's own context id. | | `taskCount() -> n` | Number of tasks this library currently holds open. | ## time | Function | Description | |---|---| | `timeNow() -> real` | Wall-clock epoch seconds, fractional (CLOCK_REALTIME). | | `timeMonotonic() -> real` | Seconds from an unspecified origin (CLOCK_MONOTONIC); use for intervals. | | `timeSleep(ms)` | Block the calling context for `ms` milliseconds. | ## timer One background thread drives every timer; each callback runs on the context that created the timer. | Function | Description | |---|---| | `timerAfter(ms, fn) -> id` | Fire `fn` once, `ms` milliseconds from now. | | `timerEvery(ms, fn) -> id` | Fire `fn` every `ms` milliseconds. | | `timerCancel(id)` | Stop a pending or repeating timer. |