Skip to content

First-party `bynk` capabilities

Bynk ships a small set of capabilities with the compiler, under the reserved bynk namespace. You consume them like any capability — consumes the unit, then given the capability in the handlers that need it — but you never declare or provide them: the toolchain injects the implementation for the target platform. The bynk root namespace is reserved, so your own code can never collide with it.

There are two units:

UnitConsume withPortability
bynkconsumes bynk { … }Portable — the same source runs on the cloudflare and node platforms.
bynk.cloudflareconsumes bynk.cloudflare { … }Platform-locked — consuming it pins the deployment unit to Cloudflare.

For why a capability is the unit of outside-world access, see Understand the capability model; for the general capability / provides / given rules, see Capabilities & providers.

consumes bynk { … } brings these into scope. They are implemented identically on every platform (the host Date.now, crypto, fetch, console, environment), so code that stays on this surface is portable.

CapabilityOperations
Clocknow() -> Effect[Instant] — the current instant (an absolute point in time; epoch-millis under the hood).
Randomuuid() -> Effect[Uuid] · int(lo: Int, hi: Int) -> Effect[Int] (lo-inclusive, hi-exclusive).
Loggerinfo(msg: String) -> Effect[()] · error(msg: String) -> Effect[()].
Fetchsend(req: Request) -> Effect[Result[Response, FetchError]] — an outbound HTTP request.
Secretsget(name: String) -> Effect[Option[String]] — read configuration/secrets; None if unset.

The bynk unit also exports the transparent types these operations use:

type Uuid = String where Matches("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")
type Method = enum { Get, Post, Put, Delete }
type FetchError = enum { Network, Timeout }
type Request = {
method: Method,
url: String,
contentType: Option[String],
authorization: Option[String],
body: Option[String],
}
type Response = {
status: Int,
body: String,
}

The Cloudflare surface — bynk.cloudflare

Section titled “The Cloudflare surface — bynk.cloudflare”

consumes bynk.cloudflare { … } exposes the platform’s own infrastructure. Consuming it locks the deployment unit to Cloudflare (it cannot then target node), and the generated wrangler.toml gains the matching binding stanza.

CapabilityOperations
Kvget(key: String) -> Effect[Option[String]] · put(key: String, value: String) -> Effect[()] · putTtl(key: String, value: String, ttlSeconds: Int) -> Effect[()] · delete(key: String) -> Effect[()] · list(prefix: Option[String]) -> Effect[List[String]].

Kv is backed by a single Worker KV namespace bound as env.KV; the [[kv_namespaces]] stanza is derived for you.

Noteproducing queue messages (send/sendBatch) is not yet a first-party capability. Consuming a queue is a separate entry-point feature: see Process a queued message and the Queue reference.

Consume the unit, then grant the capability with given in each handler that calls it — exactly as you would a capability you declared yourself:

context greeter
consumes bynk { Clock, Logger }
service api from http {
on GET("/now") by Visitor () -> Effect[HttpResult[Int]] given Clock, Logger {
let t <- Clock.now()
let _ <- Logger.info("checked the clock")
Ok(t.toEpochMillis())
}
}

The Cloudflare surface is consumed the same way — consumes bynk.cloudflare { Kv } and given Kv — with the portability trade-off noted above. To configure a first-party capability (an API key for Fetch, say), read it from Secrets rather than passing it as an argument; Wrap a library as an adapter shows the pattern.

Beyond capabilities, the bynk namespace also ships pure commons you bring in with uses (not consumes) — bynk.list and bynk.map (combinators over the List/Map kernels) and bynk.string (string helpers). These are ordinary functions with no effects; see the type system reference.

Deprecated (v0.91, ADR 0116 D6): the bynk.list free functions whose method forms now exist — map, filter, find, any, all — emit a non-failing bynk.list.deprecated_function warning at each call site (the build still succeeds) with a machine-applicable fix to the method form: map(xs, f)xs.map(f), find(xs, p)xs.filter(p).first(), and so on. Prefer the List methods. reverse and traverse keep their free-function form (no method equivalent yet).

See also: Capabilities & providers, Adapters, Understand the capability model.