The single-active-jti-per-family invariant is encoded structurally:
activeJti is always a non-empty string. The aggregate is registered
atomically with its initial activeJti via registerFamily and remains
a string field for the family's lifetime; rotation updates the value
(via updateFamily); revocation does NOT clear it (a revoked family
retains the jti that was active when it was revoked, for audit purposes).
expiresAtMs stores the expiry as a Unix epoch millisecond timestamp
(number). Using epoch-ms eliminates the Date mutation surface that
Object.freeze cannot defend against — a caller holding a reference to
a Date object could call setTime(0) and corrupt store state.
Refresh-token family aggregate value type.
The single-active-jti-per-family invariant is encoded structurally:
activeJtiis always a non-empty string. The aggregate is registered atomically with its initial activeJti viaregisterFamilyand remains a string field for the family's lifetime; rotation updates the value (viaupdateFamily); revocation does NOT clear it (a revoked family retains the jti that was active when it was revoked, for audit purposes).expiresAtMsstores the expiry as a Unix epoch millisecond timestamp (number). Using epoch-ms eliminates the Date mutation surface that Object.freeze cannot defend against — a caller holding a reference to a Date object could call setTime(0) and corrupt store state.Per A3 §5.1.