feat(gateway): confirmEmailLink RPC + language on the email request + profile event

Add the confirm-link edge method (auth.email.confirm_link): a new
EmailConfirmLinkRequest/Result fbs table, the transcode const + handler + encoder,
and the backend-client call to the existing /sessions/email/confirm-link endpoint —
it rides Execute under the existing service prefix, so no proto/Caddy change. Add a
language field to EmailRequestRequest and forward it (the backend already seeds it).
Add the NotifyProfile sub-kind + notify.ProfileChanged, published by the confirm-link
handler on a successful link so an in-app session re-fetches its profile when the
email was confirmed in another browser. Regenerated fbs bindings (Go + TS).
This commit is contained in:
Ilia Denisov
2026-07-03 04:22:09 +02:00
parent 25d80bc31d
commit 762155a55e
14 changed files with 418 additions and 41 deletions
+2
View File
@@ -17,6 +17,8 @@ export { ComplaintRequest } from './scrabblefb/complaint-request.js';
export { CreateInvitationRequest } from './scrabblefb/create-invitation-request.js';
export { DraftRequest } from './scrabblefb/draft-request.js';
export { DraftView } from './scrabblefb/draft-view.js';
export { EmailConfirmLinkRequest } from './scrabblefb/email-confirm-link-request.js';
export { EmailConfirmLinkResult } from './scrabblefb/email-confirm-link-result.js';
export { EmailLoginRequest } from './scrabblefb/email-login-request.js';
export { EmailRequestRequest } from './scrabblefb/email-request-request.js';
export { EnqueueRequest } from './scrabblefb/enqueue-request.js';
@@ -0,0 +1,48 @@
// automatically generated by the FlatBuffers compiler, do not modify
import * as flatbuffers from 'flatbuffers';
export class EmailConfirmLinkRequest {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):EmailConfirmLinkRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsEmailConfirmLinkRequest(bb:flatbuffers.ByteBuffer, obj?:EmailConfirmLinkRequest):EmailConfirmLinkRequest {
return (obj || new EmailConfirmLinkRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsEmailConfirmLinkRequest(bb:flatbuffers.ByteBuffer, obj?:EmailConfirmLinkRequest):EmailConfirmLinkRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new EmailConfirmLinkRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
token():string|null
token(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
token(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
static startEmailConfirmLinkRequest(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addToken(builder:flatbuffers.Builder, tokenOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, tokenOffset, 0);
}
static endEmailConfirmLinkRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createEmailConfirmLinkRequest(builder:flatbuffers.Builder, tokenOffset:flatbuffers.Offset):flatbuffers.Offset {
EmailConfirmLinkRequest.startEmailConfirmLinkRequest(builder);
EmailConfirmLinkRequest.addToken(builder, tokenOffset);
return EmailConfirmLinkRequest.endEmailConfirmLinkRequest(builder);
}
}
@@ -0,0 +1,66 @@
// automatically generated by the FlatBuffers compiler, do not modify
import * as flatbuffers from 'flatbuffers';
import { Session } from '../scrabblefb/session.js';
export class EmailConfirmLinkResult {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):EmailConfirmLinkResult {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsEmailConfirmLinkResult(bb:flatbuffers.ByteBuffer, obj?:EmailConfirmLinkResult):EmailConfirmLinkResult {
return (obj || new EmailConfirmLinkResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsEmailConfirmLinkResult(bb:flatbuffers.ByteBuffer, obj?:EmailConfirmLinkResult):EmailConfirmLinkResult {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new EmailConfirmLinkResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
purpose():string|null
purpose(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
purpose(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
status():string|null
status(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
status(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
session(obj?:Session):Session|null {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? (obj || new Session()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startEmailConfirmLinkResult(builder:flatbuffers.Builder) {
builder.startObject(3);
}
static addPurpose(builder:flatbuffers.Builder, purposeOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, purposeOffset, 0);
}
static addStatus(builder:flatbuffers.Builder, statusOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, statusOffset, 0);
}
static addSession(builder:flatbuffers.Builder, sessionOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, sessionOffset, 0);
}
static endEmailConfirmLinkResult(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
}
@@ -34,8 +34,15 @@ browserTz(optionalEncoding?:any):string|Uint8Array|null {
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
language():string|null
language(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
language(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
static startEmailRequestRequest(builder:flatbuffers.Builder) {
builder.startObject(2);
builder.startObject(3);
}
static addEmail(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset) {
@@ -46,15 +53,20 @@ static addBrowserTz(builder:flatbuffers.Builder, browserTzOffset:flatbuffers.Off
builder.addFieldOffset(1, browserTzOffset, 0);
}
static addLanguage(builder:flatbuffers.Builder, languageOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, languageOffset, 0);
}
static endEmailRequestRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createEmailRequestRequest(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset, browserTzOffset:flatbuffers.Offset):flatbuffers.Offset {
static createEmailRequestRequest(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset, browserTzOffset:flatbuffers.Offset, languageOffset:flatbuffers.Offset):flatbuffers.Offset {
EmailRequestRequest.startEmailRequestRequest(builder);
EmailRequestRequest.addEmail(builder, emailOffset);
EmailRequestRequest.addBrowserTz(builder, browserTzOffset);
EmailRequestRequest.addLanguage(builder, languageOffset);
return EmailRequestRequest.endEmailRequestRequest(builder);
}
}