Documentation
¶
Overview ¶
Package id is the one place bex mints and validates typed resource ids (docs/ADR020-identifiers.md — the ADR). A bex id is "<prefix>-<20-char xid>", e.g. "srv-c185th5c2rvvnhbfiltg": a short greppable type prefix, a hyphen, then an xid (k-sortable, non-guessable). The separator is a HYPHEN, never an underscore — ids must be safe to drop into DNS labels, hostnames, and Kubernetes object names, where "_" is illegal; the id_test guard enforces this, so the choice can't silently drift to Stripe's "tea_…" form.
This package is a leaf: it imports only xid, so every feature and the store can depend on it without pulling in the control plane. Mint through New and validate through WellFormed/KindOf — never hand-concatenate a prefix.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( Workspace = Kind{/* contains filtered or unexported fields */} // Render: teams are tea- Service = Kind{/* contains filtered or unexported fields */} // Render: services are srv- Postgres = Kind{/* contains filtered or unexported fields */} // Render: Postgres databases are dpg- KeyValue = Kind{/* contains filtered or unexported fields */} // Render: Key Value (Redis-compatible) stores are red- Domain = Kind{/* contains filtered or unexported fields */} // Render: custom domains are cdm- EnvGroup = Kind{/* contains filtered or unexported fields */} // Render: env groups are evg- Deploy = Kind{/* contains filtered or unexported fields */} // Render: deploys are dep- Invite = Kind{/* contains filtered or unexported fields */} // w4/m12 team invites Export = Kind{/* contains filtered or unexported fields */} Audit = Kind{/* contains filtered or unexported fields */} // w4/m10 audit log Owner = Kind{/* contains filtered or unexported fields */} // w6/m7: opaque per-subject user id Event = Kind{/* contains filtered or unexported fields */} // Render: events are evt-; w3/m7 — minted by Derive, never New CronRun = Kind{/* contains filtered or unexported fields */} // projection of App.status.runs; minted by Derive, never New Notification = Kind{/* contains filtered or unexported fields */} // w3/m9 Project = Kind{/* contains filtered or unexported fields */} // w1/m31 // RegistryCredential is a bex-chosen prefix — Render's own id spelling for // this resource isn't confirmed against a live capture (w2/m14). RegistryCredential = Kind{/* contains filtered or unexported fields */} Blueprint = Kind{/* contains filtered or unexported fields */} // w2/m15 // Environment is a named subset of a Project's services (e.g. staging/ // production) — the second half of w1/m31's grouping feature, layered on // afterward. "env" (not "evg" — that's the pre-existing, unrelated EnvGroup // env-var-grouping feature). Environment = Kind{/* contains filtered or unexported fields */} // Webhook / WebhookDelivery are bex-chosen prefixes (w3/m11 outbound event // webhooks) — Render's public docs don't expose its webhook-endpoint id // spelling, so these follow the RegistryCredential precedent. Webhook = Kind{/* contains filtered or unexported fields */} WebhookDelivery = Kind{/* contains filtered or unexported fields */} // Job is a one-off job run in a service's container (Render's /services/{id}/jobs). // Prefix "job" matches Render's observed id prefix from the live API. Job = Kind{/* contains filtered or unexported fields */} SSHKey = Kind{/* contains filtered or unexported fields */} SSHSession = Kind{/* contains filtered or unexported fields */} // BlueprintSync is a recorded sync run (w2/m62 — Git-connected Blueprints). // Each manual or auto-triggered sync produces one row in blueprint_syncs. BlueprintSync = Kind{/* contains filtered or unexported fields */} // AgentSession is bex-native (Render has no coding-agent session resource). // "ags" keeps the public id short, typed, and DNS-safe for sandbox metadata. AgentSession = Kind{/* contains filtered or unexported fields */} // Prefix "dsk" is Render's own spelling for a persistent service disk // (^dsk-[0-9a-z]{20}$ in its API), so a Render client's id parsing works // unchanged against bex. w1/m84, docs/ADR082-persistent-disks.md. Disk = Kind{/* contains filtered or unexported fields */} )
The registered kinds — the SINGLE source of truth. A new id-bearing resource adds its Kind here (and nowhere else); the guard test then holds it to the format + uniqueness + DNS-safety contract automatically.
Functions ¶
func Derive ¶
Derive returns the id of a DERIVED resource: same "<prefix>-<20 chars>" shape as New, but a deterministic function of parts rather than a fresh xid. It is the mint path for a resource that is a PROJECTION of rows the store already holds — service events (internal/events), whose public identity is also materialized in an owner-scoped lookup index while their typed data remains in deploys, audit_events, and service_event_facts.
Determinism is the whole point: an event's id must be identical on every read (a client pages with it, re-fetches it, dedupes on it), so New's fresh xid would be exactly wrong. Same parts in, same id out, forever.
parts must uniquely identify the projected event (e.g. the source row id + the transition within it) — they are joined with a separator that cannot occur in an id, so ("dep-x", "started") and ("dep-xstarted") can never collide. The output is 100 bits of SHA-256 in base32hex, which keeps it inside the [0-9a-v]{20} alphabet WellFormed pins, so a derived id is indistinguishable in shape from a minted one and satisfies Render's ^evt-[0-9a-z]{20}$ pattern.
func DeriveServiceInstance ¶
DeriveServiceInstance returns Render's compound service-instance id: "<service-id>-<stable-suffix>". A service instance is a projection of a Kubernetes Pod rather than an independently stored resource, so it extends the parent Service id instead of adding another top-level Kind. Callers pass the Pod UID as a derivation part; the opaque suffix keeps Kubernetes names and UIDs out of the public wire contract while remaining stable across reads.
Legacy hand-applied Apps can still have a name-shaped service id. Preserve that parent verbatim for backwards compatibility; store-managed services use the canonical srv-<xid> parent and therefore match Render's ^srv-[a-z0-9]{20}-[a-z0-9]+$ instance-id shape.
func New ¶
New mints a fresh id for a kind: "<prefix>-<xid>". The only mint path — do not concatenate a prefix by hand (that bypasses the format the guard test pins). It panics on an unregistered Kind (the only one a caller can produce is the zero Kind{}, since the fields are unexported) — a programmer error surfaced fail-fast rather than as a silently malformed id.
func WellFormed ¶
WellFormed reports whether s has the canonical id shape (prefix-xid). It does NOT check that the prefix is a registered kind — use KindOf for that. Cheap input validation for API boundaries (a malformed id is a 400, not a lookup).
Types ¶
type Kind ¶
type Kind struct {
// contains filtered or unexported fields
}
Kind is a typed id namespace: the prefix that leads every id of that kind and a short description of what it identifies. Its fields are UNEXPORTED on purpose — a caller outside this package cannot fabricate a Kind with an arbitrary prefix, so the set of id kinds is closed at COMPILE TIME to the package-registered vars below. The only Kinds that exist are the ones this package declares; New/KindOf hand them out, callers can't invent new ones. Prefixes follow Render's public API so bex ids are drop-in for Render clients.
func KindOf ¶
KindOf returns the registered Kind an id belongs to (ok=false if the shape is wrong or the prefix isn't a registered kind). Lets an adapter route or reject an id by type without string-slicing prefixes itself.