[accounts] clean up email in case null causes issues

This commit is contained in:
Devin Zuczek
2026-08-12 16:30:16 -04:00
parent 8364a0b5f6
commit 8e0e92b449
3 changed files with 18 additions and 7 deletions
+7 -3
View File
@@ -119,13 +119,17 @@ function toAccountDto(account: Account) {
/** /**
* Project a stored account into the private self DTO (the /account/me shape) — * Project a stored account into the private self DTO (the /account/me shape) —
* the public DTO plus owner-only fields. `juniorState`/`parentAccountId` are * the public DTO plus owner-only fields. `juniorState`/`parentAccountId` are
* OMITTED when null (emitting `null` makes the client's enum parser throw); * OMITTED when null (emitting `null` makes the client's enum parser throw).
* `email`/`birthday` are kept as null (not enums, so null is fine). *
* An unset `email` is `""`, never null — same as `bio`. Two reasons: the client reads
* it as a string, and this DTO also rides the `SelfAccountUpdate` hub frame, where the
* hub DROPS null values from `Msg` — so a null email doesn't arrive as null, it
* vanishes from the frame entirely.
*/ */
function toSelfAccountDto(account: Account) { function toSelfAccountDto(account: Account) {
return { return {
...toAccountDto(account), ...toAccountDto(account),
email: account.email ?? null, email: account.email ?? '',
// @todo he game client needs this to be set. I forget how birthdays were set, so for now // @todo he game client needs this to be set. I forget how birthdays were set, so for now
// everyone can be old. // everyone can be old.
birthday: '1904-01-01T00:00:00.000Z', birthday: '1904-01-01T00:00:00.000Z',
+8 -4
View File
@@ -77,12 +77,16 @@ export const AccountDto = z.object({
/** /**
* The private self DTO (`toSelfAccountDto`, the `/account/me` shape) — the public DTO * The private self DTO (`toSelfAccountDto`, the `/account/me` shape) — the public DTO
* plus owner-only fields. `juniorState`/`parentAccountId` are omitted entirely when * plus owner-only fields. `juniorState`/`parentAccountId` are omitted entirely when
* unset (emitting `null` makes the client's enum parser throw); `email`/`birthday` are * unset (emitting `null` makes the client's enum parser throw).
* kept as nullable since they aren't enums.
*/ */
export const SelfAccountDto = AccountDto.extend({ export const SelfAccountDto = AccountDto.extend({
email: z.string().nullable(), email: z
birthday: z.null().describe('Always null — birthday is not stored'), .string()
.describe(
'"" when unset — never null: the client reads it as a string, and the hub frame this ' +
'DTO also rides drops null values outright'
),
birthday: z.iso.datetime().describe('A fixed placeholder — birthdays are not stored'),
availableUsernameChanges: z.int().describe('Remaining username changes'), availableUsernameChanges: z.int().describe('Remaining username changes'),
}) })
@@ -161,6 +161,9 @@ describe('auth-gated endpoints', () => {
personalPronouns: 0, personalPronouns: 0,
identityFlags: 0, identityFlags: 0,
availableUsernameChanges: 1, availableUsernameChanges: 1,
// An unset email is "", not null — the client reads it as a string, and the
// hub frame this DTO also rides drops null values outright.
email: '',
}) })
// juniorState + parentAccountId must be omitted when null, not emitted as // juniorState + parentAccountId must be omitted when null, not emitted as
// null, or the client's enum parser throws on `juniorState`. `phone` isn't // null, or the client's enum parser throws on `juniorState`. `phone` isn't