Expand description
cratefield-core is the runtime-agnostic kernel of the Factory Zero harness:
the Module contract, the Harness builder, port traits, RFC 9457
problem+json errors, the request Scope, an in-process EventBus and
a TemplateRegistry (ADR 0001, 0002, 0007).
Core depends only on http, axum (default features off), serde,
tracing, sea-query and pure-Rust crypto. It must never depend on
worker, wasm-bindgen, tokio, reqwest, sqlx or rusqlite, and
never touches std::fs or std::net — CI enforces this with a
cargo tree check and the wasm build of examples/venture.
cratefield.com · HARNESS · the open-source core
§The harness
Every product needs a backend, and almost none of them should be built from scratch. This is that backend, once.
A Rust harness you compile your own backend from: pick module crates, wire adapters, ship one stateless Worker with its own database. Cloudflare D1 today, a self-hosted native binary later, with no module rewrites in between.
This repository is the open-source core, MIT, and it is complete enough to run yourself today. Cratefield is the managed service being built on top of it: builds, migrations, secrets, domains and monitoring, so you do not have to operate any of it. That service is not built yet, and the site says so on every page.
Modules only see ports. A module never touches a Cloudflare binding, an environment variable, or a vendor client. It asks for a
Database, aMailer, aCaptcha. Adapters answer. That one rule is what makes the later move off Cloudflare a change of a single runtime crate.
Read docs/ARCHITECTURE.md for the full design. Decisions, including why the TypeScript attempt was thrown away, are in docs/adr. Security controls and reporting: docs/SECURITY.md. What we store and for how long: docs/PRIVACY.md. Which module version runs on which core: docs/COMPATIBILITY.md, generated and drift-checked in CI. How crates reach crates.io: docs/RELEASING.md.
§How a venture uses it
// src/harness.rs in a venture repo
Harness::builder()
.venture(Venture::new("factory0", "factory0.ventures")
.public_url("https://factory0.ventures")
.cors_origins(["https://factory0.ventures"]))
.module(EmailSignup::new().double_opt_in(true))
.module(Waitlist::new().products(["kontinuum", "undercover-rockstars"]))
.runtime(Cloudflare::new()
.db("DB")
.mailer(Resend::from_env())
.captcha(Turnstile::from_env()))
.build()?That is the whole composition. build() refuses a module that requires a port
the runtime does not provide, two modules claiming the same table or route, or
a module built against a different contract version. The venture template runs
it under cargo test, so a misconfiguration fails before wrangler deploy can.
§Shape
%%{init: {"theme":"base","themeVariables":{
"background":"transparent",
"fontFamily":"ui-monospace, SFMono-Regular, Menlo, monospace",
"fontSize":"13px",
"primaryColor":"#141416","primaryTextColor":"#EDEBE6","primaryBorderColor":"#3A3A3F",
"lineColor":"#6E6E76","textColor":"#8A8A8E",
"clusterBkg":"transparent","clusterBorder":"#3A3A3F",
"edgeLabelBackground":"#0E0E10"
}} }%%
flowchart LR
REQ(["HTTPS<br/>request"]):::req --> H
subgraph V["ONE VENTURE · ONE BINARY · ONE DATABASE"]
H["<b>Harness</b><br/>axum router<br/>/v1/<module>"]:::core
M1["email-signup"]:::mod
M2["waitlist"]:::mod
MX["your module"]:::ghost
P{{"<b>ports</b><br/>Database · Mailer<br/>Captcha · RateLimiter<br/>Signer · KeyValue"}}:::port
H --> M1 & M2 & MX --> P
end
subgraph A["ADAPTERS · THE ONLY VENDOR-AWARE CODE"]
DB[("D1")]:::vendor
KV[("KV")]:::vendor
RS["Resend"]:::vendor
TS["Turnstile"]:::vendor
PG[("Postgres<br/>phase 3")]:::future
end
P --> DB & KV & RS & TS
P -. "runtime-native" .-> PG
classDef req fill:#0E0E10,stroke:#4C6FFF,stroke-width:1.5px,color:#EDEBE6
classDef core fill:#141416,stroke:#4C6FFF,stroke-width:1.5px,color:#EDEBE6
classDef mod fill:#0E0E10,stroke:#3A3A3F,color:#EDEBE6
classDef ghost fill:transparent,stroke:#55555A,stroke-dasharray:4 3,color:#8A8A8E
classDef port fill:#141416,stroke:#EDEBE6,stroke-width:1.5px,color:#EDEBE6
classDef vendor fill:#0E0E10,stroke:#3A3A3F,color:#A9A8A5
classDef future fill:transparent,stroke:#55555A,stroke-dasharray:4 3,color:#8A8A8E§Crates
All public crates are cratefield-*, MIT, plus the cratefield facade that
pulls them together. Nothing is published to crates.io yet; depend on this
repository by git.
Most ventures want one line:
cratefield = { version = "0.1", features = ["cloudflare", "resend", "waitlist"] }The individual crates stay available and are the same types; the facade is a convenience, not a layer.
These crates were
factory0-*until the first release. Renaming a published crate breaks every consumer, so the rename had exactly one free moment: before anything reached crates.io. It was taken then (ADR 0011). Private modules stayfz-*and stay unpublished.
| Crate | Role |
|---|---|
cratefield | The facade: one dependency that re-exports the core and pulls in a runtime, adapters and modules by feature (ADR 0011, 0012). Start here |
cratefield-core | Module trait, Harness builder, port traits, problem+json errors, request scope, event bus, templates |
cratefield-runtime-cloudflare | workers-rs entry points; D1, KV, Rate Limiting and wait_until mapped to ports |
cratefield-adapter-resend | Mailer over the Resend REST API, with a NotConfigured mode until a sending domain is verified |
cratefield-adapter-turnstile | Captcha over Cloudflare Turnstile, fail-closed |
cratefield-adapter-sqlite | Database over rusqlite: every test, and single-node self-hosting |
cratefield-module-email-signup | Email signup with double opt-in, unsubscribe, admin export |
cratefield-module-waitlist | Per-product waitlist with confirm, position, referral codes |
cratefield-secrets | Envelope-encrypted secrets over the Database port, two tiers, ciphertexts bound to their row (#39) |
cratefield-kms | The KMS port: wrap and unwrap data keys, with a local-file provider that refuses production (ADR 0102) |
cratefield-ui | Renders the module surface as HTML at /ui: pages, fragments, in-process form dispatch, the cf-* styling contract (ADR 0010) |
cratefield-cli | Binary fz: migrations collect, doctor, modules |
cratefield-testing | Conformance kit every module, public or private, must pass |
cratefield-adapter-postgres | Phase 3. Database over sqlx for the native runtime |
cratefield-runtime-native | Phase 3. The same harness as a single binary on tokio |
Private modules are fz-* crates in
harness-private, consumed as
pinned git dependencies. New ventures start from
venture-backend-template.
The first consumer is
factory0-backend.
§What a module is
A crate implementing one trait.
pub trait Module: Send + Sync + 'static {
fn name(&self) -> &'static str; // mounted at /v1/<name>
fn requires(&self) -> &'static [Port]; // build fails if one is missing
fn migrations(&self) -> Migrations; // include_str! SQL, portable subset
fn router(&self, ctx: ModuleContext) -> axum::Router;
// version, optional ports, tables, events, scheduled …
}A module is mounted one of two ways, and a caller cannot tell which. Compiled
in is the default this README describes: the crate is linked into the Worker.
Sidecar gives one module its own Worker, built and deployed separately and
mounted at the same /v1/<name> over a Cloudflare service binding, binding the
same database and secrets. It exists so a module whose source should not enter
the shared artifact can still run as a real module with real ports. Designed,
not built: epic #56.
Migrations are plain SQL in a subset SQLite and Postgres both accept. Queries go through sea-query, which renders for either. Confirmation and unsubscribe links are HMAC-signed tokens with key rotation, so there is no session store. Request scope travels in axum extensions, never in shared state; the conformance kit includes the concurrent-request test that proves it.
§Roadmap
| Milestone | Contents | Issues |
|---|---|---|
| M0 Foundation | workspace tooling, core, Cloudflare runtime, Resend and Turnstile adapters, SQLite adapter, fz, testing kit | #1–#9 |
| M1 First modules | email-signup, waitlist, templates, security baseline, observability | #10–#14 |
| M2 First venture live | crates.io publishing, docs, contract versioning, api.factory0.ventures | #15–#17 |
| M3 Self-hosted portability | Postgres adapter, native runtime, parity suite, data move | #18–#21 |
Three epics sit outside the milestones because they are specified but not scheduled: #23 multi-tenant schema, #24 embedded secrets, and #56 custom modules without rebuilding the shared bundle.
Progress is visible in the milestones.
§Observability
One structured span per request carries request_id, method, route
(the matched path), module, status, duration_ms, ip_hash and
ua_family — never an email address. Workers Logs is enabled in the
template wrangler.toml ([observability] enabled = true); every
response also echoes x-request-id. To pull one request’s trail out of
the logs, filter on the id the API returned:
wrangler tail --format pretty --search <request-id>The error taxonomy (every problem slug, status and meaning) is
docs/ERRORS.md, generated from cratefield-core’s registry and checked
in CI for drift.
§Toolchain
Stable Rust pinned in rust-toolchain.toml, target wasm32-unknown-unknown,
worker-build, wrangler. CI runs
fmt, clippy -D warnings, test, cargo deny, and builds the example
venture to wasm so a native-only dependency cannot slip into a module.
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
(cd examples/venture && worker-build --release)§Layout
crates/
core/ cratefield-core
runtime-cloudflare/ cratefield-runtime-cloudflare
adapter-resend/ cratefield-adapter-resend
adapter-turnstile/ cratefield-adapter-turnstile
adapter-sqlite/ cratefield-adapter-sqlite
module-email-signup/ cratefield-module-email-signup
module-waitlist/ cratefield-module-waitlist
kms/ cratefield-kms
secrets/ cratefield-secrets
ui/ cratefield-ui
cli/ cratefield-cli → fz
testing/ cratefield-testing
examples/
venture/ smallest complete venture; CI builds it to wasm
docs/
ARCHITECTURE.md
KEY-ROTATION.md rotating data keys and re-wrapping under a new master key
MIGRATION-STREAMS.md two repositories applying migrations to one database
RECONCILIATION.md boot-time reconciliation across tenant databases
MOUNTING.md compile a module in, or run it as a sidecar
UI.md the UI surface, its markup contract, UiSpec, admin
ui-llms.txt the same contract written for a generator
adr/ 0000 … 0010
tools/
banner-render.html source of the README banner
render-banner.sh regenerates it with headless Chrome§License
MIT. Built in the open for Cratefield, a Factory Zero venture.
Structs§
- Action
- One route the module serves, described for a renderer.
- Blob
Object - A stored object: its bytes and the content type to serve it with.
- Brand
- Venture branding for mail templates (issue #12). Defaults are text-only: factory-zero orange accent, no logo, no footer line.
- Charge
- A created charge/payment-intent and its status as Stripe reported it.
- Checkout
Request - A one-time hosted checkout (Stripe Checkout in
paymentmode). - Checkout
Session - The hosted page to send the browser to, and the session id to reconcile on.
- Column
- A column of a
View::Table. - Config
Error - Accumulates every configuration problem so
Harness::buildcan report them together instead of one at a time. - Connect
Account Link - The Connect account id (persist it) and the hosted onboarding URL.
- Connect
Account Link Request - Onboards a Connect account (a coach) and returns a hosted onboarding link.
- Decision
- Empty
Config - A configuration that always returns
None(tests, offline builds). - Event
Bus - Registry of handlers, built once by
Harness::buildfrom every module’sevents(). Cheap to clone (oneArc). - Form
- A form (
application/x-www-form-urlencoded) extractor whose rejections are problem+json with the same shape asJson’s: body reads fail through the shared 413 slug (the size limit), everything else is a 400 validation problem. Needed for cross-siteform_postcallbacks (issue #46). - Harness
- A built harness: immutable after
build(). - Harness
Builder - Builder:
.venture(..),.module(..),.runtime(..),.template(..), then.build(). - Harness
Config - The harness-level keys, parsed once from the environment
Config(issue #3):HARNESS_SECRET(required, ≥ 32 bytes),HARNESS_SECRET_PREVIOUS(optional),ADMIN_TOKEN(optional),ENV(development|staging|production, defaultdevelopment). - Hmac
Signer - HMAC-SHA256 signer over
HARNESS_SECRET(+ optional previous). - Json
- A
Jsonextractor and response whose rejections and serializations are problem+json (architecture section 6). Deserialization failures become a400 validation-failedproblem listing the field. - Line
Item - One line on a checkout: a name shown to the buyer and its price.
- MapConfig
- A
Configbacked by a map (tests,fz doctorwith process env). - Message
- An outbound mail.
textis always sent alongsidehtml. - Migrations
- The module’s migrations, per dialect.
postgresdiffers fromsqliteonly where the SQL truly differs (ADR 0004). - Module
Config - Typed view over a
Configfor one module: prefixes every key with the module name inSCREAMING_SNAKEand parses values with defaults (issue #3). - Module
Context - Everything a module’s router needs: its declared ports, the typed config, the bus, the templates and the venture identity.
- Module
Surface - One module’s entry in the composed document.
- Money
- An amount in a currency’s minor units (cents), the way Stripe takes and
reports money.
currencyis a lowercase ISO-4217 code ("usd"). - Noop
Defer - Drops deferred futures with a warning. Used when no runtime defer is available; tests that assert on deferred work supply their own.
- Notification
- One notification.
datais the custom key-value payload the app reads;collapse_idcoalesces notifications the user has not seen yet. - Payload
- The signed payload:
{ purpose, subject, exp?, kid }. - Ports
- The per-request bundle of resolved port implementations plus the typed config the runtime built from environment/secrets.
- Problem
- An API error, serialized as
application/problem+json. - Problem
Def - Definition of one problem slug.
- Redacting
Visitor - A
tracingfield visitor that records(name, redacted value)pairs into a map. Runtimes use it in their formatters; tests use it to prove the redaction rules. - Refund
- A created refund.
- Refund
Request - A refund of a prior payment: the whole amount when
amountisNone, else a partial refund. - Rendered
- A rendered mail, ready for
Message. - Rendered
Surface - A document serialized once, with the strong
ETagclients revalidate against. Built atHarness::buildfor both the public and the admin variant. - Row
- One result row: ordered
(column name, value)pairs. - Rows
- A small owned row model. No engine types leak past this point.
- Scope
- Per-request scope, inserted into extensions by the request-id layer
(issue #2). Handlers receive it through the
Scopeextractor; there is no ambient “current request”. - Scoped
Blob - Wraps a
Blobso every key is prefixed with<module>/and no key can escape it. The harness applies this inPorts::view_for, so a module sees a store scoped to itself — the blob equivalent of the table-ownership check. - Sidecar
Mount - One mounted sidecar.
- Sidecar
Mounts - The mount table, parsed from configuration.
- SqlMigration
- One migration step, embedded with
include_str!fromcrates/<module>/migrations/<dialect>/NNNN_name.sql(issue #8). - Statement
- A rendered SQL statement:
(sql, values)with?placeholders, produced by rendering a sea-query query for a dialect. Modules build queries with sea-query and render through the helpers on this type (or let adapters do it); adapters bindvaluespositionally. - Subscription
Checkout Request - A recurring hosted checkout (Stripe Checkout in
subscriptionmode) against a Stripe Price the venture configured (e.g.$15/mowith a trial). - Surface
- What a module declares from
Module::surface. - Surface
Document - The document
GET /__surfaceserves: composed atHarness::build, one entry per module in mount order, modules with an empty surface omitted. - System
Clock - Real wall clock (
timecrate). Its timeout runs futures to completion — tests that need a real timeout supply their own clock. - Template
Registry - Immutable registry: venture overrides are inserted after module defaults
at
Harness::build, so they win on id collision. - Transfer
Charge - A destination charge with an application fee: the buyer is charged
amount,application_feeis kept by the platform, and the remainder is transferred todestination_account(the coach’s Connect account). - UiContext
- What a UI renderer gets from the harness (ADR 0010). Built by
Harness::routerfor every router it assembles. - Ulid
IdGen - Real ULID generator (monotonic per process).
- Venture
- Identity and CORS configuration for the venture this harness serves.
- Venture
Surface - The venture identity a renderer needs.
- Verdict
- A captcha verification verdict.
ok: falsewith areasonfrom the provider’serror-codes; transport-level unavailability surfaces asok: false, reason: "unavailable"unless the adapter is configured fail-open (staging only). - Webhook
Event - A webhook event the adapter has verified (signature + timestamp) before
returning.
kindis Stripe’s event type ("checkout.session.completed");datais the event’sdata.objectfor the module to interpret.
Enums§
- Audience
- Who an action is for. Drives the public/admin split of
/__surfaceand, in the renderer, which pages need the admin session. - Blob
Error - Blob store failures.
- Captcha
Error - DbError
- Database failures, sanitized for logs and problem details.
- Dispatch
Error - Http
Error - Kid
- Which secret a token was signed with. Tokens name their key so rotation never breaks links in flight.
- KvError
- Mail
Error - Mailer failures, mapped by the adapter from provider responses.
- Outcome
- What the browser should do with a successful response.
- Payments
Error - Payment failures.
NotConfiguredlets a venture build and run without Stripe (the port reports it rather than erroring); the rest map an upstream failure.SignatureInvalidis separated so a webhook handler answers400and never processes an unverified event. - Port
- Every port a module can declare in
requires()/optional()(architecture section 4). - Priority
- How urgently the notification should be delivered. Maps to APNs priority
10(deliver now, may wake the device) and5(deliver to save power). - Push
Error - Push failures.
Unregisteredis separated because the caller must act on it — the device token is dead and should be pruned — where the others are transient or a bad request. - Push
Outcome - The result of a send that the provider accepted.
- Rate
Limit Error - Send
Outcome - Result of a send attempt.
- Signature
Error - Failures surfaced by
verifybeyond “the token is simply invalid”, which is reported asNone. - Signer
Error - Errors from constructing an
HmacSigner. - Template
Error - Venture
Env - Deployment environment. Mirrors the
ENVconfig key;Productiondrives the mandatory-captcha rule (architecture section 11). - View
- How actions compose into something to render.
Constants§
- FORMULA_
PREFIXES - Characters that make a cell a formula when it starts with one of them.
- HARNESS_
API - Contract version shared by core and every module.
Harness::buildrejects modules whoseharness_apidiffers. Bumped only on breaking contract changes;cratefield-core’s major follows it. - HARNESS_
SIDECARS - Config key holding the mount table, a JSON object of
{"<module name>": "<service binding>"}. - HINT_
KEYWORDS - The
x-cf-*extension keywords the renderer understands on a field schema. Anything else underx-cf-is ignored, never an error, so a module can target a newer renderer than the one that serves it. - MAX_
BODY_ BYTES - Default request body limit for
/v1/*JSON endpoints. - MAX_
EMAIL_ BYTES - The maximum accepted address length in bytes (RFC 5321 “forward-path”).
- MAX_
LOCAL_ BYTES - The maximum local-part length in bytes (RFC 5321).
- MIN_
SECRET_ BYTES - Minimum secret length.
HARNESS_SECRETmust be at least 32 bytes. - SLUGS
- SURFACE_
API - Contract version of the surface document, independent of
HARNESS_API: a renderer or the control plane checks it before reading the document. - X_
HARNESS_ API - Contract version stamped on every harness response, checked by the host on every forwarded response. Stamping beats a cold-start handshake because an isolate outlives a sidecar redeploy (ADR 0009).
- X_
HARNESS_ MODULE - Module name stamped alongside
X_HARNESS_API. - X_
REQUEST_ ID x-request-id: accepted from the client when it matches^[A-Za-z0-9_-]{8,128}$, otherwise generated as a ULID. Always set on the response (architecture section 6).
Traits§
- Blob
- A blob store. Keys are module-prefixed; the harness wraps this in a
ScopedBlobper module so a module cannot name another’s objects. - Captcha
- Clock
- Config
- Read-only key/value configuration, resolved per runtime from environment
variables and secrets (Workers
Env) or the process environment. - Database
- Execute statements against the venture database. Implementations: D1 (Workers), rusqlite (tests, self-hosted), Postgres (phase 3).
- Defer
- Dispatcher
- Http
Client - IdGen
- KeyValue
- Mailer
- Module
- A Factory Zero module. Object-safe; composed as
Arc<dyn Module>. - Payments
- Moves money for a venture. Stripe today; the trait names only Stripe identifiers and hosted URLs, never card data.
- Push
- Sends notifications to a device. APNs today, FCM later; both over the
runtime’s
HttpClient. - Rate
Limiter - Runtime
- A runtime resolves environment bindings into
Portsand declares statically which ports it can provide, soHarness::buildcan reject a module that requires something the runtime will never hand it (ADR 0002). Reference implementation:cratefield-runtime-cloudflare. - Signer
- Produces and verifies
base64url(json).base64url(mac)tokens where the MAC is computed over the encoded payload string, so a token has exactly one valid encoding (ADR 0006). - Surface
Source - Where the current surface comes from (issue #76). With no sidecar
mounted this is the document composed at build; with sidecars, each
call fetches every mounted sidecar’s
/__surface(public part) and merges it in, so a sidecar redeploy is seen on the next request (ADR 0009). An unreachable sidecar contributes nothing and is logged. - Template
- One template.
datais the caller’s JSON payload;localeis the requested locale tag (en,de, …) used by the implementation for its own variants. - TryFrom
Value - Conversion from a sea-query
SeaValuefor typed row access. - UiMount
- A renderer the venture mounts at
/uiwithHarnessBuilder::ui(ADR 0010). Core defines the seam;cratefield-uiis the implementation, kept out of core so a venture without a UI carries nomaud.
Functions§
- bearer_
token - Extracts the bearer token from
Authorization: Bearer <token>. - card_
data_ hit - The first card-data fragment
textcontains (case-insensitive), orNone. Keeps card numbers, verification codes and full expiry out of migrations and secret names — with a normal Stripe integration none of them should exist (issue #44). - client_
ip - The client IP for rate limiting, from the headers.
- constant_
time_ eq - Constant-time equality of two secrets, via fixed-length digests so timing does not leak the configured token’s length.
- csv_
escape - Escapes one CSV field: formula-guard, then RFC 4180 quoting.
- csv_row
- Escapes and joins one CSV row, with a trailing newline.
- harness_
api_ mismatch - The message
Harness::buildandfz doctorreport for a module whoseModule::harness_apidiffers from core’s: it names the module, the module crate’s version, the API it targets, and thecratefield-corecrate with its version and API (issue #17). - hint_
field - Sets one
x-cf-*(or any) keyword on a field of an object schema after derivation, for hints that only exist at runtime: aselectwhose options are the configured product list. Unknown fields are ignored so a rename in the body type cannot panic at build. - invalid_
email_ problem - A
400 validation-failedproblem for a rejected address. - is_
email_ field - Whether a field is expected to carry an email address.
- is_
secret_ field - Whether a field name marks a secret: matches
(?i)secret|token|key|authorization|password. - is_
valid - A conservative validator: non-empty, one
@, sane lengths, an ASCII local part from the unreserved set, and a dot-separated alphanumeric domain with no empty or hyphen-edge labels. - lint_
card_ data - Card-data column or table names found in
sql, as(fragment, why)pairs. Comments and string literals are ignored, so documenting the rule does not trip it. - lint_
portable_ sql - Returns
(token, explanation)pairs found insql. - migration_
checksum - The sha256 of a migration’s SQL, lowercase hex. Recorded in
harness_migrationswhen the migration is applied, so a later run can tell “already applied” from “applied, then edited” — the rule forward-only migrations rest on, enforced by the database rather than by a lockfile in one repository (issues #28, #34). - migration_
edited - The message a migration whose recorded checksum no longer matches gets. Shared so both engines say the same thing.
- normalize_
email - Trim, Unicode NFC normalise, then lowercase. Idempotent.
- problem_
registry - Every core slug definition, for tests and docs.
- rate_
limit_ keys - The rate-limit keys for one request: always
ip:<ip>(orip:unknownwhen no address is visible), plusemail:<normalized>when an address is known. The limiter is consulted per key, in order. - rate_
limited - A
429 rate-limitedproblem carryingRetry-After: <seconds>when the limiter reported a pause (architecture section 6). - redacted_
value - How one recorded field is stored:
[redacted]for secrets, the hash for emails, the value otherwise. - request_
id_ is_ valid - The character class and length bounds of an accepted request id.
- require_
admin - Checks
Authorization: Bearer <ADMIN_TOKEN>for one admin request. - schema_
for - Generates the schema for
Tthe way every action does: draft 2020-12, definitions inlined so a renderer never has to resolve$ref. - set_
error_ forwarder - Installs a process-wide forwarder for internal-error diagnostics (architecture section 11).
- subject_
hash - The redacted form of an email-ish value: its SHA-256 digest, 12 hex
characters, no
@ever reaches the logs. - timeout
- Typed wrapper over
Clock::timeout_any.Nonemeans the clock abandoned the future afterafter. - validation_
error - The reason an address is rejected, for problem
details.
Type Aliases§
- AnyError
- Error type for handler and scheduled-work results.
- BoxFuture
- An owned dynamically typed
Futurefor use in cases where you can’t statically type your result or need to add some indirection. - Event
Handler - A registered handler: receives the emitting request’s scope and the payload.
- Event
Name - Event names are
"<module>.<event>", e.g.waitlist.confirmed.