StreamGrant
Defined in: packages/server/src/circuits/stream-token.ts:12
One stream a token admits its bearer to.
The grant is self-describing: it carries the durable-streams path together with the shape and scope that path serves. That is what keeps the edge stateless. Shape creation happened on whichever replica the client reached, and the edge is replica-scaled, so a path→scope map held in memory would have to be shared between replicas — a second piece of distributed state on the read path, to answer a question the token can simply carry.
Properties
Section titled “Properties”claim:
string
Defined in: packages/server/src/circuits/stream-token.ts:43
The subscription id this grant’s claim was taken under — the name the control plane gave it
on POST /shapes (fork ADR-0008).
Carried for the same reason StreamGrant.shapeId is: renewal and release are stateless.
The re-mint renews this exact claim (the same create, repeated with this id) and the release
route drops this exact claim (DELETE /shapes/{id}?subscription=…) — both of them from the
signed token alone, with nothing remembered server-side. It is also what makes a release
idempotent: a claim named is a claim that can only be given back once, however many times the
request arrives.
Distinct per grant even when two grants share a shapeId: two joins onto one deduplicated shape
are two claims, and one id could only ever release one of them.
optionalfp?:string
Defined in: packages/server/src/circuits/stream-token.ts:61
PRIVATE TIER ONLY: the fingerprint of the compiled shape request this grant authorized.
A re-mint recompiles the shape with the subject’s CURRENT claims and admits the grant only if the result fingerprints the same; a grant without one cannot be re-authorized and is revoked. That is what keeps the re-mint stateless — the token carries the thing that was authorized, so nothing server-side has to remember it.
Shared-tier grants carry none, and deliberately: their predicate is generated from the scope values alone, so it cannot drift with the subject’s claims and the live entitlement re-check is the whole question.
path:
string
Defined in: packages/server/src/circuits/stream-token.ts:14
The durable-streams path, e.g. shape/s1.
scope?
Section titled “scope?”
optionalscope?: readonlyPredicateValue[]
Defined in: packages/server/src/circuits/stream-token.ts:48
Scope values, positionally matching the shape’s declared scope columns. Shared tier only; a private-tier grant has none, and its authorization is the token itself.
shapeId
Section titled “shapeId”shapeId:
string
Defined in: packages/server/src/circuits/stream-token.ts:28
The engine claim this grant acquired — one POST /shapes join — so the session that holds it can
release exactly what it acquired.
Carried rather than looked up, for the same reason the path and scope are: the release route is
stateless, and the signed token is the only proof of what the control plane handed out. It is not
the same thing as StreamGrant.path: the engine’s own id is what DELETE /shapes/{id}
takes, and two grants can legitimately name ONE shapeId when the engine deduplicated two
identical definitions (ADR-0055 decision 6) — which is precisely why release counts grants, not
distinct ids.
shapeKey
Section titled “shapeKey”shapeKey:
string
Defined in: packages/server/src/circuits/stream-token.ts:16
The shape this path serves — the entitlement rule’s binding key.