encodeAgentName(Encode a routing name into the actor id that addresses its instance. An actor id is not free-form. It is a path segment on every call to the instance, it is folded into the persistent records the instance owns, and it names the instance’s timers — and only ASCII letters, digits,name):string
-, _, and
. survive all three. An id built from anything else is not merely ugly: it
cannot be addressed, and the instance never activates.
Names customers actually route on are not confined to that set — a phone
number (+15550100), an email address, a composite key, a name with accents
or emoji. This encoder maps any such name onto the addressable set, and back
again:
: + the
lowercase hex of that run’s UTF-8 bytes + :. Characters inside the set are
written through untouched. : itself is never written through — it is
always escaped (: → :3a:) — which is what makes an escape impossible to
confuse with an ordinary name and the encoding reversible by
decodeAgentName.
Two names therefore never share an id: the id says exactly which characters
were escaped, so it decodes back to one name and one name only.
How long a name may be
The limit is on the ID once URL-escaped, not on the name: an actor id may
occupy at most MAX_ESCAPED_ACTOR_ID_LENGTH characters escaped, and a
name whose id would be longer is refused here rather than handed back as an
id the platform cannot keep an instance under.
So how many characters of name fit depends on which characters they are,
because an escape is longer than what it replaces — two hex digits per UTF-8
byte, plus the two : bracketing each run, which cost three apiece once
URL-escaped:
-, _, .) gets the full 225, since
it passes through unchanged and has nothing to escape. Everything else costs
more: 4 characters per accented Latin letter (54 of them fit), 6 per
three-byte character such as ☕ or most CJK (36 fit), and 8 per emoji or
other astral character (27 fit), with a further 6 for each separate run of
them. Budget for the characters your names actually use, use
escapedActorIdLength when you need the exact number, and prefer
catching the throw over assuming a name fits.
This encoding is part of an actor’s identity, and is frozen
The id an instance is first addressed by is the id its persistent state, its
timers, and every later request are filed under. Changing how a name
encodes re-points that name at a different, empty instance and orphans
everything the old one held. Treat the mapping as fixed for the lifetime
of the deployment: the same name must always yield the same id. It will not
be changed under you, and you should not re-derive it — call this function
instead.
That is also why mountAgents applies it to every name it resolves: a
mounted agent needs no encoding code, and a hand-written front door that
addresses the SAME instances stays in step by calling this rather than
writing the rule out again.
Names already inside the addressable set pass through byte-for-byte, so
adopting the encoder never re-points an instance that was already reachable.
Two things to get right
Takes the RAW name, exactly once. Encoding an already-encoded name
escapes its : signs (":2b:15550100" → ":3a:2b:3a:15550100") and
addresses a different instance — pass the name as the caller wrote it, not a
value read out of a URL path without decoding it first.
Letter case is significant: Alice and alice are different names and
different instances. Lowercase your names before you route on them if you
mean them to be the same.
Parameters
Returns
string
The actor id for that name, built only from ASCII letters, digits,
-, _, ., and :.
Throws
TypeError when the name has no faithful id and encoding it would
hand back one that cannot be addressed: an empty name, one whose id would
occupy more than MAX_ESCAPED_ACTOR_ID_LENGTH characters once escaped
(which a name of more than that many characters always does), or one
containing an unpaired surrogate. The message names the offending input and
the limit it missed.