Register a new refresh-token family at initial issue time (e.g., from the authorization_code grant handler).
Delegates to RefreshTokenFamilyStore.registerFamily(family) after
constructing a RefreshTokenFamily aggregate from the inputs.
MUST throw RefreshTokenStorageError({ reason: "duplicate-family" })
if familyId already exists. MUST throw
RefreshTokenStorageError({ reason: "expired-at-issue" }) if
expiresAtMs <= now().
Use this for initial issue, not for rotation.
Compose the storage primitive into the 4-outcome rotation ceremony.
Normal flow does NOT throw RefreshTokenStorageError or any other
domain error — the discriminated outcome union IS the complete
return contract. System errors (Redis network failure, CAS conflict
exhaustion) propagate as native errors / RefreshTokenStorageError( { reason: "conflict-exhausted" }).
Per A3 §5.2.
Rotation ceremony wrapper. Composes
RefreshTokenFamilyStore.updateFamilyinto the 4-outcome union. The default impl (createRefreshTokenFamilyRotation) is shipped asdefaultRefreshTokenFamilyRotationModule; consumers needing custom policy (audit-emitting rotation, grace-period rotation, etc.) replace the module with their own.Per A3 §5.2.