Stage 17 round 6 (#4/#5/#6): draft persistence wire + gateway + UI
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 32s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m7s
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 32s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m7s
Complete the client-side draft feature on top of the shipped backend
foundation (the game_drafts store/service):
- FB: DraftRequest{game_id,json} + DraftView{json} (a draft get reuses
GameActionRequest); regenerated committed Go + TS bindings.
- Backend REST: GET/PUT /games/:id/draft, a draftDTO
(rack_order/board_tiles) mapped to game.Draft.
- Gateway: draft.get/draft.save transcode forwarding the composition
JSON verbatim (json.RawMessage both ways -- no double-encode).
- UI: debounced save of the rack order + board tiles and restore on
load (lib/draft.ts), plus #5 -- tiles may be arranged on the
opponent's turn (placement relaxed; the preview and Make-move stay
your-turn-only, so an off-turn draft is position-only).
Tests: backend handler validation, gateway pass-through round-trip, UI
draft/codec units, and a draft-restore e2e.
This commit is contained in:
@@ -73,6 +73,18 @@ export function encodeStateRequest(gameId: string, includeAlphabet: boolean): Ui
|
||||
return finish(b, fb.StateRequest.endStateRequest(b));
|
||||
}
|
||||
|
||||
// encodeDraftSave wraps the player's composition JSON (Stage 17). The string is opaque on the
|
||||
// wire — the gateway forwards it verbatim and only the client reads {rack_order, board_tiles}.
|
||||
export function encodeDraftSave(gameId: string, json: string): Uint8Array {
|
||||
const b = new Builder(256);
|
||||
const gid = b.createString(gameId);
|
||||
const j = b.createString(json);
|
||||
fb.DraftRequest.startDraftRequest(b);
|
||||
fb.DraftRequest.addGameId(b, gid);
|
||||
fb.DraftRequest.addJson(b, j);
|
||||
return finish(b, fb.DraftRequest.endDraftRequest(b));
|
||||
}
|
||||
|
||||
export function encodeSubmitPlay(
|
||||
gameId: string,
|
||||
dir: 'H' | 'V',
|
||||
@@ -359,6 +371,13 @@ export function decodeWordCheck(buf: Uint8Array): WordCheckResult {
|
||||
return { word: s(r.word()), legal: r.legal() };
|
||||
}
|
||||
|
||||
// decodeDraftView returns the player's stored composition JSON (empty when none is stored or
|
||||
// for the save acknowledgement); the caller parses {rack_order, board_tiles}.
|
||||
export function decodeDraftView(buf: Uint8Array): string {
|
||||
const v = fb.DraftView.getRootAsDraftView(new ByteBuffer(buf));
|
||||
return v.json() ?? '';
|
||||
}
|
||||
|
||||
export function decodeHistory(buf: Uint8Array): History {
|
||||
const h = fb.History.getRootAsHistory(new ByteBuffer(buf));
|
||||
const moves: MoveRecord[] = [];
|
||||
|
||||
Reference in New Issue
Block a user