id

package
v0.0.0-...-6e066a8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 24, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

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

View Source
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

func Derive(k Kind, parts ...string) string

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

func DeriveServiceInstance(serviceID string, parts ...string) string

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

func New(k Kind) string

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

func WellFormed(s string) bool

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

func KindOf(s string) (Kind, bool)

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.

func Kinds

func Kinds() []Kind

Kinds returns the registered id kinds (a copy — callers must not mutate it).

func (Kind) Desc

func (k Kind) Desc() string

func (Kind) Prefix

func (k Kind) Prefix() string

Prefix and Desc read a Kind (e.g. for logs/errors). Read-only: there is no setter and no exported field, which is what makes the registry closed.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL