ui: plan 01-27 done #1

Merged
developer merged 120 commits from ai/ui-client into main 2026-05-13 18:55:14 +00:00
90 changed files with 11862 additions and 112 deletions
Showing only changes of commit f57a290432 - Show all commits
+9
View File
@@ -145,6 +145,15 @@ because they cross domain boundaries:
`X-User-ID`. Public games carry `owner_user_id IS NULL`; the partial
index on `(owner_user_id) WHERE visibility = 'private'` keeps the
private-owner lookup efficient.
- **Authenticated lobby commands** flow through the gateway envelope
by `message_type`. The catalog is `lobby.my.games.list`,
`lobby.public.games.list`, `lobby.my.applications.list`,
`lobby.my.invites.list`, `lobby.game.create`,
`lobby.game.open-enrollment`, `lobby.application.submit`,
`lobby.invite.redeem`, and `lobby.invite.decline`. Each lands on a
REST handler under `/api/v1/user/lobby/*`; the gateway forces
visibility to `private` on `lobby.game.create` before forwarding,
matching the user-surface invariant above.
| Package | Responsibility |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+9
View File
@@ -369,6 +369,15 @@ The current direct `Gateway -> User` self-service boundary uses that pattern:
- `user.games.command`
- `user.games.order`
- `user.games.report`
- `lobby.my.games.list`
- `lobby.my.applications.list`
- `lobby.my.invites.list`
- `lobby.public.games.list`
- `lobby.game.create`
- `lobby.game.open-enrollment`
- `lobby.application.submit`
- `lobby.invite.redeem`
- `lobby.invite.decline`
- external payloads and responses:
- FlatBuffers
- internal downstream transport:
@@ -10,6 +10,7 @@ import (
"net/http"
"net/url"
"strings"
"time"
"galaxy/gateway/internal/downstream"
lobbymodel "galaxy/model/lobby"
@@ -55,12 +56,52 @@ func (c *RESTClient) ExecuteLobbyCommand(ctx context.Context, command downstream
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyMyGames(ctx, command.UserID)
case lobbymodel.MessageTypePublicGamesList:
req, err := transcoder.PayloadToPublicGamesListRequest(command.PayloadBytes)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyPublicGames(ctx, command.UserID, req)
case lobbymodel.MessageTypeMyApplicationsList:
if _, err := transcoder.PayloadToMyApplicationsListRequest(command.PayloadBytes); err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyMyApplications(ctx, command.UserID)
case lobbymodel.MessageTypeMyInvitesList:
if _, err := transcoder.PayloadToMyInvitesListRequest(command.PayloadBytes); err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyMyInvites(ctx, command.UserID)
case lobbymodel.MessageTypeOpenEnrollment:
req, err := transcoder.PayloadToOpenEnrollmentRequest(command.PayloadBytes)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyOpenEnrollment(ctx, command.UserID, req)
case lobbymodel.MessageTypeGameCreate:
req, err := transcoder.PayloadToGameCreateRequest(command.PayloadBytes)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyGameCreate(ctx, command.UserID, req)
case lobbymodel.MessageTypeApplicationSubmit:
req, err := transcoder.PayloadToApplicationSubmitRequest(command.PayloadBytes)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyApplicationSubmit(ctx, command.UserID, req)
case lobbymodel.MessageTypeInviteRedeem:
req, err := transcoder.PayloadToInviteRedeemRequest(command.PayloadBytes)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyInviteRedeem(ctx, command.UserID, req)
case lobbymodel.MessageTypeInviteDecline:
req, err := transcoder.PayloadToInviteDeclineRequest(command.PayloadBytes)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command %q: %w", command.MessageType, err)
}
return c.executeLobbyInviteDecline(ctx, command.UserID, req)
default:
return downstream.UnaryResult{}, fmt.Errorf("backendclient: execute lobby command: unsupported message type %q", command.MessageType)
}
@@ -88,6 +129,81 @@ func (c *RESTClient) executeLobbyMyGames(ctx context.Context, userID string) (do
return projectLobbyErrorResponse(status, body)
}
func (c *RESTClient) executeLobbyPublicGames(ctx context.Context, userID string, req *lobbymodel.PublicGamesListRequest) (downstream.UnaryResult, error) {
page := req.Page
if page <= 0 {
page = 1
}
pageSize := req.PageSize
if pageSize <= 0 {
pageSize = 50
}
target := fmt.Sprintf("%s/api/v1/user/lobby/games?page=%d&page_size=%d", c.baseURL, page, pageSize)
body, status, err := c.do(ctx, http.MethodGet, target, userID, nil)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("execute lobby.public.games.list: %w", err)
}
if status == http.StatusOK {
page, err := decodePublicGamesPage(body)
if err != nil {
return downstream.UnaryResult{}, err
}
payloadBytes, err := transcoder.PublicGamesListResponseToPayload(page)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("encode success response payload: %w", err)
}
return downstream.UnaryResult{
ResultCode: lobbyResultCodeOK,
PayloadBytes: payloadBytes,
}, nil
}
return projectLobbyErrorResponse(status, body)
}
func (c *RESTClient) executeLobbyMyApplications(ctx context.Context, userID string) (downstream.UnaryResult, error) {
body, status, err := c.do(ctx, http.MethodGet, c.baseURL+"/api/v1/user/lobby/my/applications", userID, nil)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("execute lobby.my.applications.list: %w", err)
}
if status == http.StatusOK {
response, err := decodeApplicationsList(body)
if err != nil {
return downstream.UnaryResult{}, err
}
payloadBytes, err := transcoder.MyApplicationsListResponseToPayload(response)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("encode success response payload: %w", err)
}
return downstream.UnaryResult{
ResultCode: lobbyResultCodeOK,
PayloadBytes: payloadBytes,
}, nil
}
return projectLobbyErrorResponse(status, body)
}
func (c *RESTClient) executeLobbyMyInvites(ctx context.Context, userID string) (downstream.UnaryResult, error) {
body, status, err := c.do(ctx, http.MethodGet, c.baseURL+"/api/v1/user/lobby/my/invites", userID, nil)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("execute lobby.my.invites.list: %w", err)
}
if status == http.StatusOK {
response, err := decodeInvitesList(body)
if err != nil {
return downstream.UnaryResult{}, err
}
payloadBytes, err := transcoder.MyInvitesListResponseToPayload(response)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("encode success response payload: %w", err)
}
return downstream.UnaryResult{
ResultCode: lobbyResultCodeOK,
PayloadBytes: payloadBytes,
}, nil
}
return projectLobbyErrorResponse(status, body)
}
func (c *RESTClient) executeLobbyOpenEnrollment(ctx context.Context, userID string, req *lobbymodel.OpenEnrollmentRequest) (downstream.UnaryResult, error) {
if req == nil || strings.TrimSpace(req.GameID) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.game.open-enrollment: game_id must not be empty")
@@ -122,6 +238,338 @@ func (c *RESTClient) executeLobbyOpenEnrollment(ctx context.Context, userID stri
return projectLobbyErrorResponse(status, body)
}
func (c *RESTClient) executeLobbyGameCreate(ctx context.Context, userID string, req *lobbymodel.GameCreateRequest) (downstream.UnaryResult, error) {
if req == nil || strings.TrimSpace(req.GameName) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.game.create: game_name must not be empty")
}
if strings.TrimSpace(req.TurnSchedule) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.game.create: turn_schedule must not be empty")
}
if strings.TrimSpace(req.TargetEngineVersion) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.game.create: target_engine_version must not be empty")
}
if req.MinPlayers <= 0 || req.MaxPlayers <= 0 {
return downstream.UnaryResult{}, errors.New("execute lobby.game.create: min_players and max_players must be positive")
}
if req.MinPlayers > req.MaxPlayers {
return downstream.UnaryResult{}, errors.New("execute lobby.game.create: min_players must not exceed max_players")
}
if req.EnrollmentEndsAt.IsZero() {
return downstream.UnaryResult{}, errors.New("execute lobby.game.create: enrollment_ends_at must be set")
}
body := map[string]any{
"game_name": req.GameName,
"visibility": "private",
"description": req.Description,
"min_players": int32(req.MinPlayers),
"max_players": int32(req.MaxPlayers),
"start_gap_hours": int32(req.StartGapHours),
"start_gap_players": int32(req.StartGapPlayers),
"enrollment_ends_at": req.EnrollmentEndsAt.UTC().Format(time.RFC3339Nano),
"turn_schedule": req.TurnSchedule,
"target_engine_version": req.TargetEngineVersion,
}
payload, status, err := c.do(ctx, http.MethodPost, c.baseURL+"/api/v1/user/lobby/games", userID, body)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("execute lobby.game.create: %w", err)
}
if status == http.StatusOK || status == http.StatusCreated {
summary, err := decodeGameSummaryFromGameDetail(payload)
if err != nil {
return downstream.UnaryResult{}, err
}
payloadBytes, err := transcoder.GameCreateResponseToPayload(&lobbymodel.GameCreateResponse{Game: summary})
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("encode success response payload: %w", err)
}
return downstream.UnaryResult{
ResultCode: lobbyResultCodeOK,
PayloadBytes: payloadBytes,
}, nil
}
return projectLobbyErrorResponse(status, payload)
}
func (c *RESTClient) executeLobbyApplicationSubmit(ctx context.Context, userID string, req *lobbymodel.ApplicationSubmitRequest) (downstream.UnaryResult, error) {
if req == nil || strings.TrimSpace(req.GameID) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.application.submit: game_id must not be empty")
}
if strings.TrimSpace(req.RaceName) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.application.submit: race_name must not be empty")
}
target := c.baseURL + "/api/v1/user/lobby/games/" + url.PathEscape(req.GameID) + "/applications"
body := map[string]any{"race_name": req.RaceName}
payload, status, err := c.do(ctx, http.MethodPost, target, userID, body)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("execute lobby.application.submit: %w", err)
}
if status == http.StatusOK || status == http.StatusCreated {
app, err := decodeApplicationDetail(payload)
if err != nil {
return downstream.UnaryResult{}, err
}
payloadBytes, err := transcoder.ApplicationSubmitResponseToPayload(&lobbymodel.ApplicationSubmitResponse{Application: app})
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("encode success response payload: %w", err)
}
return downstream.UnaryResult{
ResultCode: lobbyResultCodeOK,
PayloadBytes: payloadBytes,
}, nil
}
return projectLobbyErrorResponse(status, payload)
}
func (c *RESTClient) executeLobbyInviteRedeem(ctx context.Context, userID string, req *lobbymodel.InviteRedeemRequest) (downstream.UnaryResult, error) {
if req == nil || strings.TrimSpace(req.GameID) == "" || strings.TrimSpace(req.InviteID) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.invite.redeem: game_id and invite_id must not be empty")
}
target := c.baseURL + "/api/v1/user/lobby/games/" + url.PathEscape(req.GameID) + "/invites/" + url.PathEscape(req.InviteID) + "/redeem"
payload, status, err := c.do(ctx, http.MethodPost, target, userID, nil)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("execute lobby.invite.redeem: %w", err)
}
if status == http.StatusOK {
invite, err := decodeInviteDetail(payload)
if err != nil {
return downstream.UnaryResult{}, err
}
payloadBytes, err := transcoder.InviteRedeemResponseToPayload(&lobbymodel.InviteRedeemResponse{Invite: invite})
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("encode success response payload: %w", err)
}
return downstream.UnaryResult{
ResultCode: lobbyResultCodeOK,
PayloadBytes: payloadBytes,
}, nil
}
return projectLobbyErrorResponse(status, payload)
}
func (c *RESTClient) executeLobbyInviteDecline(ctx context.Context, userID string, req *lobbymodel.InviteDeclineRequest) (downstream.UnaryResult, error) {
if req == nil || strings.TrimSpace(req.GameID) == "" || strings.TrimSpace(req.InviteID) == "" {
return downstream.UnaryResult{}, errors.New("execute lobby.invite.decline: game_id and invite_id must not be empty")
}
target := c.baseURL + "/api/v1/user/lobby/games/" + url.PathEscape(req.GameID) + "/invites/" + url.PathEscape(req.InviteID) + "/decline"
payload, status, err := c.do(ctx, http.MethodPost, target, userID, nil)
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("execute lobby.invite.decline: %w", err)
}
if status == http.StatusOK {
invite, err := decodeInviteDetail(payload)
if err != nil {
return downstream.UnaryResult{}, err
}
payloadBytes, err := transcoder.InviteDeclineResponseToPayload(&lobbymodel.InviteDeclineResponse{Invite: invite})
if err != nil {
return downstream.UnaryResult{}, fmt.Errorf("encode success response payload: %w", err)
}
return downstream.UnaryResult{
ResultCode: lobbyResultCodeOK,
PayloadBytes: payloadBytes,
}, nil
}
return projectLobbyErrorResponse(status, payload)
}
// decodeGameSummaryFromGameDetail accepts the backend's full
// LobbyGameDetail wire shape and projects it onto the gateway's
// GameSummary contract. It uses non-strict JSON decoding so the
// gateway tolerates the runtime/engine fields it does not forward to
// the UI.
func decodeGameSummaryFromGameDetail(payload []byte) (lobbymodel.GameSummary, error) {
var wire struct {
GameID string `json:"game_id"`
GameName string `json:"game_name"`
GameType string `json:"game_type"`
Status string `json:"status"`
OwnerUserID *string `json:"owner_user_id"`
MinPlayers int `json:"min_players"`
MaxPlayers int `json:"max_players"`
EnrollmentEndsAt time.Time `json:"enrollment_ends_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
if err := json.Unmarshal(payload, &wire); err != nil {
return lobbymodel.GameSummary{}, fmt.Errorf("decode success response: %w", err)
}
owner := ""
if wire.OwnerUserID != nil {
owner = *wire.OwnerUserID
}
return lobbymodel.GameSummary{
GameID: wire.GameID,
GameName: wire.GameName,
GameType: wire.GameType,
Status: wire.Status,
OwnerUserID: owner,
MinPlayers: wire.MinPlayers,
MaxPlayers: wire.MaxPlayers,
EnrollmentEndsAt: wire.EnrollmentEndsAt.UTC(),
CreatedAt: wire.CreatedAt.UTC(),
UpdatedAt: wire.UpdatedAt.UTC(),
}, nil
}
func decodePublicGamesPage(payload []byte) (*lobbymodel.PublicGamesListResponse, error) {
var wire struct {
Items []struct {
GameID string `json:"game_id"`
GameName string `json:"game_name"`
GameType string `json:"game_type"`
Status string `json:"status"`
OwnerUserID *string `json:"owner_user_id"`
MinPlayers int `json:"min_players"`
MaxPlayers int `json:"max_players"`
EnrollmentEndsAt time.Time `json:"enrollment_ends_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
} `json:"items"`
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int `json:"total"`
}
if err := json.Unmarshal(payload, &wire); err != nil {
return nil, fmt.Errorf("decode success response: %w", err)
}
out := &lobbymodel.PublicGamesListResponse{
Items: make([]lobbymodel.GameSummary, 0, len(wire.Items)),
Page: wire.Page,
PageSize: wire.PageSize,
Total: wire.Total,
}
for _, w := range wire.Items {
owner := ""
if w.OwnerUserID != nil {
owner = *w.OwnerUserID
}
out.Items = append(out.Items, lobbymodel.GameSummary{
GameID: w.GameID,
GameName: w.GameName,
GameType: w.GameType,
Status: w.Status,
OwnerUserID: owner,
MinPlayers: w.MinPlayers,
MaxPlayers: w.MaxPlayers,
EnrollmentEndsAt: w.EnrollmentEndsAt.UTC(),
CreatedAt: w.CreatedAt.UTC(),
UpdatedAt: w.UpdatedAt.UTC(),
})
}
return out, nil
}
func decodeApplicationsList(payload []byte) (*lobbymodel.MyApplicationsListResponse, error) {
var wire struct {
Items []applicationDetailWire `json:"items"`
}
if err := json.Unmarshal(payload, &wire); err != nil {
return nil, fmt.Errorf("decode success response: %w", err)
}
out := &lobbymodel.MyApplicationsListResponse{
Items: make([]lobbymodel.ApplicationSummary, 0, len(wire.Items)),
}
for _, w := range wire.Items {
out.Items = append(out.Items, w.toModel())
}
return out, nil
}
func decodeApplicationDetail(payload []byte) (lobbymodel.ApplicationSummary, error) {
var wire applicationDetailWire
if err := json.Unmarshal(payload, &wire); err != nil {
return lobbymodel.ApplicationSummary{}, fmt.Errorf("decode success response: %w", err)
}
return wire.toModel(), nil
}
func decodeInvitesList(payload []byte) (*lobbymodel.MyInvitesListResponse, error) {
var wire struct {
Items []inviteDetailWire `json:"items"`
}
if err := json.Unmarshal(payload, &wire); err != nil {
return nil, fmt.Errorf("decode success response: %w", err)
}
out := &lobbymodel.MyInvitesListResponse{
Items: make([]lobbymodel.InviteSummary, 0, len(wire.Items)),
}
for _, w := range wire.Items {
out.Items = append(out.Items, w.toModel())
}
return out, nil
}
func decodeInviteDetail(payload []byte) (lobbymodel.InviteSummary, error) {
var wire inviteDetailWire
if err := json.Unmarshal(payload, &wire); err != nil {
return lobbymodel.InviteSummary{}, fmt.Errorf("decode success response: %w", err)
}
return wire.toModel(), nil
}
type applicationDetailWire struct {
ApplicationID string `json:"application_id"`
GameID string `json:"game_id"`
ApplicantUserID string `json:"applicant_user_id"`
RaceName string `json:"race_name"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
DecidedAt *time.Time `json:"decided_at,omitempty"`
}
func (w applicationDetailWire) toModel() lobbymodel.ApplicationSummary {
out := lobbymodel.ApplicationSummary{
ApplicationID: w.ApplicationID,
GameID: w.GameID,
ApplicantUserID: w.ApplicantUserID,
RaceName: w.RaceName,
Status: w.Status,
CreatedAt: w.CreatedAt.UTC(),
}
if w.DecidedAt != nil {
t := w.DecidedAt.UTC()
out.DecidedAt = &t
}
return out
}
type inviteDetailWire struct {
InviteID string `json:"invite_id"`
GameID string `json:"game_id"`
InviterUserID string `json:"inviter_user_id"`
InvitedUserID *string `json:"invited_user_id,omitempty"`
Code *string `json:"code,omitempty"`
RaceName string `json:"race_name"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
DecidedAt *time.Time `json:"decided_at,omitempty"`
}
func (w inviteDetailWire) toModel() lobbymodel.InviteSummary {
out := lobbymodel.InviteSummary{
InviteID: w.InviteID,
GameID: w.GameID,
InviterUserID: w.InviterUserID,
RaceName: w.RaceName,
Status: w.Status,
CreatedAt: w.CreatedAt.UTC(),
ExpiresAt: w.ExpiresAt.UTC(),
}
if w.InvitedUserID != nil {
out.InvitedUserID = *w.InvitedUserID
}
if w.Code != nil {
out.Code = *w.Code
}
if w.DecidedAt != nil {
t := w.DecidedAt.UTC()
out.DecidedAt = &t
}
return out
}
func projectLobbyErrorResponse(statusCode int, payload []byte) (downstream.UnaryResult, error) {
switch {
case statusCode == http.StatusServiceUnavailable:
@@ -0,0 +1,512 @@
package backendclient_test
import (
"context"
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"galaxy/gateway/internal/backendclient"
"galaxy/gateway/internal/downstream"
lobbymodel "galaxy/model/lobby"
"galaxy/transcoder"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func newAuthCommand(t *testing.T, messageType string, payload []byte) downstream.AuthenticatedCommand {
t.Helper()
return downstream.AuthenticatedCommand{
MessageType: messageType,
PayloadBytes: payload,
UserID: "user-1",
}
}
func mustEncode[T any](t *testing.T, encode func(*T) ([]byte, error), value *T) []byte {
t.Helper()
bytes, err := encode(value)
require.NoError(t, err)
return bytes
}
func TestExecuteLobbyMyGamesListReturnsItems(t *testing.T) {
t.Parallel()
enrollment := time.Date(2026, 5, 15, 12, 0, 0, 0, time.UTC)
created := time.Date(2026, 5, 7, 10, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
require.Equal(t, "/api/v1/user/lobby/my/games", r.URL.Path)
require.Equal(t, "user-1", r.Header.Get(backendclient.HeaderUserID))
writeJSON(t, w, http.StatusOK, map[string]any{
"items": []map[string]any{{
"game_id": "game-1",
"game_name": "Test Game",
"game_type": "private",
"status": "draft",
"owner_user_id": "user-1",
"min_players": 2,
"max_players": 8,
"enrollment_ends_at": enrollment.Format(time.RFC3339Nano),
"created_at": created.Format(time.RFC3339Nano),
"updated_at": created.Format(time.RFC3339Nano),
}},
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.MyGamesListRequestToPayload, &lobbymodel.MyGamesListRequest{})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeMyGamesList, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToMyGamesListResponse(result.PayloadBytes)
require.NoError(t, err)
require.Len(t, decoded.Items, 1)
assert.Equal(t, "game-1", decoded.Items[0].GameID)
assert.Equal(t, enrollment, decoded.Items[0].EnrollmentEndsAt)
}
func TestExecuteLobbyPublicGamesListPaginatesAndDecodes(t *testing.T) {
t.Parallel()
enrollment := time.Date(2026, 6, 1, 12, 0, 0, 0, time.UTC)
created := time.Date(2026, 5, 1, 12, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodGet, r.Method)
require.Equal(t, "/api/v1/user/lobby/games", r.URL.Path)
require.Equal(t, "2", r.URL.Query().Get("page"))
require.Equal(t, "10", r.URL.Query().Get("page_size"))
writeJSON(t, w, http.StatusOK, map[string]any{
"items": []map[string]any{{
"game_id": "public-1",
"game_name": "Open",
"game_type": "public",
"status": "enrollment_open",
"owner_user_id": nil,
"min_players": 4,
"max_players": 12,
"enrollment_ends_at": enrollment.Format(time.RFC3339Nano),
"created_at": created.Format(time.RFC3339Nano),
"updated_at": created.Format(time.RFC3339Nano),
}},
"page": 2,
"page_size": 10,
"total": 31,
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.PublicGamesListRequestToPayload, &lobbymodel.PublicGamesListRequest{Page: 2, PageSize: 10})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypePublicGamesList, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToPublicGamesListResponse(result.PayloadBytes)
require.NoError(t, err)
assert.Equal(t, 2, decoded.Page)
assert.Equal(t, 10, decoded.PageSize)
assert.Equal(t, 31, decoded.Total)
require.Len(t, decoded.Items, 1)
assert.Empty(t, decoded.Items[0].OwnerUserID)
}
func TestExecuteLobbyMyApplicationsList(t *testing.T) {
t.Parallel()
created := time.Date(2026, 5, 5, 10, 0, 0, 0, time.UTC)
decided := time.Date(2026, 5, 6, 12, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/api/v1/user/lobby/my/applications", r.URL.Path)
writeJSON(t, w, http.StatusOK, map[string]any{
"items": []map[string]any{
{
"application_id": "app-1",
"game_id": "public-1",
"applicant_user_id": "user-1",
"race_name": "Vegan Federation",
"status": "pending",
"created_at": created.Format(time.RFC3339Nano),
},
{
"application_id": "app-2",
"game_id": "public-2",
"applicant_user_id": "user-1",
"race_name": "Lithic Compact",
"status": "approved",
"created_at": created.Format(time.RFC3339Nano),
"decided_at": decided.Format(time.RFC3339Nano),
},
},
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.MyApplicationsListRequestToPayload, &lobbymodel.MyApplicationsListRequest{})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeMyApplicationsList, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToMyApplicationsListResponse(result.PayloadBytes)
require.NoError(t, err)
require.Len(t, decoded.Items, 2)
assert.Equal(t, "pending", decoded.Items[0].Status)
assert.Nil(t, decoded.Items[0].DecidedAt)
require.NotNil(t, decoded.Items[1].DecidedAt)
assert.Equal(t, decided, *decoded.Items[1].DecidedAt)
}
func TestExecuteLobbyMyInvitesList(t *testing.T) {
t.Parallel()
created := time.Date(2026, 5, 5, 10, 0, 0, 0, time.UTC)
expires := time.Date(2026, 5, 8, 10, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, "/api/v1/user/lobby/my/invites", r.URL.Path)
writeJSON(t, w, http.StatusOK, map[string]any{
"items": []map[string]any{{
"invite_id": "invite-1",
"game_id": "private-1",
"inviter_user_id": "user-host",
"invited_user_id": "user-1",
"race_name": "Vegan Federation",
"status": "pending",
"created_at": created.Format(time.RFC3339Nano),
"expires_at": expires.Format(time.RFC3339Nano),
}},
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.MyInvitesListRequestToPayload, &lobbymodel.MyInvitesListRequest{})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeMyInvitesList, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToMyInvitesListResponse(result.PayloadBytes)
require.NoError(t, err)
require.Len(t, decoded.Items, 1)
assert.Equal(t, "user-1", decoded.Items[0].InvitedUserID)
assert.Empty(t, decoded.Items[0].Code)
assert.Equal(t, expires, decoded.Items[0].ExpiresAt)
}
func TestExecuteLobbyGameCreatePostsPrivateAndProjectsToSummary(t *testing.T) {
t.Parallel()
enrollment := time.Date(2026, 6, 1, 12, 0, 0, 0, time.UTC)
created := time.Date(2026, 5, 7, 10, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodPost, r.Method)
require.Equal(t, "/api/v1/user/lobby/games", r.URL.Path)
var body map[string]any
raw, err := io.ReadAll(r.Body)
require.NoError(t, err)
require.NoError(t, json.Unmarshal(raw, &body))
assert.Equal(t, "private", body["visibility"])
assert.Equal(t, "First Contact", body["game_name"])
assert.Equal(t, "0 0 * * *", body["turn_schedule"])
// Backend always returns the full GameDetail including runtime
// snapshot fields the gateway must tolerate.
writeJSON(t, w, http.StatusCreated, map[string]any{
"game_id": "newly-created",
"game_name": "First Contact",
"game_type": "private",
"status": "draft",
"owner_user_id": "user-1",
"min_players": 2,
"max_players": 8,
"enrollment_ends_at": enrollment.Format(time.RFC3339Nano),
"created_at": created.Format(time.RFC3339Nano),
"updated_at": created.Format(time.RFC3339Nano),
"visibility": "private",
"description": "",
"turn_schedule": "0 0 * * *",
"target_engine_version": "v1",
"start_gap_hours": 24,
"start_gap_players": 2,
"current_turn": 0,
"runtime_status": "",
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.GameCreateRequestToPayload, &lobbymodel.GameCreateRequest{
GameName: "First Contact",
Description: "",
MinPlayers: 2,
MaxPlayers: 8,
StartGapHours: 24,
StartGapPlayers: 2,
EnrollmentEndsAt: enrollment,
TurnSchedule: "0 0 * * *",
TargetEngineVersion: "v1",
})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeGameCreate, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToGameCreateResponse(result.PayloadBytes)
require.NoError(t, err)
assert.Equal(t, "newly-created", decoded.Game.GameID)
assert.Equal(t, "draft", decoded.Game.Status)
}
func TestExecuteLobbyGameCreateRejectsEmptyGameName(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
t.Errorf("backend must not be hit on validation failure")
w.WriteHeader(http.StatusInternalServerError)
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.GameCreateRequestToPayload, &lobbymodel.GameCreateRequest{
MinPlayers: 2,
MaxPlayers: 8,
EnrollmentEndsAt: time.Date(2026, 6, 1, 12, 0, 0, 0, time.UTC),
TurnSchedule: "0 0 * * *",
TargetEngineVersion: "v1",
})
_, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeGameCreate, payload))
require.Error(t, err)
assert.Contains(t, err.Error(), "game_name must not be empty")
}
func TestExecuteLobbyApplicationSubmitPostsRaceName(t *testing.T) {
t.Parallel()
created := time.Date(2026, 5, 5, 10, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodPost, r.Method)
require.Equal(t, "/api/v1/user/lobby/games/public-1/applications", r.URL.Path)
var body map[string]any
raw, err := io.ReadAll(r.Body)
require.NoError(t, err)
require.NoError(t, json.Unmarshal(raw, &body))
assert.Equal(t, "Vegan Federation", body["race_name"])
writeJSON(t, w, http.StatusCreated, map[string]any{
"application_id": "app-3",
"game_id": "public-1",
"applicant_user_id": "user-1",
"race_name": "Vegan Federation",
"status": "pending",
"created_at": created.Format(time.RFC3339Nano),
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.ApplicationSubmitRequestToPayload, &lobbymodel.ApplicationSubmitRequest{
GameID: "public-1",
RaceName: "Vegan Federation",
})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeApplicationSubmit, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToApplicationSubmitResponse(result.PayloadBytes)
require.NoError(t, err)
assert.Equal(t, "app-3", decoded.Application.ApplicationID)
assert.Equal(t, "pending", decoded.Application.Status)
}
func TestExecuteLobbyInviteRedeemPostsToBackend(t *testing.T) {
t.Parallel()
created := time.Date(2026, 5, 5, 10, 0, 0, 0, time.UTC)
expires := time.Date(2026, 5, 8, 10, 0, 0, 0, time.UTC)
decided := time.Date(2026, 5, 6, 12, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodPost, r.Method)
require.Equal(t, "/api/v1/user/lobby/games/private-1/invites/invite-1/redeem", r.URL.Path)
writeJSON(t, w, http.StatusOK, map[string]any{
"invite_id": "invite-1",
"game_id": "private-1",
"inviter_user_id": "user-host",
"invited_user_id": "user-1",
"race_name": "Vegan Federation",
"status": "accepted",
"created_at": created.Format(time.RFC3339Nano),
"expires_at": expires.Format(time.RFC3339Nano),
"decided_at": decided.Format(time.RFC3339Nano),
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.InviteRedeemRequestToPayload, &lobbymodel.InviteRedeemRequest{GameID: "private-1", InviteID: "invite-1"})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeInviteRedeem, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToInviteRedeemResponse(result.PayloadBytes)
require.NoError(t, err)
assert.Equal(t, "accepted", decoded.Invite.Status)
}
func TestExecuteLobbyInviteDeclinePostsToBackend(t *testing.T) {
t.Parallel()
created := time.Date(2026, 5, 5, 10, 0, 0, 0, time.UTC)
expires := time.Date(2026, 5, 8, 10, 0, 0, 0, time.UTC)
decided := time.Date(2026, 5, 6, 12, 0, 0, 0, time.UTC)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
require.Equal(t, http.MethodPost, r.Method)
require.Equal(t, "/api/v1/user/lobby/games/private-1/invites/invite-1/decline", r.URL.Path)
writeJSON(t, w, http.StatusOK, map[string]any{
"invite_id": "invite-1",
"game_id": "private-1",
"inviter_user_id": "user-host",
"invited_user_id": "user-1",
"race_name": "Vegan Federation",
"status": "declined",
"created_at": created.Format(time.RFC3339Nano),
"expires_at": expires.Format(time.RFC3339Nano),
"decided_at": decided.Format(time.RFC3339Nano),
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.InviteDeclineRequestToPayload, &lobbymodel.InviteDeclineRequest{GameID: "private-1", InviteID: "invite-1"})
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeInviteDecline, payload))
require.NoError(t, err)
assert.Equal(t, "ok", result.ResultCode)
decoded, err := transcoder.PayloadToInviteDeclineResponse(result.PayloadBytes)
require.NoError(t, err)
assert.Equal(t, "declined", decoded.Invite.Status)
}
func TestExecuteLobbyProjectsBackendErrorAcrossCommands(t *testing.T) {
t.Parallel()
cases := []struct {
name string
messageType string
payload []byte
statusCode int
want string
}{
{
name: "public games conflict",
messageType: lobbymodel.MessageTypePublicGamesList,
payload: mustEncode(t, transcoder.PublicGamesListRequestToPayload, &lobbymodel.PublicGamesListRequest{Page: 1, PageSize: 50}),
statusCode: http.StatusConflict,
want: "conflict",
},
{
name: "applications forbidden",
messageType: lobbymodel.MessageTypeApplicationSubmit,
payload: mustEncode(t, transcoder.ApplicationSubmitRequestToPayload, &lobbymodel.ApplicationSubmitRequest{GameID: "g", RaceName: "r"}),
statusCode: http.StatusForbidden,
want: "forbidden",
},
{
name: "invite redeem not found",
messageType: lobbymodel.MessageTypeInviteRedeem,
payload: mustEncode(t, transcoder.InviteRedeemRequestToPayload, &lobbymodel.InviteRedeemRequest{GameID: "g", InviteID: "i"}),
statusCode: http.StatusNotFound,
want: "subject_not_found",
},
{
name: "create invalid request",
messageType: lobbymodel.MessageTypeGameCreate,
payload: mustEncode(t, transcoder.GameCreateRequestToPayload, validCreateRequest()),
statusCode: http.StatusBadRequest,
want: "invalid_request",
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
writeJSON(t, w, tc.statusCode, map[string]any{
"error": map[string]any{"code": tc.want, "message": "from backend"},
})
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
result, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, tc.messageType, tc.payload))
require.NoError(t, err)
assert.Equal(t, tc.want, result.ResultCode)
errResp, err := transcoder.PayloadToLobbyErrorResponse(result.PayloadBytes)
require.NoError(t, err)
assert.Equal(t, tc.want, errResp.Error.Code)
assert.Equal(t, "from backend", errResp.Error.Message)
})
}
}
func TestExecuteLobbyMapsServiceUnavailableToDownstreamError(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
payload := mustEncode(t, transcoder.MyGamesListRequestToPayload, &lobbymodel.MyGamesListRequest{})
_, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, lobbymodel.MessageTypeMyGamesList, payload))
require.Error(t, err)
assert.True(t, errors.Is(err, downstream.ErrDownstreamUnavailable))
}
func TestExecuteLobbyRejectsUnknownMessageType(t *testing.T) {
t.Parallel()
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
}))
t.Cleanup(server.Close)
client := newRESTClient(t, server)
_, err := client.ExecuteLobbyCommand(context.Background(), newAuthCommand(t, "lobby.unknown", []byte{0x01}))
require.Error(t, err)
assert.True(t, strings.Contains(err.Error(), "unsupported message type"))
}
func validCreateRequest() *lobbymodel.GameCreateRequest {
return &lobbymodel.GameCreateRequest{
GameName: "Test",
Description: "",
MinPlayers: 2,
MaxPlayers: 8,
StartGapHours: 24,
StartGapPlayers: 2,
EnrollmentEndsAt: time.Date(2026, 6, 1, 12, 0, 0, 0, time.UTC),
TurnSchedule: "0 0 * * *",
TargetEngineVersion: "v1",
}
}
+7
View File
@@ -39,7 +39,14 @@ func LobbyRoutes(client *RESTClient) map[string]downstream.Client {
}
return map[string]downstream.Client{
lobbymodel.MessageTypeMyGamesList: target,
lobbymodel.MessageTypePublicGamesList: target,
lobbymodel.MessageTypeMyApplicationsList: target,
lobbymodel.MessageTypeMyInvitesList: target,
lobbymodel.MessageTypeOpenEnrollment: target,
lobbymodel.MessageTypeGameCreate: target,
lobbymodel.MessageTypeApplicationSubmit: target,
lobbymodel.MessageTypeInviteRedeem: target,
lobbymodel.MessageTypeInviteDecline: target,
}
}
+169 -1
View File
@@ -9,10 +9,44 @@ const (
// used to read the calling user's own games.
MessageTypeMyGamesList = "lobby.my.games.list"
// MessageTypePublicGamesList is the authenticated gateway message
// type used to read the paginated list of joinable public games.
MessageTypePublicGamesList = "lobby.public.games.list"
// MessageTypeMyApplicationsList is the authenticated gateway message
// type used to read the caller's pending and decided applications to
// public games.
MessageTypeMyApplicationsList = "lobby.my.applications.list"
// MessageTypeMyInvitesList is the authenticated gateway message type
// used to read the caller's pending invites to private games.
MessageTypeMyInvitesList = "lobby.my.invites.list"
// MessageTypeOpenEnrollment is the authenticated gateway message
// type used by the game owner to transition a draft game to
// `enrollment_open`.
MessageTypeOpenEnrollment = "lobby.game.open-enrollment"
// MessageTypeGameCreate is the authenticated gateway message type
// used to create a private game owned by the caller. Public games
// are created exclusively through the admin surface; the gateway
// rejects any attempt to set visibility to `public`.
MessageTypeGameCreate = "lobby.game.create"
// MessageTypeApplicationSubmit is the authenticated gateway message
// type used by a user to submit an application to a public game in
// `enrollment_open`.
MessageTypeApplicationSubmit = "lobby.application.submit"
// MessageTypeInviteRedeem is the authenticated gateway message type
// used to accept an outstanding invite and create the corresponding
// membership.
MessageTypeInviteRedeem = "lobby.invite.redeem"
// MessageTypeInviteDecline is the authenticated gateway message type
// used to terminally decline an outstanding invite. No membership is
// created.
MessageTypeInviteDecline = "lobby.invite.decline"
)
// MyGamesListRequest stores the authenticated read request for the
@@ -26,7 +60,9 @@ type MyGamesListResponse struct {
Items []GameSummary `json:"items"`
}
// GameSummary stores one game record returned by `lobby.my.games.list`.
// GameSummary stores one game record returned by the various lobby
// list endpoints. `OwnerUserID` is empty for public games (no human
// owner).
type GameSummary struct {
GameID string `json:"game_id"`
GameName string `json:"game_name"`
@@ -40,6 +76,74 @@ type GameSummary struct {
UpdatedAt time.Time `json:"updated_at"`
}
// PublicGamesListRequest stores the paginated read request for joinable
// public games. Page numbers start at 1; page sizes are capped by the
// backend.
type PublicGamesListRequest struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// PublicGamesListResponse stores one page of public games together with
// the pagination metadata returned by the backend.
type PublicGamesListResponse struct {
Items []GameSummary `json:"items"`
Page int `json:"page"`
PageSize int `json:"page_size"`
Total int `json:"total"`
}
// MyApplicationsListRequest stores the authenticated read request for
// the caller's applications. Empty body — gateway derives identity from
// the authenticated session.
type MyApplicationsListRequest struct{}
// MyApplicationsListResponse stores the caller's application list,
// ordered as Lobby returns it.
type MyApplicationsListResponse struct {
Items []ApplicationSummary `json:"items"`
}
// ApplicationSummary stores a single application record returned by
// `lobby.my.applications.list` and `lobby.application.submit`.
// `DecidedAt` is nil while the application is pending.
type ApplicationSummary struct {
ApplicationID string `json:"application_id"`
GameID string `json:"game_id"`
ApplicantUserID string `json:"applicant_user_id"`
RaceName string `json:"race_name"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
DecidedAt *time.Time `json:"decided_at,omitempty"`
}
// MyInvitesListRequest stores the authenticated read request for the
// caller's invites. Empty body.
type MyInvitesListRequest struct{}
// MyInvitesListResponse stores the caller's invite list.
type MyInvitesListResponse struct {
Items []InviteSummary `json:"items"`
}
// InviteSummary stores one invite record returned by
// `lobby.my.invites.list`, `lobby.invite.redeem`, and
// `lobby.invite.decline`. `InvitedUserID` is empty for code-based
// invites; `Code` is empty for user-bound invites; `DecidedAt` is nil
// while the invite is still pending.
type InviteSummary struct {
InviteID string `json:"invite_id"`
GameID string `json:"game_id"`
InviterUserID string `json:"inviter_user_id"`
InvitedUserID string `json:"invited_user_id,omitempty"`
Code string `json:"code,omitempty"`
RaceName string `json:"race_name"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
DecidedAt *time.Time `json:"decided_at,omitempty"`
}
// OpenEnrollmentRequest stores the owner-only command that transitions
// a game from `draft` to `enrollment_open`.
type OpenEnrollmentRequest struct {
@@ -55,6 +159,70 @@ type OpenEnrollmentResponse struct {
Status string `json:"status"`
}
// GameCreateRequest stores the create-game command issued by the user
// surface. Visibility is always `private` here; the gateway rejects any
// other value before forwarding to backend, mirroring the FUNCTIONAL
// §3.3 invariant.
type GameCreateRequest struct {
GameName string `json:"game_name"`
Description string `json:"description"`
MinPlayers int `json:"min_players"`
MaxPlayers int `json:"max_players"`
StartGapHours int `json:"start_gap_hours"`
StartGapPlayers int `json:"start_gap_players"`
EnrollmentEndsAt time.Time `json:"enrollment_ends_at"`
TurnSchedule string `json:"turn_schedule"`
TargetEngineVersion string `json:"target_engine_version"`
}
// GameCreateResponse stores the freshly created game projected onto the
// shared GameSummary shape — the gateway does not expose runtime fields
// at create time because the game is always in `draft` until the owner
// transitions it.
type GameCreateResponse struct {
Game GameSummary `json:"game"`
}
// ApplicationSubmitRequest stores the submit-application command. The
// game must be public and in `enrollment_open`; backend rejects all
// other states.
type ApplicationSubmitRequest struct {
GameID string `json:"game_id"`
RaceName string `json:"race_name"`
}
// ApplicationSubmitResponse wraps the application created by a
// successful submit-application call.
type ApplicationSubmitResponse struct {
Application ApplicationSummary `json:"application"`
}
// InviteRedeemRequest accepts a pending invite and creates the
// corresponding membership at the backend.
type InviteRedeemRequest struct {
GameID string `json:"game_id"`
InviteID string `json:"invite_id"`
}
// InviteRedeemResponse wraps the invite record updated by a successful
// redeem (status transitions to `accepted`).
type InviteRedeemResponse struct {
Invite InviteSummary `json:"invite"`
}
// InviteDeclineRequest terminally declines a pending invite. No
// membership is created.
type InviteDeclineRequest struct {
GameID string `json:"game_id"`
InviteID string `json:"invite_id"`
}
// InviteDeclineResponse wraps the invite record updated by a successful
// decline (status transitions to `declined`).
type InviteDeclineResponse struct {
Invite InviteSummary `json:"invite"`
}
// ErrorBody stores the canonical Lobby error envelope code/message
// pair.
type ErrorBody struct {
+126 -1
View File
@@ -4,7 +4,8 @@
// from the verified session and forwards it as `X-User-Id` to lobby.
namespace lobby;
// GameSummary stores one game record returned by `lobby.my.games.list`.
// GameSummary stores one game record returned by the lobby list
// endpoints. owner_user_id is empty for public games (no human owner).
// The shape matches `lobby/openapi.yaml` `MyGameSummary`.
table GameSummary {
game_id:string;
@@ -31,6 +32,71 @@ table MyGamesListResponse {
items:[GameSummary];
}
// PublicGamesListRequest stores the paginated read request for joinable
// public games. Page numbers start at 1; backend caps page_size.
table PublicGamesListRequest {
page:int32;
page_size:int32;
}
// PublicGamesListResponse stores one page of public games together with
// the pagination metadata.
table PublicGamesListResponse {
items:[GameSummary];
page:int32;
page_size:int32;
total:int32;
}
// ApplicationSummary stores one application record. decided_at_ms is 0
// while the application is pending.
table ApplicationSummary {
application_id:string;
game_id:string;
applicant_user_id:string;
race_name:string;
status:string;
created_at_ms:int64;
decided_at_ms:int64;
}
// MyApplicationsListRequest stores the authenticated read request for
// the caller's applications. Empty body.
table MyApplicationsListRequest {
}
// MyApplicationsListResponse stores the caller's applications in the
// order the backend returns them.
table MyApplicationsListResponse {
items:[ApplicationSummary];
}
// InviteSummary stores one invite record. invited_user_id is empty for
// code-based invites; code is empty for user-bound invites;
// decided_at_ms is 0 while the invite is still pending.
table InviteSummary {
invite_id:string;
game_id:string;
inviter_user_id:string;
invited_user_id:string;
code:string;
race_name:string;
status:string;
created_at_ms:int64;
expires_at_ms:int64;
decided_at_ms:int64;
}
// MyInvitesListRequest stores the authenticated read request for the
// caller's invites. Empty body.
table MyInvitesListRequest {
}
// MyInvitesListResponse stores the caller's invite list.
table MyInvitesListResponse {
items:[InviteSummary];
}
// OpenEnrollmentRequest stores the owner-only command that transitions
// a game from `draft` to `enrollment_open`.
table OpenEnrollmentRequest {
@@ -43,6 +109,65 @@ table OpenEnrollmentResponse {
status:string;
}
// GameCreateRequest stores the create-game command. Visibility is
// always `private` for the user surface; the gateway rejects any other
// value before forwarding to backend.
table GameCreateRequest {
game_name:string;
description:string;
min_players:int32;
max_players:int32;
start_gap_hours:int32;
start_gap_players:int32;
enrollment_ends_at_ms:int64;
turn_schedule:string;
target_engine_version:string;
}
// GameCreateResponse wraps the freshly created game projected onto the
// shared GameSummary shape.
table GameCreateResponse {
game:GameSummary;
}
// ApplicationSubmitRequest stores the submit-application command for a
// public game in `enrollment_open`.
table ApplicationSubmitRequest {
game_id:string;
race_name:string;
}
// ApplicationSubmitResponse wraps the freshly created application
// record.
table ApplicationSubmitResponse {
application:ApplicationSummary;
}
// InviteRedeemRequest accepts a pending invite and creates the
// corresponding membership.
table InviteRedeemRequest {
game_id:string;
invite_id:string;
}
// InviteRedeemResponse wraps the updated invite record (status
// transitioned to `accepted`).
table InviteRedeemResponse {
invite:InviteSummary;
}
// InviteDeclineRequest terminally declines a pending invite.
table InviteDeclineRequest {
game_id:string;
invite_id:string;
}
// InviteDeclineResponse wraps the updated invite record (status
// transitioned to `declined`).
table InviteDeclineResponse {
invite:InviteSummary;
}
// ErrorBody stores the canonical lobby error envelope code/message
// pair.
table ErrorBody {
@@ -0,0 +1,71 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type ApplicationSubmitRequest struct {
_tab flatbuffers.Table
}
func GetRootAsApplicationSubmitRequest(buf []byte, offset flatbuffers.UOffsetT) *ApplicationSubmitRequest {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &ApplicationSubmitRequest{}
x.Init(buf, n+offset)
return x
}
func FinishApplicationSubmitRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsApplicationSubmitRequest(buf []byte, offset flatbuffers.UOffsetT) *ApplicationSubmitRequest {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &ApplicationSubmitRequest{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedApplicationSubmitRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *ApplicationSubmitRequest) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *ApplicationSubmitRequest) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *ApplicationSubmitRequest) GameId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *ApplicationSubmitRequest) RaceName() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func ApplicationSubmitRequestStart(builder *flatbuffers.Builder) {
builder.StartObject(2)
}
func ApplicationSubmitRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0)
}
func ApplicationSubmitRequestAddRaceName(builder *flatbuffers.Builder, raceName flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(raceName), 0)
}
func ApplicationSubmitRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,65 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type ApplicationSubmitResponse struct {
_tab flatbuffers.Table
}
func GetRootAsApplicationSubmitResponse(buf []byte, offset flatbuffers.UOffsetT) *ApplicationSubmitResponse {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &ApplicationSubmitResponse{}
x.Init(buf, n+offset)
return x
}
func FinishApplicationSubmitResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsApplicationSubmitResponse(buf []byte, offset flatbuffers.UOffsetT) *ApplicationSubmitResponse {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &ApplicationSubmitResponse{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedApplicationSubmitResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *ApplicationSubmitResponse) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *ApplicationSubmitResponse) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *ApplicationSubmitResponse) Application(obj *ApplicationSummary) *ApplicationSummary {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Indirect(o + rcv._tab.Pos)
if obj == nil {
obj = new(ApplicationSummary)
}
obj.Init(rcv._tab.Bytes, x)
return obj
}
return nil
}
func ApplicationSubmitResponseStart(builder *flatbuffers.Builder) {
builder.StartObject(1)
}
func ApplicationSubmitResponseAddApplication(builder *flatbuffers.Builder, application flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(application), 0)
}
func ApplicationSubmitResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
+134
View File
@@ -0,0 +1,134 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type ApplicationSummary struct {
_tab flatbuffers.Table
}
func GetRootAsApplicationSummary(buf []byte, offset flatbuffers.UOffsetT) *ApplicationSummary {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &ApplicationSummary{}
x.Init(buf, n+offset)
return x
}
func FinishApplicationSummaryBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsApplicationSummary(buf []byte, offset flatbuffers.UOffsetT) *ApplicationSummary {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &ApplicationSummary{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedApplicationSummaryBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *ApplicationSummary) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *ApplicationSummary) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *ApplicationSummary) ApplicationId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *ApplicationSummary) GameId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *ApplicationSummary) ApplicantUserId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *ApplicationSummary) RaceName() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *ApplicationSummary) Status() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(12))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *ApplicationSummary) CreatedAtMs() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
if o != 0 {
return rcv._tab.GetInt64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *ApplicationSummary) MutateCreatedAtMs(n int64) bool {
return rcv._tab.MutateInt64Slot(14, n)
}
func (rcv *ApplicationSummary) DecidedAtMs() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
if o != 0 {
return rcv._tab.GetInt64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *ApplicationSummary) MutateDecidedAtMs(n int64) bool {
return rcv._tab.MutateInt64Slot(16, n)
}
func ApplicationSummaryStart(builder *flatbuffers.Builder) {
builder.StartObject(7)
}
func ApplicationSummaryAddApplicationId(builder *flatbuffers.Builder, applicationId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(applicationId), 0)
}
func ApplicationSummaryAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(gameId), 0)
}
func ApplicationSummaryAddApplicantUserId(builder *flatbuffers.Builder, applicantUserId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(applicantUserId), 0)
}
func ApplicationSummaryAddRaceName(builder *flatbuffers.Builder, raceName flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(raceName), 0)
}
func ApplicationSummaryAddStatus(builder *flatbuffers.Builder, status flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(4, flatbuffers.UOffsetT(status), 0)
}
func ApplicationSummaryAddCreatedAtMs(builder *flatbuffers.Builder, createdAtMs int64) {
builder.PrependInt64Slot(5, createdAtMs, 0)
}
func ApplicationSummaryAddDecidedAtMs(builder *flatbuffers.Builder, decidedAtMs int64) {
builder.PrependInt64Slot(6, decidedAtMs, 0)
}
func ApplicationSummaryEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
+168
View File
@@ -0,0 +1,168 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type GameCreateRequest struct {
_tab flatbuffers.Table
}
func GetRootAsGameCreateRequest(buf []byte, offset flatbuffers.UOffsetT) *GameCreateRequest {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &GameCreateRequest{}
x.Init(buf, n+offset)
return x
}
func FinishGameCreateRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsGameCreateRequest(buf []byte, offset flatbuffers.UOffsetT) *GameCreateRequest {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &GameCreateRequest{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedGameCreateRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *GameCreateRequest) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *GameCreateRequest) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *GameCreateRequest) GameName() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *GameCreateRequest) Description() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *GameCreateRequest) MinPlayers() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *GameCreateRequest) MutateMinPlayers(n int32) bool {
return rcv._tab.MutateInt32Slot(8, n)
}
func (rcv *GameCreateRequest) MaxPlayers() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *GameCreateRequest) MutateMaxPlayers(n int32) bool {
return rcv._tab.MutateInt32Slot(10, n)
}
func (rcv *GameCreateRequest) StartGapHours() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(12))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *GameCreateRequest) MutateStartGapHours(n int32) bool {
return rcv._tab.MutateInt32Slot(12, n)
}
func (rcv *GameCreateRequest) StartGapPlayers() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *GameCreateRequest) MutateStartGapPlayers(n int32) bool {
return rcv._tab.MutateInt32Slot(14, n)
}
func (rcv *GameCreateRequest) EnrollmentEndsAtMs() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
if o != 0 {
return rcv._tab.GetInt64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *GameCreateRequest) MutateEnrollmentEndsAtMs(n int64) bool {
return rcv._tab.MutateInt64Slot(16, n)
}
func (rcv *GameCreateRequest) TurnSchedule() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(18))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *GameCreateRequest) TargetEngineVersion() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(20))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func GameCreateRequestStart(builder *flatbuffers.Builder) {
builder.StartObject(9)
}
func GameCreateRequestAddGameName(builder *flatbuffers.Builder, gameName flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameName), 0)
}
func GameCreateRequestAddDescription(builder *flatbuffers.Builder, description flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(description), 0)
}
func GameCreateRequestAddMinPlayers(builder *flatbuffers.Builder, minPlayers int32) {
builder.PrependInt32Slot(2, minPlayers, 0)
}
func GameCreateRequestAddMaxPlayers(builder *flatbuffers.Builder, maxPlayers int32) {
builder.PrependInt32Slot(3, maxPlayers, 0)
}
func GameCreateRequestAddStartGapHours(builder *flatbuffers.Builder, startGapHours int32) {
builder.PrependInt32Slot(4, startGapHours, 0)
}
func GameCreateRequestAddStartGapPlayers(builder *flatbuffers.Builder, startGapPlayers int32) {
builder.PrependInt32Slot(5, startGapPlayers, 0)
}
func GameCreateRequestAddEnrollmentEndsAtMs(builder *flatbuffers.Builder, enrollmentEndsAtMs int64) {
builder.PrependInt64Slot(6, enrollmentEndsAtMs, 0)
}
func GameCreateRequestAddTurnSchedule(builder *flatbuffers.Builder, turnSchedule flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(7, flatbuffers.UOffsetT(turnSchedule), 0)
}
func GameCreateRequestAddTargetEngineVersion(builder *flatbuffers.Builder, targetEngineVersion flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(8, flatbuffers.UOffsetT(targetEngineVersion), 0)
}
func GameCreateRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,65 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type GameCreateResponse struct {
_tab flatbuffers.Table
}
func GetRootAsGameCreateResponse(buf []byte, offset flatbuffers.UOffsetT) *GameCreateResponse {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &GameCreateResponse{}
x.Init(buf, n+offset)
return x
}
func FinishGameCreateResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsGameCreateResponse(buf []byte, offset flatbuffers.UOffsetT) *GameCreateResponse {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &GameCreateResponse{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedGameCreateResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *GameCreateResponse) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *GameCreateResponse) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *GameCreateResponse) Game(obj *GameSummary) *GameSummary {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Indirect(o + rcv._tab.Pos)
if obj == nil {
obj = new(GameSummary)
}
obj.Init(rcv._tab.Bytes, x)
return obj
}
return nil
}
func GameCreateResponseStart(builder *flatbuffers.Builder) {
builder.StartObject(1)
}
func GameCreateResponseAddGame(builder *flatbuffers.Builder, game flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(game), 0)
}
func GameCreateResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,71 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type InviteDeclineRequest struct {
_tab flatbuffers.Table
}
func GetRootAsInviteDeclineRequest(buf []byte, offset flatbuffers.UOffsetT) *InviteDeclineRequest {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &InviteDeclineRequest{}
x.Init(buf, n+offset)
return x
}
func FinishInviteDeclineRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsInviteDeclineRequest(buf []byte, offset flatbuffers.UOffsetT) *InviteDeclineRequest {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &InviteDeclineRequest{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedInviteDeclineRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *InviteDeclineRequest) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *InviteDeclineRequest) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *InviteDeclineRequest) GameId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteDeclineRequest) InviteId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func InviteDeclineRequestStart(builder *flatbuffers.Builder) {
builder.StartObject(2)
}
func InviteDeclineRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0)
}
func InviteDeclineRequestAddInviteId(builder *flatbuffers.Builder, inviteId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(inviteId), 0)
}
func InviteDeclineRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,65 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type InviteDeclineResponse struct {
_tab flatbuffers.Table
}
func GetRootAsInviteDeclineResponse(buf []byte, offset flatbuffers.UOffsetT) *InviteDeclineResponse {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &InviteDeclineResponse{}
x.Init(buf, n+offset)
return x
}
func FinishInviteDeclineResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsInviteDeclineResponse(buf []byte, offset flatbuffers.UOffsetT) *InviteDeclineResponse {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &InviteDeclineResponse{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedInviteDeclineResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *InviteDeclineResponse) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *InviteDeclineResponse) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *InviteDeclineResponse) Invite(obj *InviteSummary) *InviteSummary {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Indirect(o + rcv._tab.Pos)
if obj == nil {
obj = new(InviteSummary)
}
obj.Init(rcv._tab.Bytes, x)
return obj
}
return nil
}
func InviteDeclineResponseStart(builder *flatbuffers.Builder) {
builder.StartObject(1)
}
func InviteDeclineResponseAddInvite(builder *flatbuffers.Builder, invite flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(invite), 0)
}
func InviteDeclineResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,71 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type InviteRedeemRequest struct {
_tab flatbuffers.Table
}
func GetRootAsInviteRedeemRequest(buf []byte, offset flatbuffers.UOffsetT) *InviteRedeemRequest {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &InviteRedeemRequest{}
x.Init(buf, n+offset)
return x
}
func FinishInviteRedeemRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsInviteRedeemRequest(buf []byte, offset flatbuffers.UOffsetT) *InviteRedeemRequest {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &InviteRedeemRequest{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedInviteRedeemRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *InviteRedeemRequest) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *InviteRedeemRequest) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *InviteRedeemRequest) GameId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteRedeemRequest) InviteId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func InviteRedeemRequestStart(builder *flatbuffers.Builder) {
builder.StartObject(2)
}
func InviteRedeemRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0)
}
func InviteRedeemRequestAddInviteId(builder *flatbuffers.Builder, inviteId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(inviteId), 0)
}
func InviteRedeemRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,65 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type InviteRedeemResponse struct {
_tab flatbuffers.Table
}
func GetRootAsInviteRedeemResponse(buf []byte, offset flatbuffers.UOffsetT) *InviteRedeemResponse {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &InviteRedeemResponse{}
x.Init(buf, n+offset)
return x
}
func FinishInviteRedeemResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsInviteRedeemResponse(buf []byte, offset flatbuffers.UOffsetT) *InviteRedeemResponse {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &InviteRedeemResponse{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedInviteRedeemResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *InviteRedeemResponse) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *InviteRedeemResponse) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *InviteRedeemResponse) Invite(obj *InviteSummary) *InviteSummary {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Indirect(o + rcv._tab.Pos)
if obj == nil {
obj = new(InviteSummary)
}
obj.Init(rcv._tab.Bytes, x)
return obj
}
return nil
}
func InviteRedeemResponseStart(builder *flatbuffers.Builder) {
builder.StartObject(1)
}
func InviteRedeemResponseAddInvite(builder *flatbuffers.Builder, invite flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(invite), 0)
}
func InviteRedeemResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
+171
View File
@@ -0,0 +1,171 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type InviteSummary struct {
_tab flatbuffers.Table
}
func GetRootAsInviteSummary(buf []byte, offset flatbuffers.UOffsetT) *InviteSummary {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &InviteSummary{}
x.Init(buf, n+offset)
return x
}
func FinishInviteSummaryBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsInviteSummary(buf []byte, offset flatbuffers.UOffsetT) *InviteSummary {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &InviteSummary{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedInviteSummaryBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *InviteSummary) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *InviteSummary) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *InviteSummary) InviteId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteSummary) GameId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteSummary) InviterUserId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteSummary) InvitedUserId() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteSummary) Code() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(12))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteSummary) RaceName() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteSummary) Status() []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
if o != 0 {
return rcv._tab.ByteVector(o + rcv._tab.Pos)
}
return nil
}
func (rcv *InviteSummary) CreatedAtMs() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(18))
if o != 0 {
return rcv._tab.GetInt64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *InviteSummary) MutateCreatedAtMs(n int64) bool {
return rcv._tab.MutateInt64Slot(18, n)
}
func (rcv *InviteSummary) ExpiresAtMs() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(20))
if o != 0 {
return rcv._tab.GetInt64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *InviteSummary) MutateExpiresAtMs(n int64) bool {
return rcv._tab.MutateInt64Slot(20, n)
}
func (rcv *InviteSummary) DecidedAtMs() int64 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(22))
if o != 0 {
return rcv._tab.GetInt64(o + rcv._tab.Pos)
}
return 0
}
func (rcv *InviteSummary) MutateDecidedAtMs(n int64) bool {
return rcv._tab.MutateInt64Slot(22, n)
}
func InviteSummaryStart(builder *flatbuffers.Builder) {
builder.StartObject(10)
}
func InviteSummaryAddInviteId(builder *flatbuffers.Builder, inviteId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(inviteId), 0)
}
func InviteSummaryAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(gameId), 0)
}
func InviteSummaryAddInviterUserId(builder *flatbuffers.Builder, inviterUserId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(inviterUserId), 0)
}
func InviteSummaryAddInvitedUserId(builder *flatbuffers.Builder, invitedUserId flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(3, flatbuffers.UOffsetT(invitedUserId), 0)
}
func InviteSummaryAddCode(builder *flatbuffers.Builder, code flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(4, flatbuffers.UOffsetT(code), 0)
}
func InviteSummaryAddRaceName(builder *flatbuffers.Builder, raceName flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(5, flatbuffers.UOffsetT(raceName), 0)
}
func InviteSummaryAddStatus(builder *flatbuffers.Builder, status flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(6, flatbuffers.UOffsetT(status), 0)
}
func InviteSummaryAddCreatedAtMs(builder *flatbuffers.Builder, createdAtMs int64) {
builder.PrependInt64Slot(7, createdAtMs, 0)
}
func InviteSummaryAddExpiresAtMs(builder *flatbuffers.Builder, expiresAtMs int64) {
builder.PrependInt64Slot(8, expiresAtMs, 0)
}
func InviteSummaryAddDecidedAtMs(builder *flatbuffers.Builder, decidedAtMs int64) {
builder.PrependInt64Slot(9, decidedAtMs, 0)
}
func InviteSummaryEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,49 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type MyApplicationsListRequest struct {
_tab flatbuffers.Table
}
func GetRootAsMyApplicationsListRequest(buf []byte, offset flatbuffers.UOffsetT) *MyApplicationsListRequest {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &MyApplicationsListRequest{}
x.Init(buf, n+offset)
return x
}
func FinishMyApplicationsListRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsMyApplicationsListRequest(buf []byte, offset flatbuffers.UOffsetT) *MyApplicationsListRequest {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &MyApplicationsListRequest{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedMyApplicationsListRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *MyApplicationsListRequest) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *MyApplicationsListRequest) Table() flatbuffers.Table {
return rcv._tab
}
func MyApplicationsListRequestStart(builder *flatbuffers.Builder) {
builder.StartObject(0)
}
func MyApplicationsListRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,75 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type MyApplicationsListResponse struct {
_tab flatbuffers.Table
}
func GetRootAsMyApplicationsListResponse(buf []byte, offset flatbuffers.UOffsetT) *MyApplicationsListResponse {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &MyApplicationsListResponse{}
x.Init(buf, n+offset)
return x
}
func FinishMyApplicationsListResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsMyApplicationsListResponse(buf []byte, offset flatbuffers.UOffsetT) *MyApplicationsListResponse {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &MyApplicationsListResponse{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedMyApplicationsListResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *MyApplicationsListResponse) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *MyApplicationsListResponse) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *MyApplicationsListResponse) Items(obj *ApplicationSummary, j int) bool {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Vector(o)
x += flatbuffers.UOffsetT(j) * 4
x = rcv._tab.Indirect(x)
obj.Init(rcv._tab.Bytes, x)
return true
}
return false
}
func (rcv *MyApplicationsListResponse) ItemsLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func MyApplicationsListResponseStart(builder *flatbuffers.Builder) {
builder.StartObject(1)
}
func MyApplicationsListResponseAddItems(builder *flatbuffers.Builder, items flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(items), 0)
}
func MyApplicationsListResponseStartItemsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
return builder.StartVector(4, numElems, 4)
}
func MyApplicationsListResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,49 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type MyInvitesListRequest struct {
_tab flatbuffers.Table
}
func GetRootAsMyInvitesListRequest(buf []byte, offset flatbuffers.UOffsetT) *MyInvitesListRequest {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &MyInvitesListRequest{}
x.Init(buf, n+offset)
return x
}
func FinishMyInvitesListRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsMyInvitesListRequest(buf []byte, offset flatbuffers.UOffsetT) *MyInvitesListRequest {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &MyInvitesListRequest{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedMyInvitesListRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *MyInvitesListRequest) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *MyInvitesListRequest) Table() flatbuffers.Table {
return rcv._tab
}
func MyInvitesListRequestStart(builder *flatbuffers.Builder) {
builder.StartObject(0)
}
func MyInvitesListRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,75 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type MyInvitesListResponse struct {
_tab flatbuffers.Table
}
func GetRootAsMyInvitesListResponse(buf []byte, offset flatbuffers.UOffsetT) *MyInvitesListResponse {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &MyInvitesListResponse{}
x.Init(buf, n+offset)
return x
}
func FinishMyInvitesListResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsMyInvitesListResponse(buf []byte, offset flatbuffers.UOffsetT) *MyInvitesListResponse {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &MyInvitesListResponse{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedMyInvitesListResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *MyInvitesListResponse) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *MyInvitesListResponse) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *MyInvitesListResponse) Items(obj *InviteSummary, j int) bool {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Vector(o)
x += flatbuffers.UOffsetT(j) * 4
x = rcv._tab.Indirect(x)
obj.Init(rcv._tab.Bytes, x)
return true
}
return false
}
func (rcv *MyInvitesListResponse) ItemsLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func MyInvitesListResponseStart(builder *flatbuffers.Builder) {
builder.StartObject(1)
}
func MyInvitesListResponseAddItems(builder *flatbuffers.Builder, items flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(items), 0)
}
func MyInvitesListResponseStartItemsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
return builder.StartVector(4, numElems, 4)
}
func MyInvitesListResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,79 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type PublicGamesListRequest struct {
_tab flatbuffers.Table
}
func GetRootAsPublicGamesListRequest(buf []byte, offset flatbuffers.UOffsetT) *PublicGamesListRequest {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &PublicGamesListRequest{}
x.Init(buf, n+offset)
return x
}
func FinishPublicGamesListRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsPublicGamesListRequest(buf []byte, offset flatbuffers.UOffsetT) *PublicGamesListRequest {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &PublicGamesListRequest{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedPublicGamesListRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *PublicGamesListRequest) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *PublicGamesListRequest) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *PublicGamesListRequest) Page() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *PublicGamesListRequest) MutatePage(n int32) bool {
return rcv._tab.MutateInt32Slot(4, n)
}
func (rcv *PublicGamesListRequest) PageSize() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *PublicGamesListRequest) MutatePageSize(n int32) bool {
return rcv._tab.MutateInt32Slot(6, n)
}
func PublicGamesListRequestStart(builder *flatbuffers.Builder) {
builder.StartObject(2)
}
func PublicGamesListRequestAddPage(builder *flatbuffers.Builder, page int32) {
builder.PrependInt32Slot(0, page, 0)
}
func PublicGamesListRequestAddPageSize(builder *flatbuffers.Builder, pageSize int32) {
builder.PrependInt32Slot(1, pageSize, 0)
}
func PublicGamesListRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
@@ -0,0 +1,120 @@
// Code generated by the FlatBuffers compiler. DO NOT EDIT.
package lobby
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type PublicGamesListResponse struct {
_tab flatbuffers.Table
}
func GetRootAsPublicGamesListResponse(buf []byte, offset flatbuffers.UOffsetT) *PublicGamesListResponse {
n := flatbuffers.GetUOffsetT(buf[offset:])
x := &PublicGamesListResponse{}
x.Init(buf, n+offset)
return x
}
func FinishPublicGamesListResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.Finish(offset)
}
func GetSizePrefixedRootAsPublicGamesListResponse(buf []byte, offset flatbuffers.UOffsetT) *PublicGamesListResponse {
n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])
x := &PublicGamesListResponse{}
x.Init(buf, n+offset+flatbuffers.SizeUint32)
return x
}
func FinishSizePrefixedPublicGamesListResponseBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) {
builder.FinishSizePrefixed(offset)
}
func (rcv *PublicGamesListResponse) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *PublicGamesListResponse) Table() flatbuffers.Table {
return rcv._tab
}
func (rcv *PublicGamesListResponse) Items(obj *GameSummary, j int) bool {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Vector(o)
x += flatbuffers.UOffsetT(j) * 4
x = rcv._tab.Indirect(x)
obj.Init(rcv._tab.Bytes, x)
return true
}
return false
}
func (rcv *PublicGamesListResponse) ItemsLength() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func (rcv *PublicGamesListResponse) Page() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *PublicGamesListResponse) MutatePage(n int32) bool {
return rcv._tab.MutateInt32Slot(6, n)
}
func (rcv *PublicGamesListResponse) PageSize() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *PublicGamesListResponse) MutatePageSize(n int32) bool {
return rcv._tab.MutateInt32Slot(8, n)
}
func (rcv *PublicGamesListResponse) Total() int32 {
o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
if o != 0 {
return rcv._tab.GetInt32(o + rcv._tab.Pos)
}
return 0
}
func (rcv *PublicGamesListResponse) MutateTotal(n int32) bool {
return rcv._tab.MutateInt32Slot(10, n)
}
func PublicGamesListResponseStart(builder *flatbuffers.Builder) {
builder.StartObject(4)
}
func PublicGamesListResponseAddItems(builder *flatbuffers.Builder, items flatbuffers.UOffsetT) {
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(items), 0)
}
func PublicGamesListResponseStartItemsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
return builder.StartVector(4, numElems, 4)
}
func PublicGamesListResponseAddPage(builder *flatbuffers.Builder, page int32) {
builder.PrependInt32Slot(1, page, 0)
}
func PublicGamesListResponseAddPageSize(builder *flatbuffers.Builder, pageSize int32) {
builder.PrependInt32Slot(2, pageSize, 0)
}
func PublicGamesListResponseAddTotal(builder *flatbuffers.Builder, total int32) {
builder.PrependInt32Slot(3, total, 0)
}
func PublicGamesListResponseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
return builder.EndObject()
}
+641 -8
View File
@@ -53,14 +53,7 @@ func MyGamesListResponseToPayload(response *lobbymodel.MyGamesListResponse) ([]b
itemOffsets[index] = encodeGameSummary(builder, response.Items[index])
}
var itemsVector flatbuffers.UOffsetT
if len(itemOffsets) > 0 {
lobbyfbs.MyGamesListResponseStartItemsVector(builder, len(itemOffsets))
for index := len(itemOffsets) - 1; index >= 0; index-- {
builder.PrependUOffsetT(itemOffsets[index])
}
itemsVector = builder.EndVector(len(itemOffsets))
}
itemsVector := finishOffsetVector(builder, itemOffsets)
lobbyfbs.MyGamesListResponseStart(builder)
if itemsVector != 0 {
@@ -96,6 +89,248 @@ func PayloadToMyGamesListResponse(data []byte) (result *lobbymodel.MyGamesListRe
return out, nil
}
// PublicGamesListRequestToPayload converts lobbymodel.PublicGamesListRequest to
// FlatBuffers bytes.
func PublicGamesListRequestToPayload(request *lobbymodel.PublicGamesListRequest) ([]byte, error) {
if request == nil {
return nil, errors.New("encode public games list request payload: request is nil")
}
builder := flatbuffers.NewBuilder(32)
lobbyfbs.PublicGamesListRequestStart(builder)
lobbyfbs.PublicGamesListRequestAddPage(builder, int32(request.Page))
lobbyfbs.PublicGamesListRequestAddPageSize(builder, int32(request.PageSize))
offset := lobbyfbs.PublicGamesListRequestEnd(builder)
lobbyfbs.FinishPublicGamesListRequestBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToPublicGamesListRequest converts FlatBuffers payload bytes into
// lobbymodel.PublicGamesListRequest.
func PayloadToPublicGamesListRequest(data []byte) (result *lobbymodel.PublicGamesListRequest, err error) {
if len(data) == 0 {
return nil, errors.New("decode public games list request payload: data is empty")
}
defer recoverLobbyDecodePanic("decode public games list request payload", &result, &err)
request := lobbyfbs.GetRootAsPublicGamesListRequest(data, 0)
return &lobbymodel.PublicGamesListRequest{
Page: int(request.Page()),
PageSize: int(request.PageSize()),
}, nil
}
// PublicGamesListResponseToPayload converts lobbymodel.PublicGamesListResponse
// to FlatBuffers bytes.
func PublicGamesListResponseToPayload(response *lobbymodel.PublicGamesListResponse) ([]byte, error) {
if response == nil {
return nil, errors.New("encode public games list response payload: response is nil")
}
builder := flatbuffers.NewBuilder(512)
itemOffsets := make([]flatbuffers.UOffsetT, len(response.Items))
for index := range response.Items {
itemOffsets[index] = encodeGameSummary(builder, response.Items[index])
}
itemsVector := finishOffsetVector(builder, itemOffsets)
lobbyfbs.PublicGamesListResponseStart(builder)
if itemsVector != 0 {
lobbyfbs.PublicGamesListResponseAddItems(builder, itemsVector)
}
lobbyfbs.PublicGamesListResponseAddPage(builder, int32(response.Page))
lobbyfbs.PublicGamesListResponseAddPageSize(builder, int32(response.PageSize))
lobbyfbs.PublicGamesListResponseAddTotal(builder, int32(response.Total))
offset := lobbyfbs.PublicGamesListResponseEnd(builder)
lobbyfbs.FinishPublicGamesListResponseBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToPublicGamesListResponse converts FlatBuffers payload bytes into
// lobbymodel.PublicGamesListResponse.
func PayloadToPublicGamesListResponse(data []byte) (result *lobbymodel.PublicGamesListResponse, err error) {
if len(data) == 0 {
return nil, errors.New("decode public games list response payload: data is empty")
}
defer recoverLobbyDecodePanic("decode public games list response payload", &result, &err)
response := lobbyfbs.GetRootAsPublicGamesListResponse(data, 0)
out := &lobbymodel.PublicGamesListResponse{
Items: make([]lobbymodel.GameSummary, 0, response.ItemsLength()),
Page: int(response.Page()),
PageSize: int(response.PageSize()),
Total: int(response.Total()),
}
summary := new(lobbyfbs.GameSummary)
for index := 0; index < response.ItemsLength(); index++ {
if !response.Items(summary, index) {
return nil, fmt.Errorf("decode public games list response payload: items[%d] is missing", index)
}
out.Items = append(out.Items, decodeGameSummary(summary))
}
return out, nil
}
// MyApplicationsListRequestToPayload converts lobbymodel.MyApplicationsListRequest
// to FlatBuffers bytes.
func MyApplicationsListRequestToPayload(request *lobbymodel.MyApplicationsListRequest) ([]byte, error) {
if request == nil {
return nil, errors.New("encode my applications list request payload: request is nil")
}
builder := flatbuffers.NewBuilder(32)
lobbyfbs.MyApplicationsListRequestStart(builder)
offset := lobbyfbs.MyApplicationsListRequestEnd(builder)
lobbyfbs.FinishMyApplicationsListRequestBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToMyApplicationsListRequest converts FlatBuffers payload bytes into
// lobbymodel.MyApplicationsListRequest.
func PayloadToMyApplicationsListRequest(data []byte) (result *lobbymodel.MyApplicationsListRequest, err error) {
if len(data) == 0 {
return nil, errors.New("decode my applications list request payload: data is empty")
}
defer recoverLobbyDecodePanic("decode my applications list request payload", &result, &err)
_ = lobbyfbs.GetRootAsMyApplicationsListRequest(data, 0)
return &lobbymodel.MyApplicationsListRequest{}, nil
}
// MyApplicationsListResponseToPayload converts lobbymodel.MyApplicationsListResponse
// to FlatBuffers bytes.
func MyApplicationsListResponseToPayload(response *lobbymodel.MyApplicationsListResponse) ([]byte, error) {
if response == nil {
return nil, errors.New("encode my applications list response payload: response is nil")
}
builder := flatbuffers.NewBuilder(512)
itemOffsets := make([]flatbuffers.UOffsetT, len(response.Items))
for index := range response.Items {
itemOffsets[index] = encodeApplicationSummary(builder, response.Items[index])
}
itemsVector := finishOffsetVector(builder, itemOffsets)
lobbyfbs.MyApplicationsListResponseStart(builder)
if itemsVector != 0 {
lobbyfbs.MyApplicationsListResponseAddItems(builder, itemsVector)
}
offset := lobbyfbs.MyApplicationsListResponseEnd(builder)
lobbyfbs.FinishMyApplicationsListResponseBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToMyApplicationsListResponse converts FlatBuffers payload bytes into
// lobbymodel.MyApplicationsListResponse.
func PayloadToMyApplicationsListResponse(data []byte) (result *lobbymodel.MyApplicationsListResponse, err error) {
if len(data) == 0 {
return nil, errors.New("decode my applications list response payload: data is empty")
}
defer recoverLobbyDecodePanic("decode my applications list response payload", &result, &err)
response := lobbyfbs.GetRootAsMyApplicationsListResponse(data, 0)
out := &lobbymodel.MyApplicationsListResponse{
Items: make([]lobbymodel.ApplicationSummary, 0, response.ItemsLength()),
}
app := new(lobbyfbs.ApplicationSummary)
for index := 0; index < response.ItemsLength(); index++ {
if !response.Items(app, index) {
return nil, fmt.Errorf("decode my applications list response payload: items[%d] is missing", index)
}
out.Items = append(out.Items, decodeApplicationSummary(app))
}
return out, nil
}
// MyInvitesListRequestToPayload converts lobbymodel.MyInvitesListRequest
// to FlatBuffers bytes.
func MyInvitesListRequestToPayload(request *lobbymodel.MyInvitesListRequest) ([]byte, error) {
if request == nil {
return nil, errors.New("encode my invites list request payload: request is nil")
}
builder := flatbuffers.NewBuilder(32)
lobbyfbs.MyInvitesListRequestStart(builder)
offset := lobbyfbs.MyInvitesListRequestEnd(builder)
lobbyfbs.FinishMyInvitesListRequestBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToMyInvitesListRequest converts FlatBuffers payload bytes into
// lobbymodel.MyInvitesListRequest.
func PayloadToMyInvitesListRequest(data []byte) (result *lobbymodel.MyInvitesListRequest, err error) {
if len(data) == 0 {
return nil, errors.New("decode my invites list request payload: data is empty")
}
defer recoverLobbyDecodePanic("decode my invites list request payload", &result, &err)
_ = lobbyfbs.GetRootAsMyInvitesListRequest(data, 0)
return &lobbymodel.MyInvitesListRequest{}, nil
}
// MyInvitesListResponseToPayload converts lobbymodel.MyInvitesListResponse
// to FlatBuffers bytes.
func MyInvitesListResponseToPayload(response *lobbymodel.MyInvitesListResponse) ([]byte, error) {
if response == nil {
return nil, errors.New("encode my invites list response payload: response is nil")
}
builder := flatbuffers.NewBuilder(512)
itemOffsets := make([]flatbuffers.UOffsetT, len(response.Items))
for index := range response.Items {
itemOffsets[index] = encodeInviteSummary(builder, response.Items[index])
}
itemsVector := finishOffsetVector(builder, itemOffsets)
lobbyfbs.MyInvitesListResponseStart(builder)
if itemsVector != 0 {
lobbyfbs.MyInvitesListResponseAddItems(builder, itemsVector)
}
offset := lobbyfbs.MyInvitesListResponseEnd(builder)
lobbyfbs.FinishMyInvitesListResponseBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToMyInvitesListResponse converts FlatBuffers payload bytes into
// lobbymodel.MyInvitesListResponse.
func PayloadToMyInvitesListResponse(data []byte) (result *lobbymodel.MyInvitesListResponse, err error) {
if len(data) == 0 {
return nil, errors.New("decode my invites list response payload: data is empty")
}
defer recoverLobbyDecodePanic("decode my invites list response payload", &result, &err)
response := lobbyfbs.GetRootAsMyInvitesListResponse(data, 0)
out := &lobbymodel.MyInvitesListResponse{
Items: make([]lobbymodel.InviteSummary, 0, response.ItemsLength()),
}
invite := new(lobbyfbs.InviteSummary)
for index := 0; index < response.ItemsLength(); index++ {
if !response.Items(invite, index) {
return nil, fmt.Errorf("decode my invites list response payload: items[%d] is missing", index)
}
out.Items = append(out.Items, decodeInviteSummary(invite))
}
return out, nil
}
// OpenEnrollmentRequestToPayload converts lobbymodel.OpenEnrollmentRequest to
// FlatBuffers bytes suitable for the authenticated gateway transport.
func OpenEnrollmentRequestToPayload(request *lobbymodel.OpenEnrollmentRequest) ([]byte, error) {
@@ -165,6 +400,292 @@ func PayloadToOpenEnrollmentResponse(data []byte) (result *lobbymodel.OpenEnroll
}, nil
}
// GameCreateRequestToPayload converts lobbymodel.GameCreateRequest to
// FlatBuffers bytes.
func GameCreateRequestToPayload(request *lobbymodel.GameCreateRequest) ([]byte, error) {
if request == nil {
return nil, errors.New("encode game create request payload: request is nil")
}
builder := flatbuffers.NewBuilder(256)
gameName := builder.CreateString(request.GameName)
description := builder.CreateString(request.Description)
turnSchedule := builder.CreateString(request.TurnSchedule)
targetEngineVersion := builder.CreateString(request.TargetEngineVersion)
lobbyfbs.GameCreateRequestStart(builder)
lobbyfbs.GameCreateRequestAddGameName(builder, gameName)
lobbyfbs.GameCreateRequestAddDescription(builder, description)
lobbyfbs.GameCreateRequestAddMinPlayers(builder, int32(request.MinPlayers))
lobbyfbs.GameCreateRequestAddMaxPlayers(builder, int32(request.MaxPlayers))
lobbyfbs.GameCreateRequestAddStartGapHours(builder, int32(request.StartGapHours))
lobbyfbs.GameCreateRequestAddStartGapPlayers(builder, int32(request.StartGapPlayers))
lobbyfbs.GameCreateRequestAddEnrollmentEndsAtMs(builder, request.EnrollmentEndsAt.UTC().UnixMilli())
lobbyfbs.GameCreateRequestAddTurnSchedule(builder, turnSchedule)
lobbyfbs.GameCreateRequestAddTargetEngineVersion(builder, targetEngineVersion)
offset := lobbyfbs.GameCreateRequestEnd(builder)
lobbyfbs.FinishGameCreateRequestBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToGameCreateRequest converts FlatBuffers payload bytes into
// lobbymodel.GameCreateRequest.
func PayloadToGameCreateRequest(data []byte) (result *lobbymodel.GameCreateRequest, err error) {
if len(data) == 0 {
return nil, errors.New("decode game create request payload: data is empty")
}
defer recoverLobbyDecodePanic("decode game create request payload", &result, &err)
request := lobbyfbs.GetRootAsGameCreateRequest(data, 0)
return &lobbymodel.GameCreateRequest{
GameName: string(request.GameName()),
Description: string(request.Description()),
MinPlayers: int(request.MinPlayers()),
MaxPlayers: int(request.MaxPlayers()),
StartGapHours: int(request.StartGapHours()),
StartGapPlayers: int(request.StartGapPlayers()),
EnrollmentEndsAt: time.UnixMilli(request.EnrollmentEndsAtMs()).UTC(),
TurnSchedule: string(request.TurnSchedule()),
TargetEngineVersion: string(request.TargetEngineVersion()),
}, nil
}
// GameCreateResponseToPayload converts lobbymodel.GameCreateResponse to
// FlatBuffers bytes.
func GameCreateResponseToPayload(response *lobbymodel.GameCreateResponse) ([]byte, error) {
if response == nil {
return nil, errors.New("encode game create response payload: response is nil")
}
builder := flatbuffers.NewBuilder(256)
gameOffset := encodeGameSummary(builder, response.Game)
lobbyfbs.GameCreateResponseStart(builder)
lobbyfbs.GameCreateResponseAddGame(builder, gameOffset)
offset := lobbyfbs.GameCreateResponseEnd(builder)
lobbyfbs.FinishGameCreateResponseBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToGameCreateResponse converts FlatBuffers payload bytes into
// lobbymodel.GameCreateResponse.
func PayloadToGameCreateResponse(data []byte) (result *lobbymodel.GameCreateResponse, err error) {
if len(data) == 0 {
return nil, errors.New("decode game create response payload: data is empty")
}
defer recoverLobbyDecodePanic("decode game create response payload", &result, &err)
response := lobbyfbs.GetRootAsGameCreateResponse(data, 0)
game := response.Game(nil)
if game == nil {
return nil, errors.New("decode game create response payload: game is missing")
}
return &lobbymodel.GameCreateResponse{
Game: decodeGameSummary(game),
}, nil
}
// ApplicationSubmitRequestToPayload converts lobbymodel.ApplicationSubmitRequest
// to FlatBuffers bytes.
func ApplicationSubmitRequestToPayload(request *lobbymodel.ApplicationSubmitRequest) ([]byte, error) {
if request == nil {
return nil, errors.New("encode application submit request payload: request is nil")
}
builder := flatbuffers.NewBuilder(128)
gameID := builder.CreateString(request.GameID)
raceName := builder.CreateString(request.RaceName)
lobbyfbs.ApplicationSubmitRequestStart(builder)
lobbyfbs.ApplicationSubmitRequestAddGameId(builder, gameID)
lobbyfbs.ApplicationSubmitRequestAddRaceName(builder, raceName)
offset := lobbyfbs.ApplicationSubmitRequestEnd(builder)
lobbyfbs.FinishApplicationSubmitRequestBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToApplicationSubmitRequest converts FlatBuffers payload bytes into
// lobbymodel.ApplicationSubmitRequest.
func PayloadToApplicationSubmitRequest(data []byte) (result *lobbymodel.ApplicationSubmitRequest, err error) {
if len(data) == 0 {
return nil, errors.New("decode application submit request payload: data is empty")
}
defer recoverLobbyDecodePanic("decode application submit request payload", &result, &err)
request := lobbyfbs.GetRootAsApplicationSubmitRequest(data, 0)
return &lobbymodel.ApplicationSubmitRequest{
GameID: string(request.GameId()),
RaceName: string(request.RaceName()),
}, nil
}
// ApplicationSubmitResponseToPayload converts lobbymodel.ApplicationSubmitResponse
// to FlatBuffers bytes.
func ApplicationSubmitResponseToPayload(response *lobbymodel.ApplicationSubmitResponse) ([]byte, error) {
if response == nil {
return nil, errors.New("encode application submit response payload: response is nil")
}
builder := flatbuffers.NewBuilder(256)
appOffset := encodeApplicationSummary(builder, response.Application)
lobbyfbs.ApplicationSubmitResponseStart(builder)
lobbyfbs.ApplicationSubmitResponseAddApplication(builder, appOffset)
offset := lobbyfbs.ApplicationSubmitResponseEnd(builder)
lobbyfbs.FinishApplicationSubmitResponseBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToApplicationSubmitResponse converts FlatBuffers payload bytes into
// lobbymodel.ApplicationSubmitResponse.
func PayloadToApplicationSubmitResponse(data []byte) (result *lobbymodel.ApplicationSubmitResponse, err error) {
if len(data) == 0 {
return nil, errors.New("decode application submit response payload: data is empty")
}
defer recoverLobbyDecodePanic("decode application submit response payload", &result, &err)
response := lobbyfbs.GetRootAsApplicationSubmitResponse(data, 0)
app := response.Application(nil)
if app == nil {
return nil, errors.New("decode application submit response payload: application is missing")
}
return &lobbymodel.ApplicationSubmitResponse{
Application: decodeApplicationSummary(app),
}, nil
}
// InviteRedeemRequestToPayload converts lobbymodel.InviteRedeemRequest to
// FlatBuffers bytes.
func InviteRedeemRequestToPayload(request *lobbymodel.InviteRedeemRequest) ([]byte, error) {
if request == nil {
return nil, errors.New("encode invite redeem request payload: request is nil")
}
return encodeInviteAction(request.GameID, request.InviteID, true)
}
// PayloadToInviteRedeemRequest converts FlatBuffers payload bytes into
// lobbymodel.InviteRedeemRequest.
func PayloadToInviteRedeemRequest(data []byte) (result *lobbymodel.InviteRedeemRequest, err error) {
if len(data) == 0 {
return nil, errors.New("decode invite redeem request payload: data is empty")
}
defer recoverLobbyDecodePanic("decode invite redeem request payload", &result, &err)
request := lobbyfbs.GetRootAsInviteRedeemRequest(data, 0)
return &lobbymodel.InviteRedeemRequest{
GameID: string(request.GameId()),
InviteID: string(request.InviteId()),
}, nil
}
// InviteRedeemResponseToPayload converts lobbymodel.InviteRedeemResponse to
// FlatBuffers bytes.
func InviteRedeemResponseToPayload(response *lobbymodel.InviteRedeemResponse) ([]byte, error) {
if response == nil {
return nil, errors.New("encode invite redeem response payload: response is nil")
}
builder := flatbuffers.NewBuilder(256)
inviteOffset := encodeInviteSummary(builder, response.Invite)
lobbyfbs.InviteRedeemResponseStart(builder)
lobbyfbs.InviteRedeemResponseAddInvite(builder, inviteOffset)
offset := lobbyfbs.InviteRedeemResponseEnd(builder)
lobbyfbs.FinishInviteRedeemResponseBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToInviteRedeemResponse converts FlatBuffers payload bytes into
// lobbymodel.InviteRedeemResponse.
func PayloadToInviteRedeemResponse(data []byte) (result *lobbymodel.InviteRedeemResponse, err error) {
if len(data) == 0 {
return nil, errors.New("decode invite redeem response payload: data is empty")
}
defer recoverLobbyDecodePanic("decode invite redeem response payload", &result, &err)
response := lobbyfbs.GetRootAsInviteRedeemResponse(data, 0)
invite := response.Invite(nil)
if invite == nil {
return nil, errors.New("decode invite redeem response payload: invite is missing")
}
return &lobbymodel.InviteRedeemResponse{
Invite: decodeInviteSummary(invite),
}, nil
}
// InviteDeclineRequestToPayload converts lobbymodel.InviteDeclineRequest to
// FlatBuffers bytes.
func InviteDeclineRequestToPayload(request *lobbymodel.InviteDeclineRequest) ([]byte, error) {
if request == nil {
return nil, errors.New("encode invite decline request payload: request is nil")
}
return encodeInviteAction(request.GameID, request.InviteID, false)
}
// PayloadToInviteDeclineRequest converts FlatBuffers payload bytes into
// lobbymodel.InviteDeclineRequest.
func PayloadToInviteDeclineRequest(data []byte) (result *lobbymodel.InviteDeclineRequest, err error) {
if len(data) == 0 {
return nil, errors.New("decode invite decline request payload: data is empty")
}
defer recoverLobbyDecodePanic("decode invite decline request payload", &result, &err)
request := lobbyfbs.GetRootAsInviteDeclineRequest(data, 0)
return &lobbymodel.InviteDeclineRequest{
GameID: string(request.GameId()),
InviteID: string(request.InviteId()),
}, nil
}
// InviteDeclineResponseToPayload converts lobbymodel.InviteDeclineResponse to
// FlatBuffers bytes.
func InviteDeclineResponseToPayload(response *lobbymodel.InviteDeclineResponse) ([]byte, error) {
if response == nil {
return nil, errors.New("encode invite decline response payload: response is nil")
}
builder := flatbuffers.NewBuilder(256)
inviteOffset := encodeInviteSummary(builder, response.Invite)
lobbyfbs.InviteDeclineResponseStart(builder)
lobbyfbs.InviteDeclineResponseAddInvite(builder, inviteOffset)
offset := lobbyfbs.InviteDeclineResponseEnd(builder)
lobbyfbs.FinishInviteDeclineResponseBuffer(builder, offset)
return builder.FinishedBytes(), nil
}
// PayloadToInviteDeclineResponse converts FlatBuffers payload bytes into
// lobbymodel.InviteDeclineResponse.
func PayloadToInviteDeclineResponse(data []byte) (result *lobbymodel.InviteDeclineResponse, err error) {
if len(data) == 0 {
return nil, errors.New("decode invite decline response payload: data is empty")
}
defer recoverLobbyDecodePanic("decode invite decline response payload", &result, &err)
response := lobbyfbs.GetRootAsInviteDeclineResponse(data, 0)
invite := response.Invite(nil)
if invite == nil {
return nil, errors.New("decode invite decline response payload: invite is missing")
}
return &lobbymodel.InviteDeclineResponse{
Invite: decodeInviteSummary(invite),
}, nil
}
// LobbyErrorResponseToPayload converts lobbymodel.ErrorResponse to FlatBuffers
// bytes suitable for the authenticated gateway transport.
func LobbyErrorResponseToPayload(response *lobbymodel.ErrorResponse) ([]byte, error) {
@@ -212,6 +733,38 @@ func PayloadToLobbyErrorResponse(data []byte) (result *lobbymodel.ErrorResponse,
}, nil
}
func encodeInviteAction(gameID, inviteID string, redeem bool) ([]byte, error) {
builder := flatbuffers.NewBuilder(128)
gameOffset := builder.CreateString(gameID)
inviteOffset := builder.CreateString(inviteID)
if redeem {
lobbyfbs.InviteRedeemRequestStart(builder)
lobbyfbs.InviteRedeemRequestAddGameId(builder, gameOffset)
lobbyfbs.InviteRedeemRequestAddInviteId(builder, inviteOffset)
offset := lobbyfbs.InviteRedeemRequestEnd(builder)
lobbyfbs.FinishInviteRedeemRequestBuffer(builder, offset)
} else {
lobbyfbs.InviteDeclineRequestStart(builder)
lobbyfbs.InviteDeclineRequestAddGameId(builder, gameOffset)
lobbyfbs.InviteDeclineRequestAddInviteId(builder, inviteOffset)
offset := lobbyfbs.InviteDeclineRequestEnd(builder)
lobbyfbs.FinishInviteDeclineRequestBuffer(builder, offset)
}
return builder.FinishedBytes(), nil
}
func finishOffsetVector(builder *flatbuffers.Builder, offsets []flatbuffers.UOffsetT) flatbuffers.UOffsetT {
if len(offsets) == 0 {
return 0
}
builder.StartVector(4, len(offsets), 4)
for index := len(offsets) - 1; index >= 0; index-- {
builder.PrependUOffsetT(offsets[index])
}
return builder.EndVector(len(offsets))
}
func encodeGameSummary(builder *flatbuffers.Builder, summary lobbymodel.GameSummary) flatbuffers.UOffsetT {
gameID := builder.CreateString(summary.GameID)
gameName := builder.CreateString(summary.GameName)
@@ -248,6 +801,86 @@ func decodeGameSummary(summary *lobbyfbs.GameSummary) lobbymodel.GameSummary {
}
}
func encodeApplicationSummary(builder *flatbuffers.Builder, app lobbymodel.ApplicationSummary) flatbuffers.UOffsetT {
applicationID := builder.CreateString(app.ApplicationID)
gameID := builder.CreateString(app.GameID)
applicantUserID := builder.CreateString(app.ApplicantUserID)
raceName := builder.CreateString(app.RaceName)
status := builder.CreateString(app.Status)
lobbyfbs.ApplicationSummaryStart(builder)
lobbyfbs.ApplicationSummaryAddApplicationId(builder, applicationID)
lobbyfbs.ApplicationSummaryAddGameId(builder, gameID)
lobbyfbs.ApplicationSummaryAddApplicantUserId(builder, applicantUserID)
lobbyfbs.ApplicationSummaryAddRaceName(builder, raceName)
lobbyfbs.ApplicationSummaryAddStatus(builder, status)
lobbyfbs.ApplicationSummaryAddCreatedAtMs(builder, app.CreatedAt.UTC().UnixMilli())
lobbyfbs.ApplicationSummaryAddDecidedAtMs(builder, unixMilliFromOptional(app.DecidedAt))
return lobbyfbs.ApplicationSummaryEnd(builder)
}
func decodeApplicationSummary(app *lobbyfbs.ApplicationSummary) lobbymodel.ApplicationSummary {
return lobbymodel.ApplicationSummary{
ApplicationID: string(app.ApplicationId()),
GameID: string(app.GameId()),
ApplicantUserID: string(app.ApplicantUserId()),
RaceName: string(app.RaceName()),
Status: string(app.Status()),
CreatedAt: time.UnixMilli(app.CreatedAtMs()).UTC(),
DecidedAt: optionalUnixMilli(app.DecidedAtMs()),
}
}
func encodeInviteSummary(builder *flatbuffers.Builder, invite lobbymodel.InviteSummary) flatbuffers.UOffsetT {
inviteID := builder.CreateString(invite.InviteID)
gameID := builder.CreateString(invite.GameID)
inviterUserID := builder.CreateString(invite.InviterUserID)
invitedUserID := builder.CreateString(invite.InvitedUserID)
code := builder.CreateString(invite.Code)
raceName := builder.CreateString(invite.RaceName)
status := builder.CreateString(invite.Status)
lobbyfbs.InviteSummaryStart(builder)
lobbyfbs.InviteSummaryAddInviteId(builder, inviteID)
lobbyfbs.InviteSummaryAddGameId(builder, gameID)
lobbyfbs.InviteSummaryAddInviterUserId(builder, inviterUserID)
lobbyfbs.InviteSummaryAddInvitedUserId(builder, invitedUserID)
lobbyfbs.InviteSummaryAddCode(builder, code)
lobbyfbs.InviteSummaryAddRaceName(builder, raceName)
lobbyfbs.InviteSummaryAddStatus(builder, status)
lobbyfbs.InviteSummaryAddCreatedAtMs(builder, invite.CreatedAt.UTC().UnixMilli())
lobbyfbs.InviteSummaryAddExpiresAtMs(builder, invite.ExpiresAt.UTC().UnixMilli())
lobbyfbs.InviteSummaryAddDecidedAtMs(builder, unixMilliFromOptional(invite.DecidedAt))
return lobbyfbs.InviteSummaryEnd(builder)
}
func decodeInviteSummary(invite *lobbyfbs.InviteSummary) lobbymodel.InviteSummary {
return lobbymodel.InviteSummary{
InviteID: string(invite.InviteId()),
GameID: string(invite.GameId()),
InviterUserID: string(invite.InviterUserId()),
InvitedUserID: string(invite.InvitedUserId()),
Code: string(invite.Code()),
RaceName: string(invite.RaceName()),
Status: string(invite.Status()),
CreatedAt: time.UnixMilli(invite.CreatedAtMs()).UTC(),
ExpiresAt: time.UnixMilli(invite.ExpiresAtMs()).UTC(),
DecidedAt: optionalUnixMilli(invite.DecidedAtMs()),
}
}
// unixMilliFromOptional returns 0 when the pointer is nil, else the
// millisecond UTC timestamp. The transcoder uses 0 as the "not set"
// sentinel because FlatBuffers tables do not carry per-field presence
// flags, and 0 is unreachable for any realistic decided/redeemed time.
// optionalUnixMilli (defined in user.go) is the decode counterpart.
func unixMilliFromOptional(t *time.Time) int64 {
if t == nil {
return 0
}
return t.UTC().UnixMilli()
}
func recoverLobbyDecodePanic[T any](message string, result **T, err *error) {
if recovered := recover(); recovered != nil {
*result = nil
+517
View File
@@ -0,0 +1,517 @@
package transcoder
import (
"reflect"
"testing"
"time"
lobbymodel "galaxy/model/lobby"
)
// fixedTimes returns deterministic UTC timestamps for round-trip
// fixtures. Millisecond precision matches the FlatBuffers `*Ms` ints,
// which is what the transcoder preserves.
func fixedTimes() (created, updated, ends time.Time) {
created = time.Date(2026, time.May, 7, 9, 30, 15, 123_000_000, time.UTC)
updated = created.Add(2 * time.Minute)
ends = created.Add(48 * time.Hour)
return
}
func TestLobbyMyGamesListRoundTrip(t *testing.T) {
t.Parallel()
created, updated, ends := fixedTimes()
source := &lobbymodel.MyGamesListResponse{
Items: []lobbymodel.GameSummary{
{
GameID: "game-private-7c8f",
GameName: "First Contact",
GameType: "private",
Status: "draft",
OwnerUserID: "user-9912",
MinPlayers: 2,
MaxPlayers: 8,
EnrollmentEndsAt: ends,
CreatedAt: created,
UpdatedAt: updated,
},
{
GameID: "game-public-aabb",
GameName: "Open Lobby",
GameType: "public",
Status: "enrollment_open",
OwnerUserID: "",
MinPlayers: 4,
MaxPlayers: 12,
EnrollmentEndsAt: ends,
CreatedAt: created,
UpdatedAt: updated,
},
},
}
payload, err := MyGamesListResponseToPayload(source)
if err != nil {
t.Fatalf("encode: %v", err)
}
decoded, err := PayloadToMyGamesListResponse(payload)
if err != nil {
t.Fatalf("decode: %v", err)
}
if !reflect.DeepEqual(source, decoded) {
t.Fatalf("round-trip mismatch\nsource: %#v\ndecoded:%#v", source, decoded)
}
requestBytes, err := MyGamesListRequestToPayload(&lobbymodel.MyGamesListRequest{})
if err != nil {
t.Fatalf("encode request: %v", err)
}
if _, err := PayloadToMyGamesListRequest(requestBytes); err != nil {
t.Fatalf("decode request: %v", err)
}
}
func TestLobbyMyGamesListEmpty(t *testing.T) {
t.Parallel()
payload, err := MyGamesListResponseToPayload(&lobbymodel.MyGamesListResponse{Items: nil})
if err != nil {
t.Fatalf("encode: %v", err)
}
decoded, err := PayloadToMyGamesListResponse(payload)
if err != nil {
t.Fatalf("decode: %v", err)
}
if got := len(decoded.Items); got != 0 {
t.Fatalf("expected empty items, got %d", got)
}
}
func TestLobbyPublicGamesListRoundTrip(t *testing.T) {
t.Parallel()
created, updated, ends := fixedTimes()
requestSource := &lobbymodel.PublicGamesListRequest{Page: 3, PageSize: 25}
requestBytes, err := PublicGamesListRequestToPayload(requestSource)
if err != nil {
t.Fatalf("encode request: %v", err)
}
requestDecoded, err := PayloadToPublicGamesListRequest(requestBytes)
if err != nil {
t.Fatalf("decode request: %v", err)
}
if !reflect.DeepEqual(requestSource, requestDecoded) {
t.Fatalf("request round-trip mismatch\nsource: %#v\ndecoded:%#v", requestSource, requestDecoded)
}
responseSource := &lobbymodel.PublicGamesListResponse{
Items: []lobbymodel.GameSummary{
{
GameID: "game-public-aabb",
GameName: "Open Lobby",
GameType: "public",
Status: "enrollment_open",
OwnerUserID: "",
MinPlayers: 4,
MaxPlayers: 12,
EnrollmentEndsAt: ends,
CreatedAt: created,
UpdatedAt: updated,
},
},
Page: 3,
PageSize: 25,
Total: 51,
}
responseBytes, err := PublicGamesListResponseToPayload(responseSource)
if err != nil {
t.Fatalf("encode response: %v", err)
}
responseDecoded, err := PayloadToPublicGamesListResponse(responseBytes)
if err != nil {
t.Fatalf("decode response: %v", err)
}
if !reflect.DeepEqual(responseSource, responseDecoded) {
t.Fatalf("response round-trip mismatch\nsource: %#v\ndecoded:%#v", responseSource, responseDecoded)
}
}
func TestLobbyMyApplicationsListRoundTrip(t *testing.T) {
t.Parallel()
created, _, _ := fixedTimes()
decided := created.Add(2 * time.Hour)
requestBytes, err := MyApplicationsListRequestToPayload(&lobbymodel.MyApplicationsListRequest{})
if err != nil {
t.Fatalf("encode request: %v", err)
}
if _, err := PayloadToMyApplicationsListRequest(requestBytes); err != nil {
t.Fatalf("decode request: %v", err)
}
source := &lobbymodel.MyApplicationsListResponse{
Items: []lobbymodel.ApplicationSummary{
{
ApplicationID: "app-1",
GameID: "game-public-aabb",
ApplicantUserID: "user-9912",
RaceName: "Vegan Federation",
Status: "pending",
CreatedAt: created,
DecidedAt: nil,
},
{
ApplicationID: "app-2",
GameID: "game-public-ccdd",
ApplicantUserID: "user-9912",
RaceName: "Lithic Compact",
Status: "approved",
CreatedAt: created,
DecidedAt: &decided,
},
},
}
payload, err := MyApplicationsListResponseToPayload(source)
if err != nil {
t.Fatalf("encode: %v", err)
}
decoded, err := PayloadToMyApplicationsListResponse(payload)
if err != nil {
t.Fatalf("decode: %v", err)
}
if !reflect.DeepEqual(source, decoded) {
t.Fatalf("round-trip mismatch\nsource: %#v\ndecoded:%#v", source, decoded)
}
}
func TestLobbyMyInvitesListRoundTrip(t *testing.T) {
t.Parallel()
created, _, _ := fixedTimes()
expires := created.Add(72 * time.Hour)
decided := created.Add(1 * time.Hour)
requestBytes, err := MyInvitesListRequestToPayload(&lobbymodel.MyInvitesListRequest{})
if err != nil {
t.Fatalf("encode request: %v", err)
}
if _, err := PayloadToMyInvitesListRequest(requestBytes); err != nil {
t.Fatalf("decode request: %v", err)
}
source := &lobbymodel.MyInvitesListResponse{
Items: []lobbymodel.InviteSummary{
{
InviteID: "invite-user-bound",
GameID: "game-private-7c8f",
InviterUserID: "user-1111",
InvitedUserID: "user-9912",
Code: "",
RaceName: "Vegan Federation",
Status: "pending",
CreatedAt: created,
ExpiresAt: expires,
DecidedAt: nil,
},
{
InviteID: "invite-code-based",
GameID: "game-private-3322",
InviterUserID: "user-1111",
InvitedUserID: "",
Code: "ABCDEF12",
RaceName: "Lithic Compact",
Status: "accepted",
CreatedAt: created,
ExpiresAt: expires,
DecidedAt: &decided,
},
},
}
payload, err := MyInvitesListResponseToPayload(source)
if err != nil {
t.Fatalf("encode: %v", err)
}
decoded, err := PayloadToMyInvitesListResponse(payload)
if err != nil {
t.Fatalf("decode: %v", err)
}
if !reflect.DeepEqual(source, decoded) {
t.Fatalf("round-trip mismatch\nsource: %#v\ndecoded:%#v", source, decoded)
}
}
func TestLobbyOpenEnrollmentRoundTrip(t *testing.T) {
t.Parallel()
requestSource := &lobbymodel.OpenEnrollmentRequest{GameID: "game-private-7c8f"}
requestBytes, err := OpenEnrollmentRequestToPayload(requestSource)
if err != nil {
t.Fatalf("encode request: %v", err)
}
requestDecoded, err := PayloadToOpenEnrollmentRequest(requestBytes)
if err != nil {
t.Fatalf("decode request: %v", err)
}
if !reflect.DeepEqual(requestSource, requestDecoded) {
t.Fatalf("request round-trip mismatch\nsource: %#v\ndecoded:%#v", requestSource, requestDecoded)
}
responseSource := &lobbymodel.OpenEnrollmentResponse{GameID: "game-private-7c8f", Status: "enrollment_open"}
responseBytes, err := OpenEnrollmentResponseToPayload(responseSource)
if err != nil {
t.Fatalf("encode response: %v", err)
}
responseDecoded, err := PayloadToOpenEnrollmentResponse(responseBytes)
if err != nil {
t.Fatalf("decode response: %v", err)
}
if !reflect.DeepEqual(responseSource, responseDecoded) {
t.Fatalf("response round-trip mismatch\nsource: %#v\ndecoded:%#v", responseSource, responseDecoded)
}
}
func TestLobbyGameCreateRoundTrip(t *testing.T) {
t.Parallel()
_, _, ends := fixedTimes()
requestSource := &lobbymodel.GameCreateRequest{
GameName: "First Contact",
Description: "First Phase 8 sandbox game",
MinPlayers: 2,
MaxPlayers: 8,
StartGapHours: 24,
StartGapPlayers: 2,
EnrollmentEndsAt: ends,
TurnSchedule: "0 0 * * *",
TargetEngineVersion: "v1",
}
requestBytes, err := GameCreateRequestToPayload(requestSource)
if err != nil {
t.Fatalf("encode request: %v", err)
}
requestDecoded, err := PayloadToGameCreateRequest(requestBytes)
if err != nil {
t.Fatalf("decode request: %v", err)
}
if !reflect.DeepEqual(requestSource, requestDecoded) {
t.Fatalf("request round-trip mismatch\nsource: %#v\ndecoded:%#v", requestSource, requestDecoded)
}
created, updated, _ := fixedTimes()
responseSource := &lobbymodel.GameCreateResponse{
Game: lobbymodel.GameSummary{
GameID: "game-private-newly-created",
GameName: "First Contact",
GameType: "private",
Status: "draft",
OwnerUserID: "user-9912",
MinPlayers: 2,
MaxPlayers: 8,
EnrollmentEndsAt: ends,
CreatedAt: created,
UpdatedAt: updated,
},
}
responseBytes, err := GameCreateResponseToPayload(responseSource)
if err != nil {
t.Fatalf("encode response: %v", err)
}
responseDecoded, err := PayloadToGameCreateResponse(responseBytes)
if err != nil {
t.Fatalf("decode response: %v", err)
}
if !reflect.DeepEqual(responseSource, responseDecoded) {
t.Fatalf("response round-trip mismatch\nsource: %#v\ndecoded:%#v", responseSource, responseDecoded)
}
}
func TestLobbyApplicationSubmitRoundTrip(t *testing.T) {
t.Parallel()
requestSource := &lobbymodel.ApplicationSubmitRequest{GameID: "game-public-aabb", RaceName: "Vegan Federation"}
requestBytes, err := ApplicationSubmitRequestToPayload(requestSource)
if err != nil {
t.Fatalf("encode request: %v", err)
}
requestDecoded, err := PayloadToApplicationSubmitRequest(requestBytes)
if err != nil {
t.Fatalf("decode request: %v", err)
}
if !reflect.DeepEqual(requestSource, requestDecoded) {
t.Fatalf("request round-trip mismatch\nsource: %#v\ndecoded:%#v", requestSource, requestDecoded)
}
created, _, _ := fixedTimes()
responseSource := &lobbymodel.ApplicationSubmitResponse{
Application: lobbymodel.ApplicationSummary{
ApplicationID: "app-3",
GameID: "game-public-aabb",
ApplicantUserID: "user-9912",
RaceName: "Vegan Federation",
Status: "pending",
CreatedAt: created,
DecidedAt: nil,
},
}
responseBytes, err := ApplicationSubmitResponseToPayload(responseSource)
if err != nil {
t.Fatalf("encode response: %v", err)
}
responseDecoded, err := PayloadToApplicationSubmitResponse(responseBytes)
if err != nil {
t.Fatalf("decode response: %v", err)
}
if !reflect.DeepEqual(responseSource, responseDecoded) {
t.Fatalf("response round-trip mismatch\nsource: %#v\ndecoded:%#v", responseSource, responseDecoded)
}
}
func TestLobbyInviteRedeemAndDeclineRoundTrip(t *testing.T) {
t.Parallel()
created, _, _ := fixedTimes()
expires := created.Add(72 * time.Hour)
decided := created.Add(1 * time.Hour)
redeemReq := &lobbymodel.InviteRedeemRequest{GameID: "game-private-7c8f", InviteID: "invite-user-bound"}
redeemBytes, err := InviteRedeemRequestToPayload(redeemReq)
if err != nil {
t.Fatalf("encode redeem request: %v", err)
}
redeemDecoded, err := PayloadToInviteRedeemRequest(redeemBytes)
if err != nil {
t.Fatalf("decode redeem request: %v", err)
}
if !reflect.DeepEqual(redeemReq, redeemDecoded) {
t.Fatalf("redeem request mismatch")
}
redeemResp := &lobbymodel.InviteRedeemResponse{
Invite: lobbymodel.InviteSummary{
InviteID: "invite-user-bound",
GameID: "game-private-7c8f",
InviterUserID: "user-1111",
InvitedUserID: "user-9912",
Code: "",
RaceName: "Vegan Federation",
Status: "accepted",
CreatedAt: created,
ExpiresAt: expires,
DecidedAt: &decided,
},
}
redeemRespBytes, err := InviteRedeemResponseToPayload(redeemResp)
if err != nil {
t.Fatalf("encode redeem response: %v", err)
}
redeemRespDecoded, err := PayloadToInviteRedeemResponse(redeemRespBytes)
if err != nil {
t.Fatalf("decode redeem response: %v", err)
}
if !reflect.DeepEqual(redeemResp, redeemRespDecoded) {
t.Fatalf("redeem response mismatch")
}
declineReq := &lobbymodel.InviteDeclineRequest{GameID: "game-private-7c8f", InviteID: "invite-user-bound"}
declineBytes, err := InviteDeclineRequestToPayload(declineReq)
if err != nil {
t.Fatalf("encode decline request: %v", err)
}
declineDecoded, err := PayloadToInviteDeclineRequest(declineBytes)
if err != nil {
t.Fatalf("decode decline request: %v", err)
}
if !reflect.DeepEqual(declineReq, declineDecoded) {
t.Fatalf("decline request mismatch")
}
declineResp := &lobbymodel.InviteDeclineResponse{
Invite: lobbymodel.InviteSummary{
InviteID: "invite-user-bound",
GameID: "game-private-7c8f",
InviterUserID: "user-1111",
InvitedUserID: "user-9912",
Code: "",
RaceName: "Vegan Federation",
Status: "declined",
CreatedAt: created,
ExpiresAt: expires,
DecidedAt: &decided,
},
}
declineRespBytes, err := InviteDeclineResponseToPayload(declineResp)
if err != nil {
t.Fatalf("encode decline response: %v", err)
}
declineRespDecoded, err := PayloadToInviteDeclineResponse(declineRespBytes)
if err != nil {
t.Fatalf("decode decline response: %v", err)
}
if !reflect.DeepEqual(declineResp, declineRespDecoded) {
t.Fatalf("decline response mismatch")
}
}
func TestLobbyErrorResponseRoundTrip(t *testing.T) {
t.Parallel()
source := &lobbymodel.ErrorResponse{
Error: lobbymodel.ErrorBody{
Code: "conflict",
Message: "request conflicts with current state",
},
}
payload, err := LobbyErrorResponseToPayload(source)
if err != nil {
t.Fatalf("encode: %v", err)
}
decoded, err := PayloadToLobbyErrorResponse(payload)
if err != nil {
t.Fatalf("decode: %v", err)
}
if !reflect.DeepEqual(source, decoded) {
t.Fatalf("round-trip mismatch\nsource: %#v\ndecoded:%#v", source, decoded)
}
}
func TestLobbyDecodersRecoverFromCorruption(t *testing.T) {
t.Parallel()
garbage := []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}
if _, err := PayloadToMyGamesListResponse(garbage); err == nil {
t.Fatal("expected error decoding corrupt my games payload")
}
if _, err := PayloadToPublicGamesListResponse(garbage); err == nil {
t.Fatal("expected error decoding corrupt public games payload")
}
if _, err := PayloadToApplicationSubmitResponse(garbage); err == nil {
t.Fatal("expected error decoding corrupt application submit response")
}
if _, err := PayloadToInviteRedeemResponse(garbage); err == nil {
t.Fatal("expected error decoding corrupt invite redeem response")
}
if _, err := PayloadToLobbyErrorResponse(garbage); err == nil {
t.Fatal("expected error decoding corrupt error payload")
}
}
func TestLobbyDecodersRejectEmptyPayload(t *testing.T) {
t.Parallel()
if _, err := PayloadToMyGamesListRequest(nil); err == nil {
t.Fatal("expected error decoding nil request")
}
if _, err := PayloadToPublicGamesListResponse(nil); err == nil {
t.Fatal("expected error decoding nil response")
}
if _, err := PayloadToInviteDeclineRequest(nil); err == nil {
t.Fatal("expected error decoding nil decline request")
}
}
+9 -1
View File
@@ -1,15 +1,18 @@
.PHONY: help web wasm ts-protos gomobile desktop-mac desktop-win desktop-linux ios android all
.PHONY: help web wasm ts-protos fbs-ts gomobile desktop-mac desktop-win desktop-linux ios android all
.DEFAULT_GOAL := help
WASM_OUT := frontend/static/core.wasm
WASM_EXEC := frontend/static/wasm_exec.js
TINYGO_ROOT := $(shell tinygo env TINYGOROOT 2>/dev/null)
FBS_OUT := frontend/src/proto/galaxy/fbs
FBS_INPUTS := ../pkg/schema/fbs/lobby.fbs ../pkg/schema/fbs/user.fbs
help:
@echo "ui targets:"
@echo " wasm TinyGo build of ui/core to core.wasm + wasm_exec.js shim (Phase 5)"
@echo " ts-protos Connect-ES + Protobuf-ES generation from gateway/proto (Phase 5)"
@echo " fbs-ts FlatBuffers TS generation from pkg/schema/fbs/*.fbs (Phase 8)"
@echo " web Vite production build (Phase 5+)"
@echo " gomobile gomobile bind for iOS .framework + Android .aar (Phase 32+)"
@echo " desktop-mac Wails build for darwin/{arm64,amd64} (Phase 31)"
@@ -30,6 +33,11 @@ ts-protos:
@test -x frontend/node_modules/.bin/protoc-gen-es || { echo "protoc-gen-es not installed; run 'pnpm install' inside ui/frontend"; exit 1; }
buf generate ../gateway --template buf.gen.yaml --include-imports
fbs-ts:
@command -v flatc >/dev/null || { echo "flatc not found; install via 'brew install flatbuffers' (macOS) or 'apt-get install -y flatbuffers-compiler' (Linux)"; exit 1; }
mkdir -p $(FBS_OUT)
flatc --ts --gen-object-api -o $(FBS_OUT) $(FBS_INPUTS)
web gomobile desktop-mac desktop-win desktop-linux ios android all:
@echo "TODO: implement '$@' (placeholder, see ui/PLAN.md)"
@exit 1
+154 -25
View File
@@ -720,7 +720,12 @@ Artifacts (delivered):
- `ui/frontend/src/routes/lobby/+page.svelte` (+ `+page.ts`) —
placeholder lobby that issues the first authenticated
`user.account.get` through `GalaxyClient` and surfaces the decoded
display name.
display name. The placeholder used `JSON.parse(TextDecoder)` to
read the response payload; that worked with the mocked Playwright
setup but did not match the gateway's FlatBuffers wire format. Phase
8 introduces the TS-side FlatBuffers integration and rewrites this
page to decode `AccountResponse` via the generated bindings, so the
greeting now also works against a real local stack.
- `ui/frontend/src/routes/+layout.svelte` — boot-time session init,
route guard (anonymous → `/login`, authenticated on `/login` →
`/lobby`), browser-not-supported blocker, and the revocation
@@ -784,41 +789,165 @@ Targeted tests (delivered):
chromium-mobile-pixel-5: fresh login, returning user, revocation
within one second, browser-not-supported blocker.
## Phase 8. Lobby UI
## ~~Phase 8. Lobby UI~~
Status: pending.
Status: done.
Goal: replace the placeholder lobby with a working list of games
allowing the user to view membership, accept invitations, join public
games, and create new games.
allowing the user to view membership, see and act on invitations and
applications, submit applications to public games, and create new
private games. The phase also introduces the TS-side FlatBuffers
codec the rest of the client relies on for authenticated payloads.
Artifacts:
Decisions taken with the project owner before implementation:
- `ui/frontend/src/routes/lobby/+page.svelte` landing page sections:
my games (`docs/FUNCTIONAL.md` §4.5), public games (§4.2), pending
invitations (§4.3), action to create a new game (§3.3)
- `ui/frontend/src/api/lobby.ts` typed wrappers over the relevant
authenticated RPCs
- `ui/frontend/src/routes/lobby/create/+page.svelte` create-game form
matching backend contract
- routing wiring: clicking a game card navigates to
`/games/:gameId/map` (placeholder until Phase 10)
1. **Cross-stack catalog extension.** Phase 8 expands the lobby
command catalog beyond `lobby.my.games.list` and
`lobby.game.open-enrollment` (the only routes shipped before this
phase). Seven new authenticated message types now flow through
`gateway/internal/backendclient/lobby_commands.go`:
`lobby.public.games.list`, `lobby.my.applications.list`,
`lobby.my.invites.list`, `lobby.game.create`,
`lobby.application.submit`, `lobby.invite.redeem`,
`lobby.invite.decline`. Each carries its FlatBuffers schema in
`pkg/schema/fbs/lobby.fbs`, its Go request/response struct in
`pkg/model/lobby/lobby.go`, and its transcoder pair in
`pkg/transcoder/lobby.go`.
2. **My applications projection.** FUNCTIONAL.md §4.5 lists three
"my" projections (games, applications, invites). The original
plan text omitted applications; the lobby now renders a fourth
"my applications" section so the user sees the pending status of
any application they submit.
3. **Submit-application UX.** Per FUNCTIONAL.md §4.2, joining a
public game means submitting an application that lands in the
`pending` state until the owner approves. The button label is
`Submit application`, the inline race-name form lives on the
public-game card itself (no overlay/modal infrastructure yet —
that lands later when the in-game shell does), and a successful
submit refreshes the applications section so the user sees the
pending entry immediately.
4. **TS-side FlatBuffers integration.** The placeholder lobby in
Phase 7 used `JSON.parse(TextDecoder)` to read the
`user.account.get` payload; that was a mismatch with the gateway's
FlatBuffers transcoder and only worked under mocked tests. Phase 8
adds a `flatbuffers` runtime dep to `ui/frontend/package.json`, a
`fbs-ts` Make target in `ui/Makefile` that drives `flatc --ts`,
and checks the generated bindings into
`ui/frontend/src/proto/galaxy/fbs/{lobby,user}/`. Phase 7's
`user.account.get` decode is rewritten to use those bindings as
part of this phase, fixing the wire-format gap.
5. **Create-game form scope.** The form keeps `game_name`,
`description`, `turn_schedule` (5-field cron), and
`enrollment_ends_at` always visible; the rest (`min_players`,
`max_players`, `start_gap_hours`, `start_gap_players`,
`target_engine_version`) sit behind a `<details>` "Advanced"
toggle with TS-side defaults (2 / 8 / 24 / 2 / `v1`). The gateway
forces visibility to `private` regardless of input — public games
come exclusively through the admin surface per FUNCTIONAL.md §3.3.
Artifacts (delivered):
- `ui/frontend/src/routes/lobby/+page.svelte` — full lobby landing
page. Header preserves the Phase 7 device-session-id and greeting
affordances; below it five sections render in a single mobile-first
column: a top-level "create new game" action (§3.3), `my games`
cards routing to `/games/:id/map` (placeholder until Phase 10,
§4.5), `pending invitations` cards with Accept / Decline (§4.3),
`my applications` cards with localised pending / approved /
rejected status (§4.5), and `public games` cards with an inline
race-name form behind a `Submit application` button (§4.2).
Convention follows the Phase 7 login page — single `max-width:
32rem` cap, no `@media` queries.
- `ui/frontend/src/routes/lobby/create/+page.svelte` (+ `+page.ts`
with `ssr = false; prerender = false;`) — create-game form with
always-visible name / description / turn-schedule / enrollment-end,
Advanced fields under `<details>` for the rest, and TS-side
defaults for the advanced inputs.
- `ui/frontend/src/api/lobby.ts` — typed wrappers around
`GalaxyClient.executeCommand` for all eight lobby commands plus a
`LobbyError` class that surfaces canonical lobby error codes
(`invalid_request`, `subject_not_found`, `forbidden`, `conflict`,
`internal_error`).
- `ui/frontend/src/api/galaxy-client.ts` — `executeCommand` now
returns `{ resultCode, payloadBytes }`; `lobby.ts` uses the
result-code branch to throw `LobbyError`.
- `pkg/model/lobby/lobby.go` — seven new message-type constants and
matching request/response structs.
- `pkg/schema/fbs/lobby.fbs` — `PublicGamesListRequest`,
`PublicGamesListResponse`, `ApplicationSummary`,
`MyApplicationsListRequest`, `MyApplicationsListResponse`,
`InviteSummary`, `MyInvitesListRequest`, `MyInvitesListResponse`,
`GameCreateRequest`, `GameCreateResponse`,
`ApplicationSubmitRequest`, `ApplicationSubmitResponse`,
`InviteRedeemRequest`, `InviteRedeemResponse`,
`InviteDeclineRequest`, `InviteDeclineResponse` tables. Reused
`GameSummary` for `GameCreateResponse.game` and `MyGamesListResponse`.
- `pkg/transcoder/lobby.go` — encode/decode pairs for all new types
plus shared helpers `encodeApplicationSummary`,
`decodeApplicationSummary`, `encodeInviteSummary`,
`decodeInviteSummary`, `unixMilliFromOptional`. Reuses
`encodeGameSummary` / `decodeGameSummary` from before.
- `gateway/internal/backendclient/lobby_commands.go` — switch cases
for the seven new message types and the per-command REST helpers
(`executeLobbyPublicGames`, `executeLobbyMyApplications`,
`executeLobbyMyInvites`, `executeLobbyGameCreate`,
`executeLobbyApplicationSubmit`, `executeLobbyInviteRedeem`,
`executeLobbyInviteDecline`); the JSON wire types from backend's
user-lobby handlers are mirrored locally for non-strict decoding.
- `gateway/internal/backendclient/routes.go` — the new message types
are wired into `LobbyRoutes`.
- `ui/frontend/src/proto/galaxy/fbs/{lobby,user}/...` — generated TS
FlatBuffers bindings (regenerated from `pkg/schema/fbs/*.fbs` via
the `fbs-ts` Make target, checked into the repo like the Connect
bindings).
- `ui/Makefile` — new `fbs-ts` target.
- `ui/frontend/package.json` — `flatbuffers` runtime dep.
- `ui/frontend/src/lib/i18n/locales/{en,ru}.ts` — full `lobby.*`
catalogue covering sections, empty states, application form,
create form, status badges, and lobby error code translations.
- Topic doc `ui/docs/lobby.md`.
- Vitest: `tests/lobby-fbs.test.ts` (binding round-trips),
`tests/lobby-api.test.ts` (wrapper unit tests over a stub client),
`tests/lobby-page.test.ts`, `tests/lobby-create.test.ts`.
- Playwright: `tests/e2e/lobby-flow.spec.ts` (3 cases × 4 projects)
with `tests/e2e/fixtures/lobby-fbs.ts` building forged FlatBuffers
payloads through the same generated bindings the production code
uses. The Phase 7 spec was migrated to the same fixture so
`user.account.get` is now FlatBuffers end-to-end.
- Phase 7 e2e specs were updated to `click → fill` the readonly
inputs (the readonly attribute is the documented Safari
autofill-suppression workaround; `fill` checks editability before
Playwright's own focus call, so a deliberate click is required).
- `pkg/transcoder/lobby_test.go` — round-trip and corruption-recover
cases for every new pair.
- `gateway/internal/backendclient/lobby_commands_test.go` — per-RPC
success / 4xx / 5xx / 503 cases against an `httptest.Server`.
Dependencies: Phase 7.
Acceptance criteria:
Acceptance criteria (met):
- the user can list, create, join a game, and accept an invitation
end-to-end against a local stack;
- mobile viewport renders without horizontal scroll;
- empty states are explicit (`no games yet`, `no public games`).
- the user can list, create, submit-application, and accept an
invitation end-to-end against a local stack — the gateway routes
every required envelope, and the FlatBuffers wire path is the same
in production and in mocked tests;
- mobile viewport renders without horizontal scroll on
`chromium-mobile-iphone-13` and `chromium-mobile-pixel-5`;
- empty states are explicit (`no games yet`, `no invitations`,
`no applications`, `no public games`).
Targeted tests:
Targeted tests (delivered):
- Vitest component tests for each section with mocked API responses;
- Playwright e2e: complete a create-game flow and confirm the new game
appears in `my games`;
- mobile-viewport Playwright run for the same flow.
- Vitest binding round-trips for every lobby request/response;
- Vitest API wrapper coverage for every wrapper plus the LobbyError
surfacing path;
- Vitest component tests for the lobby page (every section, empty
states, race-name validation, Accept / Decline) and the create-game
form (validation, submission, cancel);
- Playwright e2e (3 flows × 4 projects): full create-game flow to
My Games, submit-application to My Applications pending, accept
invitation removes card and adds the game to My Games. Phase 7
auth flow now also runs over the FlatBuffers wire.
## Phase 9. Map Renderer with Fixture Data
+6 -2
View File
@@ -75,8 +75,8 @@ ui/
├── src/lib/ env config, session store, revocation watcher
├── src/platform/core/ Core interface + WasmCore adapter
├── src/platform/store/ KeyStore/Cache interfaces + web adapter
├── src/proto/ generated Protobuf-ES + Connect descriptors
├── src/routes/ SvelteKit routes (/, /login, /lobby)
├── src/proto/ generated Protobuf-ES + Connect descriptors + FlatBuffers TS bindings
├── src/routes/ SvelteKit routes (/, /login, /lobby, /lobby/create)
└── static/ core.wasm + wasm_exec.js (committed artefacts)
```
@@ -84,6 +84,8 @@ Linked topic docs:
- [`docs/auth-flow.md`](docs/auth-flow.md) — email-code login,
session store state machine, revocation watcher.
- [`docs/lobby.md`](docs/lobby.md) — lobby UI sections, application
/ invite lifecycle, create-game form defaults.
- [`docs/i18n.md`](docs/i18n.md) — translation primitive, native-name
language picker, recipe for adding a new locale.
- [`docs/storage.md`](docs/storage.md) — web KeyStore/Cache,
@@ -119,6 +121,8 @@ named targets are placeholders until the named phase lands; running
```text
make web Vite production build Phase 5+
make wasm TinyGo → core.wasm Phase 5
make ts-protos Connect-ES + Protobuf-ES gen Phase 5
make fbs-ts FlatBuffers TS bindings via flatc Phase 8
make gomobile gomobile bind → ios + android Phase 32+
make desktop-mac Wails build for darwin Phase 31
make desktop-win Wails build for windows Phase 31
+113
View File
@@ -0,0 +1,113 @@
# Lobby UI
The lobby is the first authenticated view; the user lands here after
the email-code login completes (see
[`docs/auth-flow.md`](auth-flow.md)). Phase 8 introduced the live
lobby with five sections, the create-game form, and the TS-side
FlatBuffers integration the rest of the client builds on. This doc
captures the sections, the application / invite lifecycle the user
sees, and the defaults baked into the create-game form.
## Sections
The lobby renders one column of sections, top to bottom, with the
common content max-width capped at `32rem` (same convention as the
login page). Cards inside each section take the full available
width.
| Section | Empty state | Source | Action |
| -------------------- | --------------------- | -------------------------- | --------------------------------------------------------- |
| `create new game` | (always visible) | — | Navigates to `/lobby/create` |
| `my games` | `no games yet` | `lobby.my.games.list` | Click → `/games/:id/map` (placeholder until Phase 10) |
| `pending invitations`| `no invitations` | `lobby.my.invites.list` | Accept (`lobby.invite.redeem`) / Decline (`lobby.invite.decline`) |
| `my applications` | `no applications` | `lobby.my.applications.list` | Status badge (`pending` / `approved` / `rejected`) |
| `public games` | `no public games` | `lobby.public.games.list` | Submit application via inline race-name form (`lobby.application.submit`) |
The header preserves the device-session-id `<code>` block from the
Phase 7 placeholder (kept as a debug affordance) plus a greeting if
the gateway returns a `display_name` for the caller.
## Application lifecycle
`Submit application` on a public-game card toggles an inline race-name
form on the same card (no overlay/modal infrastructure yet — the
in-game shell that introduces overlays lands later). On submit:
1. The page calls `submitApplication(client, gameId, raceName)` from
`src/api/lobby.ts`.
2. The wrapper builds an `ApplicationSubmitRequest` FlatBuffers
payload, posts it through `GalaxyClient.executeCommand`, decodes
the `ApplicationSubmitResponse`, and returns an
`ApplicationSummary` plain object.
3. The lobby page prepends the new application to the
`my applications` list and collapses the inline form. The page
does not refresh the public-games list — backend semantics are
that the public game still exists and is still in
`enrollment_open`.
4. Status starts as `pending`. When the owner approves, backend
creates a membership and the next refresh of `lobby.my.games.list`
surfaces the game in `my games`. When the owner rejects, the
application stays terminal in `my applications` with status
`rejected`.
## Invite lifecycle
A pending invite arrives in `pending invitations` either when the
inviter targets the user by id (`invited_user_id` is set) or when the
user redeems a code-based invite from somewhere outside the lobby.
The user can accept (`lobby.invite.redeem`) or decline
(`lobby.invite.decline`):
- **Accept** — the invite card disappears, the page refreshes
`my games`, and the freshly-joined game appears there.
- **Decline** — the invite card disappears. No membership is
created.
## Create-game form
The form posts `lobby.game.create` through the gateway with
`visibility="private"` hard-coded; the user surface never produces a
public game (FUNCTIONAL.md §3.3). Fields:
| Field | Visibility | Default | Notes |
| --------------------- | ---------------- | ------- | ------------------------------------------------------ |
| `game_name` | always | `""` | Non-empty client-side check |
| `description` | always | `""` | |
| `turn_schedule` | always | `0 0 * * *` | Plain text input, hint says "five-field cron" |
| `enrollment_ends_at` | always | `""` | `<input type="datetime-local">`, RFC 3339 on submit |
| `min_players` | Advanced toggle | `2` | `<details>` block |
| `max_players` | Advanced toggle | `8` | |
| `start_gap_hours` | Advanced toggle | `24` | |
| `start_gap_players` | Advanced toggle | `2` | |
| `target_engine_version` | Advanced toggle | `v1` | Falls back to `v1` if blank |
On success the page navigates back to `/lobby` and the new game shows
up in `my games` once the lobby's onMount has had a chance to refresh
the list.
## Errors
Lobby errors raised by the gateway carry a canonical code
(`invalid_request`, `subject_not_found`, `forbidden`, `conflict`,
`internal_error`). The `LobbyError` thrown by `lobby.ts` exposes the
code; the page maps it to the matching `lobby.error.<code>` i18n key
and falls back to the gateway-supplied message via
`lobby.error.unknown` for any unknown code.
## Why FlatBuffers on the TS side
The gateway encodes lobby payloads through `pkg/transcoder/lobby.go`
into FlatBuffers bytes; the browser must decode them with the same
schema. Phase 8 ships:
- `flatbuffers` runtime dependency in `ui/frontend/package.json`;
- `make -C ui fbs-ts` driving `flatc --ts` to regenerate the bindings
from `pkg/schema/fbs/*.fbs` into `ui/frontend/src/proto/galaxy/fbs/`;
- a Vitest round-trip suite (`tests/lobby-fbs.test.ts`) that catches
binding drift in CI.
Phase 7's `user.account.get` decode previously used
`JSON.parse(TextDecoder)`; that path was rewritten in Phase 8 to use
the same generated `AccountResponse` table, so the lobby greeting now
works against a real local stack as well as the mocked Playwright
fixtures.
+1
View File
@@ -12,6 +12,7 @@
"test:e2e": "playwright test"
},
"dependencies": {
"flatbuffers": "^25.9.23",
"idb": "^8.0.3"
},
"devDependencies": {
+10 -2
View File
@@ -46,6 +46,11 @@ export interface GalaxyClientOptions {
const PROTOCOL_VERSION = "v1";
export interface ExecuteCommandResult {
resultCode: string;
payloadBytes: Uint8Array;
}
export class GalaxyClient {
private readonly core: Core;
private readonly edge: EdgeGatewayClient;
@@ -72,7 +77,7 @@ export class GalaxyClient {
messageType: string,
payload: Uint8Array,
traceId = "",
): Promise<Uint8Array> {
): Promise<ExecuteCommandResult> {
const requestId = this.requestIdFactory();
const timestampMs = this.clock();
const payloadHash = await this.sha256(payload);
@@ -103,7 +108,10 @@ export class GalaxyClient {
);
this.verifyResponse(response, requestId);
return response.payloadBytes;
return {
resultCode: response.resultCode,
payloadBytes: response.payloadBytes,
};
}
private verifyResponse(
+361
View File
@@ -0,0 +1,361 @@
// Typed wrappers around `GalaxyClient.executeCommand` for the Phase 8
// lobby command catalog. Each wrapper builds a FlatBuffers request
// payload via the generated TS bindings, calls `executeCommand`, then
// decodes the FlatBuffers response payload. Errors carrying a non-`ok`
// `result_code` are surfaced as a thrown `LobbyError` so callers can
// branch on canonical lobby error codes (`invalid_request`,
// `subject_not_found`, `forbidden`, `conflict`, `internal_error`).
import { Builder, ByteBuffer } from "flatbuffers";
import type { GalaxyClient } from "./galaxy-client";
import {
ApplicationSubmitRequest,
ApplicationSubmitResponse,
ApplicationSummary as FbsApplicationSummary,
ErrorResponse as FbsErrorResponse,
GameCreateRequest,
GameCreateResponse,
GameSummary as FbsGameSummary,
InviteDeclineRequest,
InviteDeclineResponse,
InviteRedeemRequest,
InviteRedeemResponse,
InviteSummary as FbsInviteSummary,
MyApplicationsListRequest,
MyApplicationsListResponse,
MyGamesListRequest,
MyGamesListResponse,
MyInvitesListRequest,
MyInvitesListResponse,
PublicGamesListRequest,
PublicGamesListResponse,
} from "../proto/galaxy/fbs/lobby";
export class LobbyError extends Error {
readonly code: string;
readonly resultCode: string;
constructor(resultCode: string, code: string, message: string) {
super(message);
this.name = "LobbyError";
this.resultCode = resultCode;
this.code = code;
}
}
export interface GameSummary {
gameId: string;
gameName: string;
gameType: string;
status: string;
ownerUserId: string;
minPlayers: number;
maxPlayers: number;
enrollmentEndsAt: Date;
createdAt: Date;
updatedAt: Date;
}
export interface PublicGamesPage {
items: GameSummary[];
page: number;
pageSize: number;
total: number;
}
export interface ApplicationSummary {
applicationId: string;
gameId: string;
applicantUserId: string;
raceName: string;
status: string;
createdAt: Date;
decidedAt: Date | null;
}
export interface InviteSummary {
inviteId: string;
gameId: string;
inviterUserId: string;
invitedUserId: string;
code: string;
raceName: string;
status: string;
createdAt: Date;
expiresAt: Date;
decidedAt: Date | null;
}
export interface CreateGameInput {
gameName: string;
description: string;
minPlayers: number;
maxPlayers: number;
startGapHours: number;
startGapPlayers: number;
enrollmentEndsAt: Date;
turnSchedule: string;
targetEngineVersion: string;
}
const RESULT_CODE_OK = "ok";
export async function listMyGames(client: GalaxyClient): Promise<GameSummary[]> {
const builder = new Builder(32);
MyGamesListRequest.startMyGamesListRequest(builder);
builder.finish(MyGamesListRequest.endMyGamesListRequest(builder));
const payload = await execute(client, "lobby.my.games.list", builder.asUint8Array());
const response = MyGamesListResponse.getRootAsMyGamesListResponse(new ByteBuffer(payload));
const out: GameSummary[] = [];
for (let i = 0; i < response.itemsLength(); i++) {
const item = response.items(i);
if (item) {
out.push(decodeGameSummary(item));
}
}
return out;
}
export async function listPublicGames(
client: GalaxyClient,
options: { page?: number; pageSize?: number } = {},
): Promise<PublicGamesPage> {
const page = options.page ?? 1;
const pageSize = options.pageSize ?? 50;
const builder = new Builder(32);
PublicGamesListRequest.startPublicGamesListRequest(builder);
PublicGamesListRequest.addPage(builder, page);
PublicGamesListRequest.addPageSize(builder, pageSize);
builder.finish(PublicGamesListRequest.endPublicGamesListRequest(builder));
const payload = await execute(client, "lobby.public.games.list", builder.asUint8Array());
const response = PublicGamesListResponse.getRootAsPublicGamesListResponse(
new ByteBuffer(payload),
);
const out: GameSummary[] = [];
for (let i = 0; i < response.itemsLength(); i++) {
const item = response.items(i);
if (item) {
out.push(decodeGameSummary(item));
}
}
return {
items: out,
page: response.page(),
pageSize: response.pageSize(),
total: response.total(),
};
}
export async function listMyApplications(
client: GalaxyClient,
): Promise<ApplicationSummary[]> {
const builder = new Builder(32);
MyApplicationsListRequest.startMyApplicationsListRequest(builder);
builder.finish(MyApplicationsListRequest.endMyApplicationsListRequest(builder));
const payload = await execute(client, "lobby.my.applications.list", builder.asUint8Array());
const response = MyApplicationsListResponse.getRootAsMyApplicationsListResponse(
new ByteBuffer(payload),
);
const out: ApplicationSummary[] = [];
for (let i = 0; i < response.itemsLength(); i++) {
const item = response.items(i);
if (item) {
out.push(decodeApplicationSummary(item));
}
}
return out;
}
export async function listMyInvites(client: GalaxyClient): Promise<InviteSummary[]> {
const builder = new Builder(32);
MyInvitesListRequest.startMyInvitesListRequest(builder);
builder.finish(MyInvitesListRequest.endMyInvitesListRequest(builder));
const payload = await execute(client, "lobby.my.invites.list", builder.asUint8Array());
const response = MyInvitesListResponse.getRootAsMyInvitesListResponse(new ByteBuffer(payload));
const out: InviteSummary[] = [];
for (let i = 0; i < response.itemsLength(); i++) {
const item = response.items(i);
if (item) {
out.push(decodeInviteSummary(item));
}
}
return out;
}
export async function createGame(
client: GalaxyClient,
input: CreateGameInput,
): Promise<GameSummary> {
const builder = new Builder(256);
const gameNameOff = builder.createString(input.gameName);
const descriptionOff = builder.createString(input.description);
const turnScheduleOff = builder.createString(input.turnSchedule);
const targetEngineVersionOff = builder.createString(input.targetEngineVersion);
GameCreateRequest.startGameCreateRequest(builder);
GameCreateRequest.addGameName(builder, gameNameOff);
GameCreateRequest.addDescription(builder, descriptionOff);
GameCreateRequest.addMinPlayers(builder, input.minPlayers);
GameCreateRequest.addMaxPlayers(builder, input.maxPlayers);
GameCreateRequest.addStartGapHours(builder, input.startGapHours);
GameCreateRequest.addStartGapPlayers(builder, input.startGapPlayers);
GameCreateRequest.addEnrollmentEndsAtMs(builder, BigInt(input.enrollmentEndsAt.getTime()));
GameCreateRequest.addTurnSchedule(builder, turnScheduleOff);
GameCreateRequest.addTargetEngineVersion(builder, targetEngineVersionOff);
builder.finish(GameCreateRequest.endGameCreateRequest(builder));
const payload = await execute(client, "lobby.game.create", builder.asUint8Array());
const response = GameCreateResponse.getRootAsGameCreateResponse(new ByteBuffer(payload));
const game = response.game();
if (game === null) {
throw new LobbyError("internal_error", "internal_error", "game missing in response");
}
return decodeGameSummary(game);
}
export async function submitApplication(
client: GalaxyClient,
gameId: string,
raceName: string,
): Promise<ApplicationSummary> {
const builder = new Builder(128);
const gameIdOff = builder.createString(gameId);
const raceNameOff = builder.createString(raceName);
ApplicationSubmitRequest.startApplicationSubmitRequest(builder);
ApplicationSubmitRequest.addGameId(builder, gameIdOff);
ApplicationSubmitRequest.addRaceName(builder, raceNameOff);
builder.finish(ApplicationSubmitRequest.endApplicationSubmitRequest(builder));
const payload = await execute(client, "lobby.application.submit", builder.asUint8Array());
const response = ApplicationSubmitResponse.getRootAsApplicationSubmitResponse(
new ByteBuffer(payload),
);
const application = response.application();
if (application === null) {
throw new LobbyError("internal_error", "internal_error", "application missing in response");
}
return decodeApplicationSummary(application);
}
export async function redeemInvite(
client: GalaxyClient,
gameId: string,
inviteId: string,
): Promise<InviteSummary> {
const builder = new Builder(128);
const gameIdOff = builder.createString(gameId);
const inviteIdOff = builder.createString(inviteId);
InviteRedeemRequest.startInviteRedeemRequest(builder);
InviteRedeemRequest.addGameId(builder, gameIdOff);
InviteRedeemRequest.addInviteId(builder, inviteIdOff);
builder.finish(InviteRedeemRequest.endInviteRedeemRequest(builder));
const payload = await execute(client, "lobby.invite.redeem", builder.asUint8Array());
const response = InviteRedeemResponse.getRootAsInviteRedeemResponse(new ByteBuffer(payload));
const invite = response.invite();
if (invite === null) {
throw new LobbyError("internal_error", "internal_error", "invite missing in response");
}
return decodeInviteSummary(invite);
}
export async function declineInvite(
client: GalaxyClient,
gameId: string,
inviteId: string,
): Promise<InviteSummary> {
const builder = new Builder(128);
const gameIdOff = builder.createString(gameId);
const inviteIdOff = builder.createString(inviteId);
InviteDeclineRequest.startInviteDeclineRequest(builder);
InviteDeclineRequest.addGameId(builder, gameIdOff);
InviteDeclineRequest.addInviteId(builder, inviteIdOff);
builder.finish(InviteDeclineRequest.endInviteDeclineRequest(builder));
const payload = await execute(client, "lobby.invite.decline", builder.asUint8Array());
const response = InviteDeclineResponse.getRootAsInviteDeclineResponse(
new ByteBuffer(payload),
);
const invite = response.invite();
if (invite === null) {
throw new LobbyError("internal_error", "internal_error", "invite missing in response");
}
return decodeInviteSummary(invite);
}
async function execute(
client: GalaxyClient,
messageType: string,
payloadBytes: Uint8Array,
): Promise<Uint8Array> {
const result = await client.executeCommand(messageType, payloadBytes);
if (result.resultCode !== RESULT_CODE_OK) {
throw decodeLobbyError(result.resultCode, result.payloadBytes);
}
return result.payloadBytes;
}
function decodeLobbyError(resultCode: string, payload: Uint8Array): LobbyError {
let code = resultCode;
let message = resultCode;
try {
const errorResponse = FbsErrorResponse.getRootAsErrorResponse(new ByteBuffer(payload));
const body = errorResponse.error();
if (body) {
code = body.code() ?? resultCode;
message = body.message() ?? resultCode;
}
} catch (_err) {
// fall through to use raw resultCode as both code and message
}
return new LobbyError(resultCode, code, message);
}
function decodeGameSummary(summary: FbsGameSummary): GameSummary {
return {
gameId: summary.gameId() ?? "",
gameName: summary.gameName() ?? "",
gameType: summary.gameType() ?? "",
status: summary.status() ?? "",
ownerUserId: summary.ownerUserId() ?? "",
minPlayers: summary.minPlayers(),
maxPlayers: summary.maxPlayers(),
enrollmentEndsAt: dateFromMs(summary.enrollmentEndsAtMs()),
createdAt: dateFromMs(summary.createdAtMs()),
updatedAt: dateFromMs(summary.updatedAtMs()),
};
}
function decodeApplicationSummary(app: FbsApplicationSummary): ApplicationSummary {
return {
applicationId: app.applicationId() ?? "",
gameId: app.gameId() ?? "",
applicantUserId: app.applicantUserId() ?? "",
raceName: app.raceName() ?? "",
status: app.status() ?? "",
createdAt: dateFromMs(app.createdAtMs()),
decidedAt: optionalDateFromMs(app.decidedAtMs()),
};
}
function decodeInviteSummary(invite: FbsInviteSummary): InviteSummary {
return {
inviteId: invite.inviteId() ?? "",
gameId: invite.gameId() ?? "",
inviterUserId: invite.inviterUserId() ?? "",
invitedUserId: invite.invitedUserId() ?? "",
code: invite.code() ?? "",
raceName: invite.raceName() ?? "",
status: invite.status() ?? "",
createdAt: dateFromMs(invite.createdAtMs()),
expiresAt: dateFromMs(invite.expiresAtMs()),
decidedAt: optionalDateFromMs(invite.decidedAtMs()),
};
}
function dateFromMs(ms: bigint): Date {
return new Date(Number(ms));
}
function optionalDateFromMs(ms: bigint): Date | null {
if (ms === 0n) {
return null;
}
return new Date(Number(ms));
}
+47
View File
@@ -35,6 +35,53 @@ const en = {
"lobby.greeting": "hello, {name}!",
"lobby.account_loading": "loading account…",
"lobby.logout": "logout",
"lobby.section.my_games": "my games",
"lobby.section.invitations": "pending invitations",
"lobby.section.applications": "my applications",
"lobby.section.public_games": "public games",
"lobby.section.create": "create a game",
"lobby.create_button": "create new game",
"lobby.my_games.empty": "no games yet",
"lobby.invitations.empty": "no invitations",
"lobby.applications.empty": "no applications",
"lobby.public_games.empty": "no public games",
"lobby.invitation.accept": "accept",
"lobby.invitation.decline": "decline",
"lobby.application.submit": "submit application",
"lobby.application.submit_for": "join {name}",
"lobby.application.race_name_label": "race name",
"lobby.application.race_name_required": "race name must not be empty",
"lobby.application.cancel": "cancel",
"lobby.application.submitted": "application submitted, awaiting approval",
"lobby.application.status.pending": "pending",
"lobby.application.status.approved": "approved",
"lobby.application.status.rejected": "rejected",
"lobby.application.status.unknown": "{status}",
"lobby.list_loading": "loading…",
"lobby.create.title": "create new game",
"lobby.create.game_name_label": "game name",
"lobby.create.description_label": "description",
"lobby.create.turn_schedule_label": "turn schedule",
"lobby.create.turn_schedule_hint": "five-field cron, e.g. 0 0 * * *",
"lobby.create.enrollment_ends_at_label": "enrollment ends at",
"lobby.create.advanced": "advanced",
"lobby.create.min_players_label": "min players",
"lobby.create.max_players_label": "max players",
"lobby.create.start_gap_hours_label": "start gap (hours)",
"lobby.create.start_gap_players_label": "start gap (players)",
"lobby.create.target_engine_version_label": "target engine version",
"lobby.create.submit": "create",
"lobby.create.submitting": "creating…",
"lobby.create.cancel": "cancel",
"lobby.create.game_name_required": "game name must not be empty",
"lobby.create.turn_schedule_required": "turn schedule must not be empty",
"lobby.create.enrollment_ends_at_required": "enrollment end time must be set",
"lobby.error.invalid_request": "request is invalid",
"lobby.error.subject_not_found": "not found",
"lobby.error.forbidden": "operation is forbidden",
"lobby.error.conflict": "request conflicts with current state",
"lobby.error.internal_error": "internal server error",
"lobby.error.unknown": "{message}",
} as const;
export default en;
+47
View File
@@ -36,6 +36,53 @@ const ru: Record<keyof typeof en, string> = {
"lobby.greeting": "здравствуйте, {name}!",
"lobby.account_loading": "загрузка профиля…",
"lobby.logout": "выйти",
"lobby.section.my_games": "мои игры",
"lobby.section.invitations": "ожидающие приглашения",
"lobby.section.applications": "мои заявки",
"lobby.section.public_games": "публичные игры",
"lobby.section.create": "создать игру",
"lobby.create_button": "создать новую игру",
"lobby.my_games.empty": "пока нет игр",
"lobby.invitations.empty": "приглашений нет",
"lobby.applications.empty": "заявок нет",
"lobby.public_games.empty": "публичных игр нет",
"lobby.invitation.accept": "принять",
"lobby.invitation.decline": "отклонить",
"lobby.application.submit": "подать заявку",
"lobby.application.submit_for": "подать заявку в {name}",
"lobby.application.race_name_label": "название расы",
"lobby.application.race_name_required": "название расы не должно быть пустым",
"lobby.application.cancel": "отмена",
"lobby.application.submitted": "заявка отправлена, ожидает одобрения",
"lobby.application.status.pending": "ожидает",
"lobby.application.status.approved": "одобрена",
"lobby.application.status.rejected": "отклонена",
"lobby.application.status.unknown": "{status}",
"lobby.list_loading": "загрузка…",
"lobby.create.title": "создание новой игры",
"lobby.create.game_name_label": "название игры",
"lobby.create.description_label": "описание",
"lobby.create.turn_schedule_label": "расписание ходов",
"lobby.create.turn_schedule_hint": "cron из пяти полей, например 0 0 * * *",
"lobby.create.enrollment_ends_at_label": "окончание набора",
"lobby.create.advanced": "дополнительно",
"lobby.create.min_players_label": "мин. игроков",
"lobby.create.max_players_label": "макс. игроков",
"lobby.create.start_gap_hours_label": "интервал старта (часы)",
"lobby.create.start_gap_players_label": "интервал старта (игроки)",
"lobby.create.target_engine_version_label": "версия движка",
"lobby.create.submit": "создать",
"lobby.create.submitting": "создаём…",
"lobby.create.cancel": "отмена",
"lobby.create.game_name_required": "название игры не должно быть пустым",
"lobby.create.turn_schedule_required": "расписание ходов не должно быть пустым",
"lobby.create.enrollment_ends_at_required": "время окончания набора обязательно",
"lobby.error.invalid_request": "запрос некорректен",
"lobby.error.subject_not_found": "объект не найден",
"lobby.error.forbidden": "операция запрещена",
"lobby.error.conflict": "запрос конфликтует с текущим состоянием",
"lobby.error.internal_error": "внутренняя ошибка сервера",
"lobby.error.unknown": "{message}",
};
export default ru;
+27
View File
@@ -0,0 +1,27 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
export { ApplicationSubmitRequest, ApplicationSubmitRequestT } from './lobby/application-submit-request.js';
export { ApplicationSubmitResponse, ApplicationSubmitResponseT } from './lobby/application-submit-response.js';
export { ApplicationSummary, ApplicationSummaryT } from './lobby/application-summary.js';
export { ErrorBody, ErrorBodyT } from './lobby/error-body.js';
export { ErrorResponse, ErrorResponseT } from './lobby/error-response.js';
export { GameCreateRequest, GameCreateRequestT } from './lobby/game-create-request.js';
export { GameCreateResponse, GameCreateResponseT } from './lobby/game-create-response.js';
export { GameSummary, GameSummaryT } from './lobby/game-summary.js';
export { InviteDeclineRequest, InviteDeclineRequestT } from './lobby/invite-decline-request.js';
export { InviteDeclineResponse, InviteDeclineResponseT } from './lobby/invite-decline-response.js';
export { InviteRedeemRequest, InviteRedeemRequestT } from './lobby/invite-redeem-request.js';
export { InviteRedeemResponse, InviteRedeemResponseT } from './lobby/invite-redeem-response.js';
export { InviteSummary, InviteSummaryT } from './lobby/invite-summary.js';
export { MyApplicationsListRequest, MyApplicationsListRequestT } from './lobby/my-applications-list-request.js';
export { MyApplicationsListResponse, MyApplicationsListResponseT } from './lobby/my-applications-list-response.js';
export { MyGamesListRequest, MyGamesListRequestT } from './lobby/my-games-list-request.js';
export { MyGamesListResponse, MyGamesListResponseT } from './lobby/my-games-list-response.js';
export { MyInvitesListRequest, MyInvitesListRequestT } from './lobby/my-invites-list-request.js';
export { MyInvitesListResponse, MyInvitesListResponseT } from './lobby/my-invites-list-response.js';
export { OpenEnrollmentRequest, OpenEnrollmentRequestT } from './lobby/open-enrollment-request.js';
export { OpenEnrollmentResponse, OpenEnrollmentResponseT } from './lobby/open-enrollment-response.js';
export { PublicGamesListRequest, PublicGamesListRequestT } from './lobby/public-games-list-request.js';
export { PublicGamesListResponse, PublicGamesListResponseT } from './lobby/public-games-list-response.js';
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ApplicationSubmitRequest implements flatbuffers.IUnpackableObject<ApplicationSubmitRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ApplicationSubmitRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsApplicationSubmitRequest(bb:flatbuffers.ByteBuffer, obj?:ApplicationSubmitRequest):ApplicationSubmitRequest {
return (obj || new ApplicationSubmitRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsApplicationSubmitRequest(bb:flatbuffers.ByteBuffer, obj?:ApplicationSubmitRequest):ApplicationSubmitRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ApplicationSubmitRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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;
}
raceName():string|null
raceName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
raceName(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;
}
static startApplicationSubmitRequest(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameIdOffset, 0);
}
static addRaceName(builder:flatbuffers.Builder, raceNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, raceNameOffset, 0);
}
static endApplicationSubmitRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createApplicationSubmitRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, raceNameOffset:flatbuffers.Offset):flatbuffers.Offset {
ApplicationSubmitRequest.startApplicationSubmitRequest(builder);
ApplicationSubmitRequest.addGameId(builder, gameIdOffset);
ApplicationSubmitRequest.addRaceName(builder, raceNameOffset);
return ApplicationSubmitRequest.endApplicationSubmitRequest(builder);
}
unpack(): ApplicationSubmitRequestT {
return new ApplicationSubmitRequestT(
this.gameId(),
this.raceName()
);
}
unpackTo(_o: ApplicationSubmitRequestT): void {
_o.gameId = this.gameId();
_o.raceName = this.raceName();
}
}
export class ApplicationSubmitRequestT implements flatbuffers.IGeneratedObject {
constructor(
public gameId: string|Uint8Array|null = null,
public raceName: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
const raceName = (this.raceName !== null ? builder.createString(this.raceName!) : 0);
return ApplicationSubmitRequest.createApplicationSubmitRequest(builder,
gameId,
raceName
);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ApplicationSummary, ApplicationSummaryT } from './application-summary.js';
export class ApplicationSubmitResponse implements flatbuffers.IUnpackableObject<ApplicationSubmitResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ApplicationSubmitResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsApplicationSubmitResponse(bb:flatbuffers.ByteBuffer, obj?:ApplicationSubmitResponse):ApplicationSubmitResponse {
return (obj || new ApplicationSubmitResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsApplicationSubmitResponse(bb:flatbuffers.ByteBuffer, obj?:ApplicationSubmitResponse):ApplicationSubmitResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ApplicationSubmitResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
application(obj?:ApplicationSummary):ApplicationSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new ApplicationSummary()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startApplicationSubmitResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addApplication(builder:flatbuffers.Builder, applicationOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, applicationOffset, 0);
}
static endApplicationSubmitResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createApplicationSubmitResponse(builder:flatbuffers.Builder, applicationOffset:flatbuffers.Offset):flatbuffers.Offset {
ApplicationSubmitResponse.startApplicationSubmitResponse(builder);
ApplicationSubmitResponse.addApplication(builder, applicationOffset);
return ApplicationSubmitResponse.endApplicationSubmitResponse(builder);
}
unpack(): ApplicationSubmitResponseT {
return new ApplicationSubmitResponseT(
(this.application() !== null ? this.application()!.unpack() : null)
);
}
unpackTo(_o: ApplicationSubmitResponseT): void {
_o.application = (this.application() !== null ? this.application()!.unpack() : null);
}
}
export class ApplicationSubmitResponseT implements flatbuffers.IGeneratedObject {
constructor(
public application: ApplicationSummaryT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const application = (this.application !== null ? this.application!.pack(builder) : 0);
return ApplicationSubmitResponse.createApplicationSubmitResponse(builder,
application
);
}
}
@@ -0,0 +1,174 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ApplicationSummary implements flatbuffers.IUnpackableObject<ApplicationSummaryT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ApplicationSummary {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsApplicationSummary(bb:flatbuffers.ByteBuffer, obj?:ApplicationSummary):ApplicationSummary {
return (obj || new ApplicationSummary()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsApplicationSummary(bb:flatbuffers.ByteBuffer, obj?:ApplicationSummary):ApplicationSummary {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ApplicationSummary()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
applicationId():string|null
applicationId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
applicationId(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;
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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;
}
applicantUserId():string|null
applicantUserId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
applicantUserId(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;
}
raceName():string|null
raceName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
raceName(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
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, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
createdAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
decidedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startApplicationSummary(builder:flatbuffers.Builder) {
builder.startObject(7);
}
static addApplicationId(builder:flatbuffers.Builder, applicationIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, applicationIdOffset, 0);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, gameIdOffset, 0);
}
static addApplicantUserId(builder:flatbuffers.Builder, applicantUserIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, applicantUserIdOffset, 0);
}
static addRaceName(builder:flatbuffers.Builder, raceNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, raceNameOffset, 0);
}
static addStatus(builder:flatbuffers.Builder, statusOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, statusOffset, 0);
}
static addCreatedAtMs(builder:flatbuffers.Builder, createdAtMs:bigint) {
builder.addFieldInt64(5, createdAtMs, BigInt('0'));
}
static addDecidedAtMs(builder:flatbuffers.Builder, decidedAtMs:bigint) {
builder.addFieldInt64(6, decidedAtMs, BigInt('0'));
}
static endApplicationSummary(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createApplicationSummary(builder:flatbuffers.Builder, applicationIdOffset:flatbuffers.Offset, gameIdOffset:flatbuffers.Offset, applicantUserIdOffset:flatbuffers.Offset, raceNameOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset, createdAtMs:bigint, decidedAtMs:bigint):flatbuffers.Offset {
ApplicationSummary.startApplicationSummary(builder);
ApplicationSummary.addApplicationId(builder, applicationIdOffset);
ApplicationSummary.addGameId(builder, gameIdOffset);
ApplicationSummary.addApplicantUserId(builder, applicantUserIdOffset);
ApplicationSummary.addRaceName(builder, raceNameOffset);
ApplicationSummary.addStatus(builder, statusOffset);
ApplicationSummary.addCreatedAtMs(builder, createdAtMs);
ApplicationSummary.addDecidedAtMs(builder, decidedAtMs);
return ApplicationSummary.endApplicationSummary(builder);
}
unpack(): ApplicationSummaryT {
return new ApplicationSummaryT(
this.applicationId(),
this.gameId(),
this.applicantUserId(),
this.raceName(),
this.status(),
this.createdAtMs(),
this.decidedAtMs()
);
}
unpackTo(_o: ApplicationSummaryT): void {
_o.applicationId = this.applicationId();
_o.gameId = this.gameId();
_o.applicantUserId = this.applicantUserId();
_o.raceName = this.raceName();
_o.status = this.status();
_o.createdAtMs = this.createdAtMs();
_o.decidedAtMs = this.decidedAtMs();
}
}
export class ApplicationSummaryT implements flatbuffers.IGeneratedObject {
constructor(
public applicationId: string|Uint8Array|null = null,
public gameId: string|Uint8Array|null = null,
public applicantUserId: string|Uint8Array|null = null,
public raceName: string|Uint8Array|null = null,
public status: string|Uint8Array|null = null,
public createdAtMs: bigint = BigInt('0'),
public decidedAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const applicationId = (this.applicationId !== null ? builder.createString(this.applicationId!) : 0);
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
const applicantUserId = (this.applicantUserId !== null ? builder.createString(this.applicantUserId!) : 0);
const raceName = (this.raceName !== null ? builder.createString(this.raceName!) : 0);
const status = (this.status !== null ? builder.createString(this.status!) : 0);
return ApplicationSummary.createApplicationSummary(builder,
applicationId,
gameId,
applicantUserId,
raceName,
status,
this.createdAtMs,
this.decidedAtMs
);
}
}
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ErrorBody implements flatbuffers.IUnpackableObject<ErrorBodyT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ErrorBody {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsErrorBody(bb:flatbuffers.ByteBuffer, obj?:ErrorBody):ErrorBody {
return (obj || new ErrorBody()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsErrorBody(bb:flatbuffers.ByteBuffer, obj?:ErrorBody):ErrorBody {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ErrorBody()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
code():string|null
code(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
code(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;
}
message():string|null
message(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
message(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;
}
static startErrorBody(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addCode(builder:flatbuffers.Builder, codeOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, codeOffset, 0);
}
static addMessage(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, messageOffset, 0);
}
static endErrorBody(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createErrorBody(builder:flatbuffers.Builder, codeOffset:flatbuffers.Offset, messageOffset:flatbuffers.Offset):flatbuffers.Offset {
ErrorBody.startErrorBody(builder);
ErrorBody.addCode(builder, codeOffset);
ErrorBody.addMessage(builder, messageOffset);
return ErrorBody.endErrorBody(builder);
}
unpack(): ErrorBodyT {
return new ErrorBodyT(
this.code(),
this.message()
);
}
unpackTo(_o: ErrorBodyT): void {
_o.code = this.code();
_o.message = this.message();
}
}
export class ErrorBodyT implements flatbuffers.IGeneratedObject {
constructor(
public code: string|Uint8Array|null = null,
public message: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const code = (this.code !== null ? builder.createString(this.code!) : 0);
const message = (this.message !== null ? builder.createString(this.message!) : 0);
return ErrorBody.createErrorBody(builder,
code,
message
);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ErrorBody, ErrorBodyT } from './error-body.js';
export class ErrorResponse implements flatbuffers.IUnpackableObject<ErrorResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ErrorResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsErrorResponse(bb:flatbuffers.ByteBuffer, obj?:ErrorResponse):ErrorResponse {
return (obj || new ErrorResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsErrorResponse(bb:flatbuffers.ByteBuffer, obj?:ErrorResponse):ErrorResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ErrorResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
error(obj?:ErrorBody):ErrorBody|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new ErrorBody()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startErrorResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addError(builder:flatbuffers.Builder, errorOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, errorOffset, 0);
}
static endErrorResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createErrorResponse(builder:flatbuffers.Builder, errorOffset:flatbuffers.Offset):flatbuffers.Offset {
ErrorResponse.startErrorResponse(builder);
ErrorResponse.addError(builder, errorOffset);
return ErrorResponse.endErrorResponse(builder);
}
unpack(): ErrorResponseT {
return new ErrorResponseT(
(this.error() !== null ? this.error()!.unpack() : null)
);
}
unpackTo(_o: ErrorResponseT): void {
_o.error = (this.error() !== null ? this.error()!.unpack() : null);
}
}
export class ErrorResponseT implements flatbuffers.IGeneratedObject {
constructor(
public error: ErrorBodyT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const error = (this.error !== null ? this.error!.pack(builder) : 0);
return ErrorResponse.createErrorResponse(builder,
error
);
}
}
@@ -0,0 +1,199 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class GameCreateRequest implements flatbuffers.IUnpackableObject<GameCreateRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):GameCreateRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsGameCreateRequest(bb:flatbuffers.ByteBuffer, obj?:GameCreateRequest):GameCreateRequest {
return (obj || new GameCreateRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsGameCreateRequest(bb:flatbuffers.ByteBuffer, obj?:GameCreateRequest):GameCreateRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new GameCreateRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameName():string|null
gameName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameName(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;
}
description():string|null
description(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
description(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;
}
minPlayers():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
maxPlayers():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
startGapHours():number {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
startGapPlayers():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
enrollmentEndsAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
turnSchedule():string|null
turnSchedule(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
turnSchedule(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
targetEngineVersion():string|null
targetEngineVersion(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
targetEngineVersion(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
static startGameCreateRequest(builder:flatbuffers.Builder) {
builder.startObject(9);
}
static addGameName(builder:flatbuffers.Builder, gameNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameNameOffset, 0);
}
static addDescription(builder:flatbuffers.Builder, descriptionOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, descriptionOffset, 0);
}
static addMinPlayers(builder:flatbuffers.Builder, minPlayers:number) {
builder.addFieldInt32(2, minPlayers, 0);
}
static addMaxPlayers(builder:flatbuffers.Builder, maxPlayers:number) {
builder.addFieldInt32(3, maxPlayers, 0);
}
static addStartGapHours(builder:flatbuffers.Builder, startGapHours:number) {
builder.addFieldInt32(4, startGapHours, 0);
}
static addStartGapPlayers(builder:flatbuffers.Builder, startGapPlayers:number) {
builder.addFieldInt32(5, startGapPlayers, 0);
}
static addEnrollmentEndsAtMs(builder:flatbuffers.Builder, enrollmentEndsAtMs:bigint) {
builder.addFieldInt64(6, enrollmentEndsAtMs, BigInt('0'));
}
static addTurnSchedule(builder:flatbuffers.Builder, turnScheduleOffset:flatbuffers.Offset) {
builder.addFieldOffset(7, turnScheduleOffset, 0);
}
static addTargetEngineVersion(builder:flatbuffers.Builder, targetEngineVersionOffset:flatbuffers.Offset) {
builder.addFieldOffset(8, targetEngineVersionOffset, 0);
}
static endGameCreateRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createGameCreateRequest(builder:flatbuffers.Builder, gameNameOffset:flatbuffers.Offset, descriptionOffset:flatbuffers.Offset, minPlayers:number, maxPlayers:number, startGapHours:number, startGapPlayers:number, enrollmentEndsAtMs:bigint, turnScheduleOffset:flatbuffers.Offset, targetEngineVersionOffset:flatbuffers.Offset):flatbuffers.Offset {
GameCreateRequest.startGameCreateRequest(builder);
GameCreateRequest.addGameName(builder, gameNameOffset);
GameCreateRequest.addDescription(builder, descriptionOffset);
GameCreateRequest.addMinPlayers(builder, minPlayers);
GameCreateRequest.addMaxPlayers(builder, maxPlayers);
GameCreateRequest.addStartGapHours(builder, startGapHours);
GameCreateRequest.addStartGapPlayers(builder, startGapPlayers);
GameCreateRequest.addEnrollmentEndsAtMs(builder, enrollmentEndsAtMs);
GameCreateRequest.addTurnSchedule(builder, turnScheduleOffset);
GameCreateRequest.addTargetEngineVersion(builder, targetEngineVersionOffset);
return GameCreateRequest.endGameCreateRequest(builder);
}
unpack(): GameCreateRequestT {
return new GameCreateRequestT(
this.gameName(),
this.description(),
this.minPlayers(),
this.maxPlayers(),
this.startGapHours(),
this.startGapPlayers(),
this.enrollmentEndsAtMs(),
this.turnSchedule(),
this.targetEngineVersion()
);
}
unpackTo(_o: GameCreateRequestT): void {
_o.gameName = this.gameName();
_o.description = this.description();
_o.minPlayers = this.minPlayers();
_o.maxPlayers = this.maxPlayers();
_o.startGapHours = this.startGapHours();
_o.startGapPlayers = this.startGapPlayers();
_o.enrollmentEndsAtMs = this.enrollmentEndsAtMs();
_o.turnSchedule = this.turnSchedule();
_o.targetEngineVersion = this.targetEngineVersion();
}
}
export class GameCreateRequestT implements flatbuffers.IGeneratedObject {
constructor(
public gameName: string|Uint8Array|null = null,
public description: string|Uint8Array|null = null,
public minPlayers: number = 0,
public maxPlayers: number = 0,
public startGapHours: number = 0,
public startGapPlayers: number = 0,
public enrollmentEndsAtMs: bigint = BigInt('0'),
public turnSchedule: string|Uint8Array|null = null,
public targetEngineVersion: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const gameName = (this.gameName !== null ? builder.createString(this.gameName!) : 0);
const description = (this.description !== null ? builder.createString(this.description!) : 0);
const turnSchedule = (this.turnSchedule !== null ? builder.createString(this.turnSchedule!) : 0);
const targetEngineVersion = (this.targetEngineVersion !== null ? builder.createString(this.targetEngineVersion!) : 0);
return GameCreateRequest.createGameCreateRequest(builder,
gameName,
description,
this.minPlayers,
this.maxPlayers,
this.startGapHours,
this.startGapPlayers,
this.enrollmentEndsAtMs,
turnSchedule,
targetEngineVersion
);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { GameSummary, GameSummaryT } from './game-summary.js';
export class GameCreateResponse implements flatbuffers.IUnpackableObject<GameCreateResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):GameCreateResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsGameCreateResponse(bb:flatbuffers.ByteBuffer, obj?:GameCreateResponse):GameCreateResponse {
return (obj || new GameCreateResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsGameCreateResponse(bb:flatbuffers.ByteBuffer, obj?:GameCreateResponse):GameCreateResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new GameCreateResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
game(obj?:GameSummary):GameSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new GameSummary()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startGameCreateResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addGame(builder:flatbuffers.Builder, gameOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameOffset, 0);
}
static endGameCreateResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createGameCreateResponse(builder:flatbuffers.Builder, gameOffset:flatbuffers.Offset):flatbuffers.Offset {
GameCreateResponse.startGameCreateResponse(builder);
GameCreateResponse.addGame(builder, gameOffset);
return GameCreateResponse.endGameCreateResponse(builder);
}
unpack(): GameCreateResponseT {
return new GameCreateResponseT(
(this.game() !== null ? this.game()!.unpack() : null)
);
}
unpackTo(_o: GameCreateResponseT): void {
_o.game = (this.game() !== null ? this.game()!.unpack() : null);
}
}
export class GameCreateResponseT implements flatbuffers.IGeneratedObject {
constructor(
public game: GameSummaryT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const game = (this.game !== null ? this.game!.pack(builder) : 0);
return GameCreateResponse.createGameCreateResponse(builder,
game
);
}
}
@@ -0,0 +1,216 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class GameSummary implements flatbuffers.IUnpackableObject<GameSummaryT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):GameSummary {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsGameSummary(bb:flatbuffers.ByteBuffer, obj?:GameSummary):GameSummary {
return (obj || new GameSummary()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsGameSummary(bb:flatbuffers.ByteBuffer, obj?:GameSummary):GameSummary {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new GameSummary()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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;
}
gameName():string|null
gameName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameName(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;
}
gameType():string|null
gameType(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameType(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;
}
status():string|null
status(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
status(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
ownerUserId():string|null
ownerUserId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
ownerUserId(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
minPlayers():number {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
maxPlayers():number {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
enrollmentEndsAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
createdAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
updatedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startGameSummary(builder:flatbuffers.Builder) {
builder.startObject(10);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameIdOffset, 0);
}
static addGameName(builder:flatbuffers.Builder, gameNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, gameNameOffset, 0);
}
static addGameType(builder:flatbuffers.Builder, gameTypeOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, gameTypeOffset, 0);
}
static addStatus(builder:flatbuffers.Builder, statusOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, statusOffset, 0);
}
static addOwnerUserId(builder:flatbuffers.Builder, ownerUserIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, ownerUserIdOffset, 0);
}
static addMinPlayers(builder:flatbuffers.Builder, minPlayers:number) {
builder.addFieldInt32(5, minPlayers, 0);
}
static addMaxPlayers(builder:flatbuffers.Builder, maxPlayers:number) {
builder.addFieldInt32(6, maxPlayers, 0);
}
static addEnrollmentEndsAtMs(builder:flatbuffers.Builder, enrollmentEndsAtMs:bigint) {
builder.addFieldInt64(7, enrollmentEndsAtMs, BigInt('0'));
}
static addCreatedAtMs(builder:flatbuffers.Builder, createdAtMs:bigint) {
builder.addFieldInt64(8, createdAtMs, BigInt('0'));
}
static addUpdatedAtMs(builder:flatbuffers.Builder, updatedAtMs:bigint) {
builder.addFieldInt64(9, updatedAtMs, BigInt('0'));
}
static endGameSummary(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createGameSummary(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, gameNameOffset:flatbuffers.Offset, gameTypeOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset, ownerUserIdOffset:flatbuffers.Offset, minPlayers:number, maxPlayers:number, enrollmentEndsAtMs:bigint, createdAtMs:bigint, updatedAtMs:bigint):flatbuffers.Offset {
GameSummary.startGameSummary(builder);
GameSummary.addGameId(builder, gameIdOffset);
GameSummary.addGameName(builder, gameNameOffset);
GameSummary.addGameType(builder, gameTypeOffset);
GameSummary.addStatus(builder, statusOffset);
GameSummary.addOwnerUserId(builder, ownerUserIdOffset);
GameSummary.addMinPlayers(builder, minPlayers);
GameSummary.addMaxPlayers(builder, maxPlayers);
GameSummary.addEnrollmentEndsAtMs(builder, enrollmentEndsAtMs);
GameSummary.addCreatedAtMs(builder, createdAtMs);
GameSummary.addUpdatedAtMs(builder, updatedAtMs);
return GameSummary.endGameSummary(builder);
}
unpack(): GameSummaryT {
return new GameSummaryT(
this.gameId(),
this.gameName(),
this.gameType(),
this.status(),
this.ownerUserId(),
this.minPlayers(),
this.maxPlayers(),
this.enrollmentEndsAtMs(),
this.createdAtMs(),
this.updatedAtMs()
);
}
unpackTo(_o: GameSummaryT): void {
_o.gameId = this.gameId();
_o.gameName = this.gameName();
_o.gameType = this.gameType();
_o.status = this.status();
_o.ownerUserId = this.ownerUserId();
_o.minPlayers = this.minPlayers();
_o.maxPlayers = this.maxPlayers();
_o.enrollmentEndsAtMs = this.enrollmentEndsAtMs();
_o.createdAtMs = this.createdAtMs();
_o.updatedAtMs = this.updatedAtMs();
}
}
export class GameSummaryT implements flatbuffers.IGeneratedObject {
constructor(
public gameId: string|Uint8Array|null = null,
public gameName: string|Uint8Array|null = null,
public gameType: string|Uint8Array|null = null,
public status: string|Uint8Array|null = null,
public ownerUserId: string|Uint8Array|null = null,
public minPlayers: number = 0,
public maxPlayers: number = 0,
public enrollmentEndsAtMs: bigint = BigInt('0'),
public createdAtMs: bigint = BigInt('0'),
public updatedAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
const gameName = (this.gameName !== null ? builder.createString(this.gameName!) : 0);
const gameType = (this.gameType !== null ? builder.createString(this.gameType!) : 0);
const status = (this.status !== null ? builder.createString(this.status!) : 0);
const ownerUserId = (this.ownerUserId !== null ? builder.createString(this.ownerUserId!) : 0);
return GameSummary.createGameSummary(builder,
gameId,
gameName,
gameType,
status,
ownerUserId,
this.minPlayers,
this.maxPlayers,
this.enrollmentEndsAtMs,
this.createdAtMs,
this.updatedAtMs
);
}
}
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class InviteDeclineRequest implements flatbuffers.IUnpackableObject<InviteDeclineRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):InviteDeclineRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsInviteDeclineRequest(bb:flatbuffers.ByteBuffer, obj?:InviteDeclineRequest):InviteDeclineRequest {
return (obj || new InviteDeclineRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsInviteDeclineRequest(bb:flatbuffers.ByteBuffer, obj?:InviteDeclineRequest):InviteDeclineRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new InviteDeclineRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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;
}
inviteId():string|null
inviteId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
inviteId(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;
}
static startInviteDeclineRequest(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameIdOffset, 0);
}
static addInviteId(builder:flatbuffers.Builder, inviteIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, inviteIdOffset, 0);
}
static endInviteDeclineRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createInviteDeclineRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, inviteIdOffset:flatbuffers.Offset):flatbuffers.Offset {
InviteDeclineRequest.startInviteDeclineRequest(builder);
InviteDeclineRequest.addGameId(builder, gameIdOffset);
InviteDeclineRequest.addInviteId(builder, inviteIdOffset);
return InviteDeclineRequest.endInviteDeclineRequest(builder);
}
unpack(): InviteDeclineRequestT {
return new InviteDeclineRequestT(
this.gameId(),
this.inviteId()
);
}
unpackTo(_o: InviteDeclineRequestT): void {
_o.gameId = this.gameId();
_o.inviteId = this.inviteId();
}
}
export class InviteDeclineRequestT implements flatbuffers.IGeneratedObject {
constructor(
public gameId: string|Uint8Array|null = null,
public inviteId: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
const inviteId = (this.inviteId !== null ? builder.createString(this.inviteId!) : 0);
return InviteDeclineRequest.createInviteDeclineRequest(builder,
gameId,
inviteId
);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { InviteSummary, InviteSummaryT } from './invite-summary.js';
export class InviteDeclineResponse implements flatbuffers.IUnpackableObject<InviteDeclineResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):InviteDeclineResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsInviteDeclineResponse(bb:flatbuffers.ByteBuffer, obj?:InviteDeclineResponse):InviteDeclineResponse {
return (obj || new InviteDeclineResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsInviteDeclineResponse(bb:flatbuffers.ByteBuffer, obj?:InviteDeclineResponse):InviteDeclineResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new InviteDeclineResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
invite(obj?:InviteSummary):InviteSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new InviteSummary()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startInviteDeclineResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addInvite(builder:flatbuffers.Builder, inviteOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, inviteOffset, 0);
}
static endInviteDeclineResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createInviteDeclineResponse(builder:flatbuffers.Builder, inviteOffset:flatbuffers.Offset):flatbuffers.Offset {
InviteDeclineResponse.startInviteDeclineResponse(builder);
InviteDeclineResponse.addInvite(builder, inviteOffset);
return InviteDeclineResponse.endInviteDeclineResponse(builder);
}
unpack(): InviteDeclineResponseT {
return new InviteDeclineResponseT(
(this.invite() !== null ? this.invite()!.unpack() : null)
);
}
unpackTo(_o: InviteDeclineResponseT): void {
_o.invite = (this.invite() !== null ? this.invite()!.unpack() : null);
}
}
export class InviteDeclineResponseT implements flatbuffers.IGeneratedObject {
constructor(
public invite: InviteSummaryT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const invite = (this.invite !== null ? this.invite!.pack(builder) : 0);
return InviteDeclineResponse.createInviteDeclineResponse(builder,
invite
);
}
}
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class InviteRedeemRequest implements flatbuffers.IUnpackableObject<InviteRedeemRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):InviteRedeemRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsInviteRedeemRequest(bb:flatbuffers.ByteBuffer, obj?:InviteRedeemRequest):InviteRedeemRequest {
return (obj || new InviteRedeemRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsInviteRedeemRequest(bb:flatbuffers.ByteBuffer, obj?:InviteRedeemRequest):InviteRedeemRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new InviteRedeemRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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;
}
inviteId():string|null
inviteId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
inviteId(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;
}
static startInviteRedeemRequest(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameIdOffset, 0);
}
static addInviteId(builder:flatbuffers.Builder, inviteIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, inviteIdOffset, 0);
}
static endInviteRedeemRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createInviteRedeemRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, inviteIdOffset:flatbuffers.Offset):flatbuffers.Offset {
InviteRedeemRequest.startInviteRedeemRequest(builder);
InviteRedeemRequest.addGameId(builder, gameIdOffset);
InviteRedeemRequest.addInviteId(builder, inviteIdOffset);
return InviteRedeemRequest.endInviteRedeemRequest(builder);
}
unpack(): InviteRedeemRequestT {
return new InviteRedeemRequestT(
this.gameId(),
this.inviteId()
);
}
unpackTo(_o: InviteRedeemRequestT): void {
_o.gameId = this.gameId();
_o.inviteId = this.inviteId();
}
}
export class InviteRedeemRequestT implements flatbuffers.IGeneratedObject {
constructor(
public gameId: string|Uint8Array|null = null,
public inviteId: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
const inviteId = (this.inviteId !== null ? builder.createString(this.inviteId!) : 0);
return InviteRedeemRequest.createInviteRedeemRequest(builder,
gameId,
inviteId
);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { InviteSummary, InviteSummaryT } from './invite-summary.js';
export class InviteRedeemResponse implements flatbuffers.IUnpackableObject<InviteRedeemResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):InviteRedeemResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsInviteRedeemResponse(bb:flatbuffers.ByteBuffer, obj?:InviteRedeemResponse):InviteRedeemResponse {
return (obj || new InviteRedeemResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsInviteRedeemResponse(bb:flatbuffers.ByteBuffer, obj?:InviteRedeemResponse):InviteRedeemResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new InviteRedeemResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
invite(obj?:InviteSummary):InviteSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new InviteSummary()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startInviteRedeemResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addInvite(builder:flatbuffers.Builder, inviteOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, inviteOffset, 0);
}
static endInviteRedeemResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createInviteRedeemResponse(builder:flatbuffers.Builder, inviteOffset:flatbuffers.Offset):flatbuffers.Offset {
InviteRedeemResponse.startInviteRedeemResponse(builder);
InviteRedeemResponse.addInvite(builder, inviteOffset);
return InviteRedeemResponse.endInviteRedeemResponse(builder);
}
unpack(): InviteRedeemResponseT {
return new InviteRedeemResponseT(
(this.invite() !== null ? this.invite()!.unpack() : null)
);
}
unpackTo(_o: InviteRedeemResponseT): void {
_o.invite = (this.invite() !== null ? this.invite()!.unpack() : null);
}
}
export class InviteRedeemResponseT implements flatbuffers.IGeneratedObject {
constructor(
public invite: InviteSummaryT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const invite = (this.invite !== null ? this.invite!.pack(builder) : 0);
return InviteRedeemResponse.createInviteRedeemResponse(builder,
invite
);
}
}
@@ -0,0 +1,222 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class InviteSummary implements flatbuffers.IUnpackableObject<InviteSummaryT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):InviteSummary {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsInviteSummary(bb:flatbuffers.ByteBuffer, obj?:InviteSummary):InviteSummary {
return (obj || new InviteSummary()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsInviteSummary(bb:flatbuffers.ByteBuffer, obj?:InviteSummary):InviteSummary {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new InviteSummary()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
inviteId():string|null
inviteId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
inviteId(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;
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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;
}
inviterUserId():string|null
inviterUserId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
inviterUserId(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;
}
invitedUserId():string|null
invitedUserId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
invitedUserId(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
code():string|null
code(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
code(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
raceName():string|null
raceName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
raceName(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 14);
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, 16);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
createdAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
expiresAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
decidedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startInviteSummary(builder:flatbuffers.Builder) {
builder.startObject(10);
}
static addInviteId(builder:flatbuffers.Builder, inviteIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, inviteIdOffset, 0);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, gameIdOffset, 0);
}
static addInviterUserId(builder:flatbuffers.Builder, inviterUserIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, inviterUserIdOffset, 0);
}
static addInvitedUserId(builder:flatbuffers.Builder, invitedUserIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, invitedUserIdOffset, 0);
}
static addCode(builder:flatbuffers.Builder, codeOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, codeOffset, 0);
}
static addRaceName(builder:flatbuffers.Builder, raceNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(5, raceNameOffset, 0);
}
static addStatus(builder:flatbuffers.Builder, statusOffset:flatbuffers.Offset) {
builder.addFieldOffset(6, statusOffset, 0);
}
static addCreatedAtMs(builder:flatbuffers.Builder, createdAtMs:bigint) {
builder.addFieldInt64(7, createdAtMs, BigInt('0'));
}
static addExpiresAtMs(builder:flatbuffers.Builder, expiresAtMs:bigint) {
builder.addFieldInt64(8, expiresAtMs, BigInt('0'));
}
static addDecidedAtMs(builder:flatbuffers.Builder, decidedAtMs:bigint) {
builder.addFieldInt64(9, decidedAtMs, BigInt('0'));
}
static endInviteSummary(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createInviteSummary(builder:flatbuffers.Builder, inviteIdOffset:flatbuffers.Offset, gameIdOffset:flatbuffers.Offset, inviterUserIdOffset:flatbuffers.Offset, invitedUserIdOffset:flatbuffers.Offset, codeOffset:flatbuffers.Offset, raceNameOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset, createdAtMs:bigint, expiresAtMs:bigint, decidedAtMs:bigint):flatbuffers.Offset {
InviteSummary.startInviteSummary(builder);
InviteSummary.addInviteId(builder, inviteIdOffset);
InviteSummary.addGameId(builder, gameIdOffset);
InviteSummary.addInviterUserId(builder, inviterUserIdOffset);
InviteSummary.addInvitedUserId(builder, invitedUserIdOffset);
InviteSummary.addCode(builder, codeOffset);
InviteSummary.addRaceName(builder, raceNameOffset);
InviteSummary.addStatus(builder, statusOffset);
InviteSummary.addCreatedAtMs(builder, createdAtMs);
InviteSummary.addExpiresAtMs(builder, expiresAtMs);
InviteSummary.addDecidedAtMs(builder, decidedAtMs);
return InviteSummary.endInviteSummary(builder);
}
unpack(): InviteSummaryT {
return new InviteSummaryT(
this.inviteId(),
this.gameId(),
this.inviterUserId(),
this.invitedUserId(),
this.code(),
this.raceName(),
this.status(),
this.createdAtMs(),
this.expiresAtMs(),
this.decidedAtMs()
);
}
unpackTo(_o: InviteSummaryT): void {
_o.inviteId = this.inviteId();
_o.gameId = this.gameId();
_o.inviterUserId = this.inviterUserId();
_o.invitedUserId = this.invitedUserId();
_o.code = this.code();
_o.raceName = this.raceName();
_o.status = this.status();
_o.createdAtMs = this.createdAtMs();
_o.expiresAtMs = this.expiresAtMs();
_o.decidedAtMs = this.decidedAtMs();
}
}
export class InviteSummaryT implements flatbuffers.IGeneratedObject {
constructor(
public inviteId: string|Uint8Array|null = null,
public gameId: string|Uint8Array|null = null,
public inviterUserId: string|Uint8Array|null = null,
public invitedUserId: string|Uint8Array|null = null,
public code: string|Uint8Array|null = null,
public raceName: string|Uint8Array|null = null,
public status: string|Uint8Array|null = null,
public createdAtMs: bigint = BigInt('0'),
public expiresAtMs: bigint = BigInt('0'),
public decidedAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const inviteId = (this.inviteId !== null ? builder.createString(this.inviteId!) : 0);
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
const inviterUserId = (this.inviterUserId !== null ? builder.createString(this.inviterUserId!) : 0);
const invitedUserId = (this.invitedUserId !== null ? builder.createString(this.invitedUserId!) : 0);
const code = (this.code !== null ? builder.createString(this.code!) : 0);
const raceName = (this.raceName !== null ? builder.createString(this.raceName!) : 0);
const status = (this.status !== null ? builder.createString(this.status!) : 0);
return InviteSummary.createInviteSummary(builder,
inviteId,
gameId,
inviterUserId,
invitedUserId,
code,
raceName,
status,
this.createdAtMs,
this.expiresAtMs,
this.decidedAtMs
);
}
}
@@ -0,0 +1,56 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class MyApplicationsListRequest implements flatbuffers.IUnpackableObject<MyApplicationsListRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):MyApplicationsListRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsMyApplicationsListRequest(bb:flatbuffers.ByteBuffer, obj?:MyApplicationsListRequest):MyApplicationsListRequest {
return (obj || new MyApplicationsListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsMyApplicationsListRequest(bb:flatbuffers.ByteBuffer, obj?:MyApplicationsListRequest):MyApplicationsListRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new MyApplicationsListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static startMyApplicationsListRequest(builder:flatbuffers.Builder) {
builder.startObject(0);
}
static endMyApplicationsListRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createMyApplicationsListRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
MyApplicationsListRequest.startMyApplicationsListRequest(builder);
return MyApplicationsListRequest.endMyApplicationsListRequest(builder);
}
unpack(): MyApplicationsListRequestT {
return new MyApplicationsListRequestT();
}
unpackTo(_o: MyApplicationsListRequestT): void {}
}
export class MyApplicationsListRequestT implements flatbuffers.IGeneratedObject {
constructor(){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return MyApplicationsListRequest.createMyApplicationsListRequest(builder);
}
}
@@ -0,0 +1,94 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ApplicationSummary, ApplicationSummaryT } from './application-summary.js';
export class MyApplicationsListResponse implements flatbuffers.IUnpackableObject<MyApplicationsListResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):MyApplicationsListResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsMyApplicationsListResponse(bb:flatbuffers.ByteBuffer, obj?:MyApplicationsListResponse):MyApplicationsListResponse {
return (obj || new MyApplicationsListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsMyApplicationsListResponse(bb:flatbuffers.ByteBuffer, obj?:MyApplicationsListResponse):MyApplicationsListResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new MyApplicationsListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
items(index: number, obj?:ApplicationSummary):ApplicationSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new ApplicationSummary()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
itemsLength():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
static startMyApplicationsListResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addItems(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, itemsOffset, 0);
}
static createItemsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startItemsVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static endMyApplicationsListResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createMyApplicationsListResponse(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset):flatbuffers.Offset {
MyApplicationsListResponse.startMyApplicationsListResponse(builder);
MyApplicationsListResponse.addItems(builder, itemsOffset);
return MyApplicationsListResponse.endMyApplicationsListResponse(builder);
}
unpack(): MyApplicationsListResponseT {
return new MyApplicationsListResponseT(
this.bb!.createObjList<ApplicationSummary, ApplicationSummaryT>(this.items.bind(this), this.itemsLength())
);
}
unpackTo(_o: MyApplicationsListResponseT): void {
_o.items = this.bb!.createObjList<ApplicationSummary, ApplicationSummaryT>(this.items.bind(this), this.itemsLength());
}
}
export class MyApplicationsListResponseT implements flatbuffers.IGeneratedObject {
constructor(
public items: (ApplicationSummaryT)[] = []
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const items = MyApplicationsListResponse.createItemsVector(builder, builder.createObjectOffsetList(this.items));
return MyApplicationsListResponse.createMyApplicationsListResponse(builder,
items
);
}
}
@@ -0,0 +1,56 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class MyGamesListRequest implements flatbuffers.IUnpackableObject<MyGamesListRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):MyGamesListRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsMyGamesListRequest(bb:flatbuffers.ByteBuffer, obj?:MyGamesListRequest):MyGamesListRequest {
return (obj || new MyGamesListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsMyGamesListRequest(bb:flatbuffers.ByteBuffer, obj?:MyGamesListRequest):MyGamesListRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new MyGamesListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static startMyGamesListRequest(builder:flatbuffers.Builder) {
builder.startObject(0);
}
static endMyGamesListRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createMyGamesListRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
MyGamesListRequest.startMyGamesListRequest(builder);
return MyGamesListRequest.endMyGamesListRequest(builder);
}
unpack(): MyGamesListRequestT {
return new MyGamesListRequestT();
}
unpackTo(_o: MyGamesListRequestT): void {}
}
export class MyGamesListRequestT implements flatbuffers.IGeneratedObject {
constructor(){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return MyGamesListRequest.createMyGamesListRequest(builder);
}
}
@@ -0,0 +1,102 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { GameSummary, GameSummaryT } from './game-summary.js';
export class MyGamesListResponse implements flatbuffers.IUnpackableObject<MyGamesListResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):MyGamesListResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsMyGamesListResponse(bb:flatbuffers.ByteBuffer, obj?:MyGamesListResponse):MyGamesListResponse {
return (obj || new MyGamesListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsMyGamesListResponse(bb:flatbuffers.ByteBuffer, obj?:MyGamesListResponse):MyGamesListResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new MyGamesListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
items(index: number, obj?:GameSummary):GameSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new GameSummary()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
itemsLength():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
static startMyGamesListResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addItems(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, itemsOffset, 0);
}
static createItemsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startItemsVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static endMyGamesListResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static finishMyGamesListResponseBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
builder.finish(offset);
}
static finishSizePrefixedMyGamesListResponseBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
builder.finish(offset, undefined, true);
}
static createMyGamesListResponse(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset):flatbuffers.Offset {
MyGamesListResponse.startMyGamesListResponse(builder);
MyGamesListResponse.addItems(builder, itemsOffset);
return MyGamesListResponse.endMyGamesListResponse(builder);
}
unpack(): MyGamesListResponseT {
return new MyGamesListResponseT(
this.bb!.createObjList<GameSummary, GameSummaryT>(this.items.bind(this), this.itemsLength())
);
}
unpackTo(_o: MyGamesListResponseT): void {
_o.items = this.bb!.createObjList<GameSummary, GameSummaryT>(this.items.bind(this), this.itemsLength());
}
}
export class MyGamesListResponseT implements flatbuffers.IGeneratedObject {
constructor(
public items: (GameSummaryT)[] = []
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const items = MyGamesListResponse.createItemsVector(builder, builder.createObjectOffsetList(this.items));
return MyGamesListResponse.createMyGamesListResponse(builder,
items
);
}
}
@@ -0,0 +1,56 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class MyInvitesListRequest implements flatbuffers.IUnpackableObject<MyInvitesListRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):MyInvitesListRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsMyInvitesListRequest(bb:flatbuffers.ByteBuffer, obj?:MyInvitesListRequest):MyInvitesListRequest {
return (obj || new MyInvitesListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsMyInvitesListRequest(bb:flatbuffers.ByteBuffer, obj?:MyInvitesListRequest):MyInvitesListRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new MyInvitesListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static startMyInvitesListRequest(builder:flatbuffers.Builder) {
builder.startObject(0);
}
static endMyInvitesListRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createMyInvitesListRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
MyInvitesListRequest.startMyInvitesListRequest(builder);
return MyInvitesListRequest.endMyInvitesListRequest(builder);
}
unpack(): MyInvitesListRequestT {
return new MyInvitesListRequestT();
}
unpackTo(_o: MyInvitesListRequestT): void {}
}
export class MyInvitesListRequestT implements flatbuffers.IGeneratedObject {
constructor(){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return MyInvitesListRequest.createMyInvitesListRequest(builder);
}
}
@@ -0,0 +1,94 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { InviteSummary, InviteSummaryT } from './invite-summary.js';
export class MyInvitesListResponse implements flatbuffers.IUnpackableObject<MyInvitesListResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):MyInvitesListResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsMyInvitesListResponse(bb:flatbuffers.ByteBuffer, obj?:MyInvitesListResponse):MyInvitesListResponse {
return (obj || new MyInvitesListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsMyInvitesListResponse(bb:flatbuffers.ByteBuffer, obj?:MyInvitesListResponse):MyInvitesListResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new MyInvitesListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
items(index: number, obj?:InviteSummary):InviteSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new InviteSummary()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
itemsLength():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
static startMyInvitesListResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addItems(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, itemsOffset, 0);
}
static createItemsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startItemsVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static endMyInvitesListResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createMyInvitesListResponse(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset):flatbuffers.Offset {
MyInvitesListResponse.startMyInvitesListResponse(builder);
MyInvitesListResponse.addItems(builder, itemsOffset);
return MyInvitesListResponse.endMyInvitesListResponse(builder);
}
unpack(): MyInvitesListResponseT {
return new MyInvitesListResponseT(
this.bb!.createObjList<InviteSummary, InviteSummaryT>(this.items.bind(this), this.itemsLength())
);
}
unpackTo(_o: MyInvitesListResponseT): void {
_o.items = this.bb!.createObjList<InviteSummary, InviteSummaryT>(this.items.bind(this), this.itemsLength());
}
}
export class MyInvitesListResponseT implements flatbuffers.IGeneratedObject {
constructor(
public items: (InviteSummaryT)[] = []
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const items = MyInvitesListResponse.createItemsVector(builder, builder.createObjectOffsetList(this.items));
return MyInvitesListResponse.createMyInvitesListResponse(builder,
items
);
}
}
@@ -0,0 +1,78 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class OpenEnrollmentRequest implements flatbuffers.IUnpackableObject<OpenEnrollmentRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):OpenEnrollmentRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsOpenEnrollmentRequest(bb:flatbuffers.ByteBuffer, obj?:OpenEnrollmentRequest):OpenEnrollmentRequest {
return (obj || new OpenEnrollmentRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsOpenEnrollmentRequest(bb:flatbuffers.ByteBuffer, obj?:OpenEnrollmentRequest):OpenEnrollmentRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new OpenEnrollmentRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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 startOpenEnrollmentRequest(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameIdOffset, 0);
}
static endOpenEnrollmentRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createOpenEnrollmentRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset):flatbuffers.Offset {
OpenEnrollmentRequest.startOpenEnrollmentRequest(builder);
OpenEnrollmentRequest.addGameId(builder, gameIdOffset);
return OpenEnrollmentRequest.endOpenEnrollmentRequest(builder);
}
unpack(): OpenEnrollmentRequestT {
return new OpenEnrollmentRequestT(
this.gameId()
);
}
unpackTo(_o: OpenEnrollmentRequestT): void {
_o.gameId = this.gameId();
}
}
export class OpenEnrollmentRequestT implements flatbuffers.IGeneratedObject {
constructor(
public gameId: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
return OpenEnrollmentRequest.createOpenEnrollmentRequest(builder,
gameId
);
}
}
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class OpenEnrollmentResponse implements flatbuffers.IUnpackableObject<OpenEnrollmentResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):OpenEnrollmentResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsOpenEnrollmentResponse(bb:flatbuffers.ByteBuffer, obj?:OpenEnrollmentResponse):OpenEnrollmentResponse {
return (obj || new OpenEnrollmentResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsOpenEnrollmentResponse(bb:flatbuffers.ByteBuffer, obj?:OpenEnrollmentResponse):OpenEnrollmentResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new OpenEnrollmentResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
gameId():string|null
gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
gameId(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;
}
static startOpenEnrollmentResponse(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, gameIdOffset, 0);
}
static addStatus(builder:flatbuffers.Builder, statusOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, statusOffset, 0);
}
static endOpenEnrollmentResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createOpenEnrollmentResponse(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset):flatbuffers.Offset {
OpenEnrollmentResponse.startOpenEnrollmentResponse(builder);
OpenEnrollmentResponse.addGameId(builder, gameIdOffset);
OpenEnrollmentResponse.addStatus(builder, statusOffset);
return OpenEnrollmentResponse.endOpenEnrollmentResponse(builder);
}
unpack(): OpenEnrollmentResponseT {
return new OpenEnrollmentResponseT(
this.gameId(),
this.status()
);
}
unpackTo(_o: OpenEnrollmentResponseT): void {
_o.gameId = this.gameId();
_o.status = this.status();
}
}
export class OpenEnrollmentResponseT implements flatbuffers.IGeneratedObject {
constructor(
public gameId: string|Uint8Array|null = null,
public status: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const gameId = (this.gameId !== null ? builder.createString(this.gameId!) : 0);
const status = (this.status !== null ? builder.createString(this.status!) : 0);
return OpenEnrollmentResponse.createOpenEnrollmentResponse(builder,
gameId,
status
);
}
}
@@ -0,0 +1,88 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class PublicGamesListRequest implements flatbuffers.IUnpackableObject<PublicGamesListRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):PublicGamesListRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsPublicGamesListRequest(bb:flatbuffers.ByteBuffer, obj?:PublicGamesListRequest):PublicGamesListRequest {
return (obj || new PublicGamesListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsPublicGamesListRequest(bb:flatbuffers.ByteBuffer, obj?:PublicGamesListRequest):PublicGamesListRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new PublicGamesListRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
page():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
pageSize():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
static startPublicGamesListRequest(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addPage(builder:flatbuffers.Builder, page:number) {
builder.addFieldInt32(0, page, 0);
}
static addPageSize(builder:flatbuffers.Builder, pageSize:number) {
builder.addFieldInt32(1, pageSize, 0);
}
static endPublicGamesListRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createPublicGamesListRequest(builder:flatbuffers.Builder, page:number, pageSize:number):flatbuffers.Offset {
PublicGamesListRequest.startPublicGamesListRequest(builder);
PublicGamesListRequest.addPage(builder, page);
PublicGamesListRequest.addPageSize(builder, pageSize);
return PublicGamesListRequest.endPublicGamesListRequest(builder);
}
unpack(): PublicGamesListRequestT {
return new PublicGamesListRequestT(
this.page(),
this.pageSize()
);
}
unpackTo(_o: PublicGamesListRequestT): void {
_o.page = this.page();
_o.pageSize = this.pageSize();
}
}
export class PublicGamesListRequestT implements flatbuffers.IGeneratedObject {
constructor(
public page: number = 0,
public pageSize: number = 0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return PublicGamesListRequest.createPublicGamesListRequest(builder,
this.page,
this.pageSize
);
}
}
@@ -0,0 +1,136 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { GameSummary, GameSummaryT } from './game-summary.js';
export class PublicGamesListResponse implements flatbuffers.IUnpackableObject<PublicGamesListResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):PublicGamesListResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsPublicGamesListResponse(bb:flatbuffers.ByteBuffer, obj?:PublicGamesListResponse):PublicGamesListResponse {
return (obj || new PublicGamesListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsPublicGamesListResponse(bb:flatbuffers.ByteBuffer, obj?:PublicGamesListResponse):PublicGamesListResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new PublicGamesListResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
items(index: number, obj?:GameSummary):GameSummary|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new GameSummary()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
itemsLength():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
page():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
pageSize():number {
const offset = this.bb!.__offset(this.bb_pos, 8);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
total():number {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
static startPublicGamesListResponse(builder:flatbuffers.Builder) {
builder.startObject(4);
}
static addItems(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, itemsOffset, 0);
}
static createItemsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startItemsVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addPage(builder:flatbuffers.Builder, page:number) {
builder.addFieldInt32(1, page, 0);
}
static addPageSize(builder:flatbuffers.Builder, pageSize:number) {
builder.addFieldInt32(2, pageSize, 0);
}
static addTotal(builder:flatbuffers.Builder, total:number) {
builder.addFieldInt32(3, total, 0);
}
static endPublicGamesListResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createPublicGamesListResponse(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset, page:number, pageSize:number, total:number):flatbuffers.Offset {
PublicGamesListResponse.startPublicGamesListResponse(builder);
PublicGamesListResponse.addItems(builder, itemsOffset);
PublicGamesListResponse.addPage(builder, page);
PublicGamesListResponse.addPageSize(builder, pageSize);
PublicGamesListResponse.addTotal(builder, total);
return PublicGamesListResponse.endPublicGamesListResponse(builder);
}
unpack(): PublicGamesListResponseT {
return new PublicGamesListResponseT(
this.bb!.createObjList<GameSummary, GameSummaryT>(this.items.bind(this), this.itemsLength()),
this.page(),
this.pageSize(),
this.total()
);
}
unpackTo(_o: PublicGamesListResponseT): void {
_o.items = this.bb!.createObjList<GameSummary, GameSummaryT>(this.items.bind(this), this.itemsLength());
_o.page = this.page();
_o.pageSize = this.pageSize();
_o.total = this.total();
}
}
export class PublicGamesListResponseT implements flatbuffers.IGeneratedObject {
constructor(
public items: (GameSummaryT)[] = [],
public page: number = 0,
public pageSize: number = 0,
public total: number = 0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const items = PublicGamesListResponse.createItemsVector(builder, builder.createObjectOffsetList(this.items));
return PublicGamesListResponse.createPublicGamesListResponse(builder,
items,
this.page,
this.pageSize,
this.total
);
}
}
+23
View File
@@ -0,0 +1,23 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
export { AccountResponse, AccountResponseT } from './user/account-response.js';
export { AccountView, AccountViewT } from './user/account-view.js';
export { ActiveLimit, ActiveLimitT } from './user/active-limit.js';
export { ActiveSanction, ActiveSanctionT } from './user/active-sanction.js';
export { ActorRef, ActorRefT } from './user/actor-ref.js';
export { DeviceSessionRevocationSummaryView, DeviceSessionRevocationSummaryViewT } from './user/device-session-revocation-summary-view.js';
export { DeviceSessionView, DeviceSessionViewT } from './user/device-session-view.js';
export { EntitlementSnapshot, EntitlementSnapshotT } from './user/entitlement-snapshot.js';
export { ErrorBody, ErrorBodyT } from './user/error-body.js';
export { ErrorResponse, ErrorResponseT } from './user/error-response.js';
export { GetMyAccountRequest, GetMyAccountRequestT } from './user/get-my-account-request.js';
export { ListMySessionsRequest, ListMySessionsRequestT } from './user/list-my-sessions-request.js';
export { ListMySessionsResponse, ListMySessionsResponseT } from './user/list-my-sessions-response.js';
export { RevokeAllMySessionsRequest, RevokeAllMySessionsRequestT } from './user/revoke-all-my-sessions-request.js';
export { RevokeAllMySessionsResponse, RevokeAllMySessionsResponseT } from './user/revoke-all-my-sessions-response.js';
export { RevokeMySessionRequest, RevokeMySessionRequestT } from './user/revoke-my-session-request.js';
export { RevokeMySessionResponse, RevokeMySessionResponseT } from './user/revoke-my-session-response.js';
export { UpdateMyProfileRequest, UpdateMyProfileRequestT } from './user/update-my-profile-request.js';
export { UpdateMySettingsRequest, UpdateMySettingsRequestT } from './user/update-my-settings-request.js';
@@ -0,0 +1,85 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { AccountView, AccountViewT } from './account-view.js';
export class AccountResponse implements flatbuffers.IUnpackableObject<AccountResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):AccountResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsAccountResponse(bb:flatbuffers.ByteBuffer, obj?:AccountResponse):AccountResponse {
return (obj || new AccountResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsAccountResponse(bb:flatbuffers.ByteBuffer, obj?:AccountResponse):AccountResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new AccountResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
account(obj?:AccountView):AccountView|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new AccountView()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startAccountResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addAccount(builder:flatbuffers.Builder, accountOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, accountOffset, 0);
}
static endAccountResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static finishAccountResponseBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
builder.finish(offset);
}
static finishSizePrefixedAccountResponseBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
builder.finish(offset, undefined, true);
}
static createAccountResponse(builder:flatbuffers.Builder, accountOffset:flatbuffers.Offset):flatbuffers.Offset {
AccountResponse.startAccountResponse(builder);
AccountResponse.addAccount(builder, accountOffset);
return AccountResponse.endAccountResponse(builder);
}
unpack(): AccountResponseT {
return new AccountResponseT(
(this.account() !== null ? this.account()!.unpack() : null)
);
}
unpackTo(_o: AccountResponseT): void {
_o.account = (this.account() !== null ? this.account()!.unpack() : null);
}
}
export class AccountResponseT implements flatbuffers.IGeneratedObject {
constructor(
public account: AccountViewT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const account = (this.account !== null ? this.account!.pack(builder) : 0);
return AccountResponse.createAccountResponse(builder,
account
);
}
}
@@ -0,0 +1,275 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ActiveLimit, ActiveLimitT } from './active-limit.js';
import { ActiveSanction, ActiveSanctionT } from './active-sanction.js';
import { EntitlementSnapshot, EntitlementSnapshotT } from './entitlement-snapshot.js';
export class AccountView implements flatbuffers.IUnpackableObject<AccountViewT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):AccountView {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsAccountView(bb:flatbuffers.ByteBuffer, obj?:AccountView):AccountView {
return (obj || new AccountView()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsAccountView(bb:flatbuffers.ByteBuffer, obj?:AccountView):AccountView {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new AccountView()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
userId():string|null
userId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
userId(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;
}
email():string|null
email(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
email(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;
}
userName():string|null
userName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
userName(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;
}
displayName():string|null
displayName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
displayName(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
preferredLanguage():string|null
preferredLanguage(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
preferredLanguage(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
timeZone():string|null
timeZone(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
timeZone(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
declaredCountry():string|null
declaredCountry(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
declaredCountry(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
entitlement(obj?:EntitlementSnapshot):EntitlementSnapshot|null {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? (obj || new EntitlementSnapshot()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
activeSanctions(index: number, obj?:ActiveSanction):ActiveSanction|null {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? (obj || new ActiveSanction()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
activeSanctionsLength():number {
const offset = this.bb!.__offset(this.bb_pos, 20);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
activeLimits(index: number, obj?:ActiveLimit):ActiveLimit|null {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? (obj || new ActiveLimit()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
activeLimitsLength():number {
const offset = this.bb!.__offset(this.bb_pos, 22);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
createdAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 24);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
updatedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 26);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startAccountView(builder:flatbuffers.Builder) {
builder.startObject(12);
}
static addUserId(builder:flatbuffers.Builder, userIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, userIdOffset, 0);
}
static addEmail(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, emailOffset, 0);
}
static addUserName(builder:flatbuffers.Builder, userNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, userNameOffset, 0);
}
static addDisplayName(builder:flatbuffers.Builder, displayNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, displayNameOffset, 0);
}
static addPreferredLanguage(builder:flatbuffers.Builder, preferredLanguageOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, preferredLanguageOffset, 0);
}
static addTimeZone(builder:flatbuffers.Builder, timeZoneOffset:flatbuffers.Offset) {
builder.addFieldOffset(5, timeZoneOffset, 0);
}
static addDeclaredCountry(builder:flatbuffers.Builder, declaredCountryOffset:flatbuffers.Offset) {
builder.addFieldOffset(6, declaredCountryOffset, 0);
}
static addEntitlement(builder:flatbuffers.Builder, entitlementOffset:flatbuffers.Offset) {
builder.addFieldOffset(7, entitlementOffset, 0);
}
static addActiveSanctions(builder:flatbuffers.Builder, activeSanctionsOffset:flatbuffers.Offset) {
builder.addFieldOffset(8, activeSanctionsOffset, 0);
}
static createActiveSanctionsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startActiveSanctionsVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addActiveLimits(builder:flatbuffers.Builder, activeLimitsOffset:flatbuffers.Offset) {
builder.addFieldOffset(9, activeLimitsOffset, 0);
}
static createActiveLimitsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startActiveLimitsVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static addCreatedAtMs(builder:flatbuffers.Builder, createdAtMs:bigint) {
builder.addFieldInt64(10, createdAtMs, BigInt('0'));
}
static addUpdatedAtMs(builder:flatbuffers.Builder, updatedAtMs:bigint) {
builder.addFieldInt64(11, updatedAtMs, BigInt('0'));
}
static endAccountView(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
unpack(): AccountViewT {
return new AccountViewT(
this.userId(),
this.email(),
this.userName(),
this.displayName(),
this.preferredLanguage(),
this.timeZone(),
this.declaredCountry(),
(this.entitlement() !== null ? this.entitlement()!.unpack() : null),
this.bb!.createObjList<ActiveSanction, ActiveSanctionT>(this.activeSanctions.bind(this), this.activeSanctionsLength()),
this.bb!.createObjList<ActiveLimit, ActiveLimitT>(this.activeLimits.bind(this), this.activeLimitsLength()),
this.createdAtMs(),
this.updatedAtMs()
);
}
unpackTo(_o: AccountViewT): void {
_o.userId = this.userId();
_o.email = this.email();
_o.userName = this.userName();
_o.displayName = this.displayName();
_o.preferredLanguage = this.preferredLanguage();
_o.timeZone = this.timeZone();
_o.declaredCountry = this.declaredCountry();
_o.entitlement = (this.entitlement() !== null ? this.entitlement()!.unpack() : null);
_o.activeSanctions = this.bb!.createObjList<ActiveSanction, ActiveSanctionT>(this.activeSanctions.bind(this), this.activeSanctionsLength());
_o.activeLimits = this.bb!.createObjList<ActiveLimit, ActiveLimitT>(this.activeLimits.bind(this), this.activeLimitsLength());
_o.createdAtMs = this.createdAtMs();
_o.updatedAtMs = this.updatedAtMs();
}
}
export class AccountViewT implements flatbuffers.IGeneratedObject {
constructor(
public userId: string|Uint8Array|null = null,
public email: string|Uint8Array|null = null,
public userName: string|Uint8Array|null = null,
public displayName: string|Uint8Array|null = null,
public preferredLanguage: string|Uint8Array|null = null,
public timeZone: string|Uint8Array|null = null,
public declaredCountry: string|Uint8Array|null = null,
public entitlement: EntitlementSnapshotT|null = null,
public activeSanctions: (ActiveSanctionT)[] = [],
public activeLimits: (ActiveLimitT)[] = [],
public createdAtMs: bigint = BigInt('0'),
public updatedAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const userId = (this.userId !== null ? builder.createString(this.userId!) : 0);
const email = (this.email !== null ? builder.createString(this.email!) : 0);
const userName = (this.userName !== null ? builder.createString(this.userName!) : 0);
const displayName = (this.displayName !== null ? builder.createString(this.displayName!) : 0);
const preferredLanguage = (this.preferredLanguage !== null ? builder.createString(this.preferredLanguage!) : 0);
const timeZone = (this.timeZone !== null ? builder.createString(this.timeZone!) : 0);
const declaredCountry = (this.declaredCountry !== null ? builder.createString(this.declaredCountry!) : 0);
const entitlement = (this.entitlement !== null ? this.entitlement!.pack(builder) : 0);
const activeSanctions = AccountView.createActiveSanctionsVector(builder, builder.createObjectOffsetList(this.activeSanctions));
const activeLimits = AccountView.createActiveLimitsVector(builder, builder.createObjectOffsetList(this.activeLimits));
AccountView.startAccountView(builder);
AccountView.addUserId(builder, userId);
AccountView.addEmail(builder, email);
AccountView.addUserName(builder, userName);
AccountView.addDisplayName(builder, displayName);
AccountView.addPreferredLanguage(builder, preferredLanguage);
AccountView.addTimeZone(builder, timeZone);
AccountView.addDeclaredCountry(builder, declaredCountry);
AccountView.addEntitlement(builder, entitlement);
AccountView.addActiveSanctions(builder, activeSanctions);
AccountView.addActiveLimits(builder, activeLimits);
AccountView.addCreatedAtMs(builder, this.createdAtMs);
AccountView.addUpdatedAtMs(builder, this.updatedAtMs);
return AccountView.endAccountView(builder);
}
}
@@ -0,0 +1,144 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ActorRef, ActorRefT } from './actor-ref.js';
export class ActiveLimit implements flatbuffers.IUnpackableObject<ActiveLimitT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ActiveLimit {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsActiveLimit(bb:flatbuffers.ByteBuffer, obj?:ActiveLimit):ActiveLimit {
return (obj || new ActiveLimit()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsActiveLimit(bb:flatbuffers.ByteBuffer, obj?:ActiveLimit):ActiveLimit {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ActiveLimit()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
limitCode():string|null
limitCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
limitCode(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;
}
value():bigint {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
reasonCode():string|null
reasonCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
reasonCode(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;
}
actor(obj?:ActorRef):ActorRef|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? (obj || new ActorRef()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
appliedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
expiresAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startActiveLimit(builder:flatbuffers.Builder) {
builder.startObject(6);
}
static addLimitCode(builder:flatbuffers.Builder, limitCodeOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, limitCodeOffset, 0);
}
static addValue(builder:flatbuffers.Builder, value:bigint) {
builder.addFieldInt64(1, value, BigInt('0'));
}
static addReasonCode(builder:flatbuffers.Builder, reasonCodeOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, reasonCodeOffset, 0);
}
static addActor(builder:flatbuffers.Builder, actorOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, actorOffset, 0);
}
static addAppliedAtMs(builder:flatbuffers.Builder, appliedAtMs:bigint) {
builder.addFieldInt64(4, appliedAtMs, BigInt('0'));
}
static addExpiresAtMs(builder:flatbuffers.Builder, expiresAtMs:bigint) {
builder.addFieldInt64(5, expiresAtMs, BigInt('0'));
}
static endActiveLimit(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
unpack(): ActiveLimitT {
return new ActiveLimitT(
this.limitCode(),
this.value(),
this.reasonCode(),
(this.actor() !== null ? this.actor()!.unpack() : null),
this.appliedAtMs(),
this.expiresAtMs()
);
}
unpackTo(_o: ActiveLimitT): void {
_o.limitCode = this.limitCode();
_o.value = this.value();
_o.reasonCode = this.reasonCode();
_o.actor = (this.actor() !== null ? this.actor()!.unpack() : null);
_o.appliedAtMs = this.appliedAtMs();
_o.expiresAtMs = this.expiresAtMs();
}
}
export class ActiveLimitT implements flatbuffers.IGeneratedObject {
constructor(
public limitCode: string|Uint8Array|null = null,
public value: bigint = BigInt('0'),
public reasonCode: string|Uint8Array|null = null,
public actor: ActorRefT|null = null,
public appliedAtMs: bigint = BigInt('0'),
public expiresAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const limitCode = (this.limitCode !== null ? builder.createString(this.limitCode!) : 0);
const reasonCode = (this.reasonCode !== null ? builder.createString(this.reasonCode!) : 0);
const actor = (this.actor !== null ? this.actor!.pack(builder) : 0);
ActiveLimit.startActiveLimit(builder);
ActiveLimit.addLimitCode(builder, limitCode);
ActiveLimit.addValue(builder, this.value);
ActiveLimit.addReasonCode(builder, reasonCode);
ActiveLimit.addActor(builder, actor);
ActiveLimit.addAppliedAtMs(builder, this.appliedAtMs);
ActiveLimit.addExpiresAtMs(builder, this.expiresAtMs);
return ActiveLimit.endActiveLimit(builder);
}
}
@@ -0,0 +1,147 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ActorRef, ActorRefT } from './actor-ref.js';
export class ActiveSanction implements flatbuffers.IUnpackableObject<ActiveSanctionT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ActiveSanction {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsActiveSanction(bb:flatbuffers.ByteBuffer, obj?:ActiveSanction):ActiveSanction {
return (obj || new ActiveSanction()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsActiveSanction(bb:flatbuffers.ByteBuffer, obj?:ActiveSanction):ActiveSanction {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ActiveSanction()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
sanctionCode():string|null
sanctionCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
sanctionCode(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;
}
scope():string|null
scope(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
scope(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;
}
reasonCode():string|null
reasonCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
reasonCode(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;
}
actor(obj?:ActorRef):ActorRef|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? (obj || new ActorRef()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
appliedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
expiresAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startActiveSanction(builder:flatbuffers.Builder) {
builder.startObject(6);
}
static addSanctionCode(builder:flatbuffers.Builder, sanctionCodeOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, sanctionCodeOffset, 0);
}
static addScope(builder:flatbuffers.Builder, scopeOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, scopeOffset, 0);
}
static addReasonCode(builder:flatbuffers.Builder, reasonCodeOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, reasonCodeOffset, 0);
}
static addActor(builder:flatbuffers.Builder, actorOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, actorOffset, 0);
}
static addAppliedAtMs(builder:flatbuffers.Builder, appliedAtMs:bigint) {
builder.addFieldInt64(4, appliedAtMs, BigInt('0'));
}
static addExpiresAtMs(builder:flatbuffers.Builder, expiresAtMs:bigint) {
builder.addFieldInt64(5, expiresAtMs, BigInt('0'));
}
static endActiveSanction(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
unpack(): ActiveSanctionT {
return new ActiveSanctionT(
this.sanctionCode(),
this.scope(),
this.reasonCode(),
(this.actor() !== null ? this.actor()!.unpack() : null),
this.appliedAtMs(),
this.expiresAtMs()
);
}
unpackTo(_o: ActiveSanctionT): void {
_o.sanctionCode = this.sanctionCode();
_o.scope = this.scope();
_o.reasonCode = this.reasonCode();
_o.actor = (this.actor() !== null ? this.actor()!.unpack() : null);
_o.appliedAtMs = this.appliedAtMs();
_o.expiresAtMs = this.expiresAtMs();
}
}
export class ActiveSanctionT implements flatbuffers.IGeneratedObject {
constructor(
public sanctionCode: string|Uint8Array|null = null,
public scope: string|Uint8Array|null = null,
public reasonCode: string|Uint8Array|null = null,
public actor: ActorRefT|null = null,
public appliedAtMs: bigint = BigInt('0'),
public expiresAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const sanctionCode = (this.sanctionCode !== null ? builder.createString(this.sanctionCode!) : 0);
const scope = (this.scope !== null ? builder.createString(this.scope!) : 0);
const reasonCode = (this.reasonCode !== null ? builder.createString(this.reasonCode!) : 0);
const actor = (this.actor !== null ? this.actor!.pack(builder) : 0);
ActiveSanction.startActiveSanction(builder);
ActiveSanction.addSanctionCode(builder, sanctionCode);
ActiveSanction.addScope(builder, scope);
ActiveSanction.addReasonCode(builder, reasonCode);
ActiveSanction.addActor(builder, actor);
ActiveSanction.addAppliedAtMs(builder, this.appliedAtMs);
ActiveSanction.addExpiresAtMs(builder, this.expiresAtMs);
return ActiveSanction.endActiveSanction(builder);
}
}
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ActorRef implements flatbuffers.IUnpackableObject<ActorRefT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ActorRef {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsActorRef(bb:flatbuffers.ByteBuffer, obj?:ActorRef):ActorRef {
return (obj || new ActorRef()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsActorRef(bb:flatbuffers.ByteBuffer, obj?:ActorRef):ActorRef {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ActorRef()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
type():string|null
type(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
type(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;
}
id():string|null
id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
id(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;
}
static startActorRef(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addType(builder:flatbuffers.Builder, typeOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, typeOffset, 0);
}
static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, idOffset, 0);
}
static endActorRef(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createActorRef(builder:flatbuffers.Builder, typeOffset:flatbuffers.Offset, idOffset:flatbuffers.Offset):flatbuffers.Offset {
ActorRef.startActorRef(builder);
ActorRef.addType(builder, typeOffset);
ActorRef.addId(builder, idOffset);
return ActorRef.endActorRef(builder);
}
unpack(): ActorRefT {
return new ActorRefT(
this.type(),
this.id()
);
}
unpackTo(_o: ActorRefT): void {
_o.type = this.type();
_o.id = this.id();
}
}
export class ActorRefT implements flatbuffers.IGeneratedObject {
constructor(
public type: string|Uint8Array|null = null,
public id: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const type = (this.type !== null ? builder.createString(this.type!) : 0);
const id = (this.id !== null ? builder.createString(this.id!) : 0);
return ActorRef.createActorRef(builder,
type,
id
);
}
}
@@ -0,0 +1,92 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class DeviceSessionRevocationSummaryView implements flatbuffers.IUnpackableObject<DeviceSessionRevocationSummaryViewT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):DeviceSessionRevocationSummaryView {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsDeviceSessionRevocationSummaryView(bb:flatbuffers.ByteBuffer, obj?:DeviceSessionRevocationSummaryView):DeviceSessionRevocationSummaryView {
return (obj || new DeviceSessionRevocationSummaryView()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsDeviceSessionRevocationSummaryView(bb:flatbuffers.ByteBuffer, obj?:DeviceSessionRevocationSummaryView):DeviceSessionRevocationSummaryView {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new DeviceSessionRevocationSummaryView()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
userId():string|null
userId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
userId(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;
}
revokedCount():number {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0;
}
static startDeviceSessionRevocationSummaryView(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addUserId(builder:flatbuffers.Builder, userIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, userIdOffset, 0);
}
static addRevokedCount(builder:flatbuffers.Builder, revokedCount:number) {
builder.addFieldInt32(1, revokedCount, 0);
}
static endDeviceSessionRevocationSummaryView(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createDeviceSessionRevocationSummaryView(builder:flatbuffers.Builder, userIdOffset:flatbuffers.Offset, revokedCount:number):flatbuffers.Offset {
DeviceSessionRevocationSummaryView.startDeviceSessionRevocationSummaryView(builder);
DeviceSessionRevocationSummaryView.addUserId(builder, userIdOffset);
DeviceSessionRevocationSummaryView.addRevokedCount(builder, revokedCount);
return DeviceSessionRevocationSummaryView.endDeviceSessionRevocationSummaryView(builder);
}
unpack(): DeviceSessionRevocationSummaryViewT {
return new DeviceSessionRevocationSummaryViewT(
this.userId(),
this.revokedCount()
);
}
unpackTo(_o: DeviceSessionRevocationSummaryViewT): void {
_o.userId = this.userId();
_o.revokedCount = this.revokedCount();
}
}
export class DeviceSessionRevocationSummaryViewT implements flatbuffers.IGeneratedObject {
constructor(
public userId: string|Uint8Array|null = null,
public revokedCount: number = 0
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const userId = (this.userId !== null ? builder.createString(this.userId!) : 0);
return DeviceSessionRevocationSummaryView.createDeviceSessionRevocationSummaryView(builder,
userId,
this.revokedCount
);
}
}
@@ -0,0 +1,171 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class DeviceSessionView implements flatbuffers.IUnpackableObject<DeviceSessionViewT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):DeviceSessionView {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsDeviceSessionView(bb:flatbuffers.ByteBuffer, obj?:DeviceSessionView):DeviceSessionView {
return (obj || new DeviceSessionView()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsDeviceSessionView(bb:flatbuffers.ByteBuffer, obj?:DeviceSessionView):DeviceSessionView {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new DeviceSessionView()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
deviceSessionId():string|null
deviceSessionId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
deviceSessionId(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;
}
userId():string|null
userId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
userId(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;
}
status():string|null
status(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
status(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;
}
clientPublicKey():string|null
clientPublicKey(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
clientPublicKey(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
createdAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
revokedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
lastSeenAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startDeviceSessionView(builder:flatbuffers.Builder) {
builder.startObject(7);
}
static addDeviceSessionId(builder:flatbuffers.Builder, deviceSessionIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, deviceSessionIdOffset, 0);
}
static addUserId(builder:flatbuffers.Builder, userIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, userIdOffset, 0);
}
static addStatus(builder:flatbuffers.Builder, statusOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, statusOffset, 0);
}
static addClientPublicKey(builder:flatbuffers.Builder, clientPublicKeyOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, clientPublicKeyOffset, 0);
}
static addCreatedAtMs(builder:flatbuffers.Builder, createdAtMs:bigint) {
builder.addFieldInt64(4, createdAtMs, BigInt('0'));
}
static addRevokedAtMs(builder:flatbuffers.Builder, revokedAtMs:bigint) {
builder.addFieldInt64(5, revokedAtMs, BigInt('0'));
}
static addLastSeenAtMs(builder:flatbuffers.Builder, lastSeenAtMs:bigint) {
builder.addFieldInt64(6, lastSeenAtMs, BigInt('0'));
}
static endDeviceSessionView(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createDeviceSessionView(builder:flatbuffers.Builder, deviceSessionIdOffset:flatbuffers.Offset, userIdOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset, clientPublicKeyOffset:flatbuffers.Offset, createdAtMs:bigint, revokedAtMs:bigint, lastSeenAtMs:bigint):flatbuffers.Offset {
DeviceSessionView.startDeviceSessionView(builder);
DeviceSessionView.addDeviceSessionId(builder, deviceSessionIdOffset);
DeviceSessionView.addUserId(builder, userIdOffset);
DeviceSessionView.addStatus(builder, statusOffset);
DeviceSessionView.addClientPublicKey(builder, clientPublicKeyOffset);
DeviceSessionView.addCreatedAtMs(builder, createdAtMs);
DeviceSessionView.addRevokedAtMs(builder, revokedAtMs);
DeviceSessionView.addLastSeenAtMs(builder, lastSeenAtMs);
return DeviceSessionView.endDeviceSessionView(builder);
}
unpack(): DeviceSessionViewT {
return new DeviceSessionViewT(
this.deviceSessionId(),
this.userId(),
this.status(),
this.clientPublicKey(),
this.createdAtMs(),
this.revokedAtMs(),
this.lastSeenAtMs()
);
}
unpackTo(_o: DeviceSessionViewT): void {
_o.deviceSessionId = this.deviceSessionId();
_o.userId = this.userId();
_o.status = this.status();
_o.clientPublicKey = this.clientPublicKey();
_o.createdAtMs = this.createdAtMs();
_o.revokedAtMs = this.revokedAtMs();
_o.lastSeenAtMs = this.lastSeenAtMs();
}
}
export class DeviceSessionViewT implements flatbuffers.IGeneratedObject {
constructor(
public deviceSessionId: string|Uint8Array|null = null,
public userId: string|Uint8Array|null = null,
public status: string|Uint8Array|null = null,
public clientPublicKey: string|Uint8Array|null = null,
public createdAtMs: bigint = BigInt('0'),
public revokedAtMs: bigint = BigInt('0'),
public lastSeenAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const deviceSessionId = (this.deviceSessionId !== null ? builder.createString(this.deviceSessionId!) : 0);
const userId = (this.userId !== null ? builder.createString(this.userId!) : 0);
const status = (this.status !== null ? builder.createString(this.status!) : 0);
const clientPublicKey = (this.clientPublicKey !== null ? builder.createString(this.clientPublicKey!) : 0);
return DeviceSessionView.createDeviceSessionView(builder,
deviceSessionId,
userId,
status,
clientPublicKey,
this.createdAtMs,
this.revokedAtMs,
this.lastSeenAtMs
);
}
}
@@ -0,0 +1,173 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ActorRef, ActorRefT } from './actor-ref.js';
export class EntitlementSnapshot implements flatbuffers.IUnpackableObject<EntitlementSnapshotT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):EntitlementSnapshot {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsEntitlementSnapshot(bb:flatbuffers.ByteBuffer, obj?:EntitlementSnapshot):EntitlementSnapshot {
return (obj || new EntitlementSnapshot()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsEntitlementSnapshot(bb:flatbuffers.ByteBuffer, obj?:EntitlementSnapshot):EntitlementSnapshot {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new EntitlementSnapshot()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
planCode():string|null
planCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
planCode(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;
}
isPaid():boolean {
const offset = this.bb!.__offset(this.bb_pos, 6);
return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false;
}
source():string|null
source(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
source(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;
}
actor(obj?:ActorRef):ActorRef|null {
const offset = this.bb!.__offset(this.bb_pos, 10);
return offset ? (obj || new ActorRef()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
reasonCode():string|null
reasonCode(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
reasonCode(optionalEncoding?:any):string|Uint8Array|null {
const offset = this.bb!.__offset(this.bb_pos, 12);
return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null;
}
startsAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 14);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
endsAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 16);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
updatedAtMs():bigint {
const offset = this.bb!.__offset(this.bb_pos, 18);
return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0');
}
static startEntitlementSnapshot(builder:flatbuffers.Builder) {
builder.startObject(8);
}
static addPlanCode(builder:flatbuffers.Builder, planCodeOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, planCodeOffset, 0);
}
static addIsPaid(builder:flatbuffers.Builder, isPaid:boolean) {
builder.addFieldInt8(1, +isPaid, +false);
}
static addSource(builder:flatbuffers.Builder, sourceOffset:flatbuffers.Offset) {
builder.addFieldOffset(2, sourceOffset, 0);
}
static addActor(builder:flatbuffers.Builder, actorOffset:flatbuffers.Offset) {
builder.addFieldOffset(3, actorOffset, 0);
}
static addReasonCode(builder:flatbuffers.Builder, reasonCodeOffset:flatbuffers.Offset) {
builder.addFieldOffset(4, reasonCodeOffset, 0);
}
static addStartsAtMs(builder:flatbuffers.Builder, startsAtMs:bigint) {
builder.addFieldInt64(5, startsAtMs, BigInt('0'));
}
static addEndsAtMs(builder:flatbuffers.Builder, endsAtMs:bigint) {
builder.addFieldInt64(6, endsAtMs, BigInt('0'));
}
static addUpdatedAtMs(builder:flatbuffers.Builder, updatedAtMs:bigint) {
builder.addFieldInt64(7, updatedAtMs, BigInt('0'));
}
static endEntitlementSnapshot(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
unpack(): EntitlementSnapshotT {
return new EntitlementSnapshotT(
this.planCode(),
this.isPaid(),
this.source(),
(this.actor() !== null ? this.actor()!.unpack() : null),
this.reasonCode(),
this.startsAtMs(),
this.endsAtMs(),
this.updatedAtMs()
);
}
unpackTo(_o: EntitlementSnapshotT): void {
_o.planCode = this.planCode();
_o.isPaid = this.isPaid();
_o.source = this.source();
_o.actor = (this.actor() !== null ? this.actor()!.unpack() : null);
_o.reasonCode = this.reasonCode();
_o.startsAtMs = this.startsAtMs();
_o.endsAtMs = this.endsAtMs();
_o.updatedAtMs = this.updatedAtMs();
}
}
export class EntitlementSnapshotT implements flatbuffers.IGeneratedObject {
constructor(
public planCode: string|Uint8Array|null = null,
public isPaid: boolean = false,
public source: string|Uint8Array|null = null,
public actor: ActorRefT|null = null,
public reasonCode: string|Uint8Array|null = null,
public startsAtMs: bigint = BigInt('0'),
public endsAtMs: bigint = BigInt('0'),
public updatedAtMs: bigint = BigInt('0')
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const planCode = (this.planCode !== null ? builder.createString(this.planCode!) : 0);
const source = (this.source !== null ? builder.createString(this.source!) : 0);
const actor = (this.actor !== null ? this.actor!.pack(builder) : 0);
const reasonCode = (this.reasonCode !== null ? builder.createString(this.reasonCode!) : 0);
EntitlementSnapshot.startEntitlementSnapshot(builder);
EntitlementSnapshot.addPlanCode(builder, planCode);
EntitlementSnapshot.addIsPaid(builder, this.isPaid);
EntitlementSnapshot.addSource(builder, source);
EntitlementSnapshot.addActor(builder, actor);
EntitlementSnapshot.addReasonCode(builder, reasonCode);
EntitlementSnapshot.addStartsAtMs(builder, this.startsAtMs);
EntitlementSnapshot.addEndsAtMs(builder, this.endsAtMs);
EntitlementSnapshot.addUpdatedAtMs(builder, this.updatedAtMs);
return EntitlementSnapshot.endEntitlementSnapshot(builder);
}
}
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ErrorBody implements flatbuffers.IUnpackableObject<ErrorBodyT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ErrorBody {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsErrorBody(bb:flatbuffers.ByteBuffer, obj?:ErrorBody):ErrorBody {
return (obj || new ErrorBody()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsErrorBody(bb:flatbuffers.ByteBuffer, obj?:ErrorBody):ErrorBody {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ErrorBody()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
code():string|null
code(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
code(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;
}
message():string|null
message(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
message(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;
}
static startErrorBody(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addCode(builder:flatbuffers.Builder, codeOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, codeOffset, 0);
}
static addMessage(builder:flatbuffers.Builder, messageOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, messageOffset, 0);
}
static endErrorBody(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createErrorBody(builder:flatbuffers.Builder, codeOffset:flatbuffers.Offset, messageOffset:flatbuffers.Offset):flatbuffers.Offset {
ErrorBody.startErrorBody(builder);
ErrorBody.addCode(builder, codeOffset);
ErrorBody.addMessage(builder, messageOffset);
return ErrorBody.endErrorBody(builder);
}
unpack(): ErrorBodyT {
return new ErrorBodyT(
this.code(),
this.message()
);
}
unpackTo(_o: ErrorBodyT): void {
_o.code = this.code();
_o.message = this.message();
}
}
export class ErrorBodyT implements flatbuffers.IGeneratedObject {
constructor(
public code: string|Uint8Array|null = null,
public message: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const code = (this.code !== null ? builder.createString(this.code!) : 0);
const message = (this.message !== null ? builder.createString(this.message!) : 0);
return ErrorBody.createErrorBody(builder,
code,
message
);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { ErrorBody, ErrorBodyT } from './error-body.js';
export class ErrorResponse implements flatbuffers.IUnpackableObject<ErrorResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ErrorResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsErrorResponse(bb:flatbuffers.ByteBuffer, obj?:ErrorResponse):ErrorResponse {
return (obj || new ErrorResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsErrorResponse(bb:flatbuffers.ByteBuffer, obj?:ErrorResponse):ErrorResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ErrorResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
error(obj?:ErrorBody):ErrorBody|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new ErrorBody()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startErrorResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addError(builder:flatbuffers.Builder, errorOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, errorOffset, 0);
}
static endErrorResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createErrorResponse(builder:flatbuffers.Builder, errorOffset:flatbuffers.Offset):flatbuffers.Offset {
ErrorResponse.startErrorResponse(builder);
ErrorResponse.addError(builder, errorOffset);
return ErrorResponse.endErrorResponse(builder);
}
unpack(): ErrorResponseT {
return new ErrorResponseT(
(this.error() !== null ? this.error()!.unpack() : null)
);
}
unpackTo(_o: ErrorResponseT): void {
_o.error = (this.error() !== null ? this.error()!.unpack() : null);
}
}
export class ErrorResponseT implements flatbuffers.IGeneratedObject {
constructor(
public error: ErrorBodyT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const error = (this.error !== null ? this.error!.pack(builder) : 0);
return ErrorResponse.createErrorResponse(builder,
error
);
}
}
@@ -0,0 +1,56 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class GetMyAccountRequest implements flatbuffers.IUnpackableObject<GetMyAccountRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):GetMyAccountRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsGetMyAccountRequest(bb:flatbuffers.ByteBuffer, obj?:GetMyAccountRequest):GetMyAccountRequest {
return (obj || new GetMyAccountRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsGetMyAccountRequest(bb:flatbuffers.ByteBuffer, obj?:GetMyAccountRequest):GetMyAccountRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new GetMyAccountRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static startGetMyAccountRequest(builder:flatbuffers.Builder) {
builder.startObject(0);
}
static endGetMyAccountRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createGetMyAccountRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
GetMyAccountRequest.startGetMyAccountRequest(builder);
return GetMyAccountRequest.endGetMyAccountRequest(builder);
}
unpack(): GetMyAccountRequestT {
return new GetMyAccountRequestT();
}
unpackTo(_o: GetMyAccountRequestT): void {}
}
export class GetMyAccountRequestT implements flatbuffers.IGeneratedObject {
constructor(){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return GetMyAccountRequest.createGetMyAccountRequest(builder);
}
}
@@ -0,0 +1,56 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class ListMySessionsRequest implements flatbuffers.IUnpackableObject<ListMySessionsRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ListMySessionsRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsListMySessionsRequest(bb:flatbuffers.ByteBuffer, obj?:ListMySessionsRequest):ListMySessionsRequest {
return (obj || new ListMySessionsRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsListMySessionsRequest(bb:flatbuffers.ByteBuffer, obj?:ListMySessionsRequest):ListMySessionsRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ListMySessionsRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static startListMySessionsRequest(builder:flatbuffers.Builder) {
builder.startObject(0);
}
static endListMySessionsRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createListMySessionsRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
ListMySessionsRequest.startListMySessionsRequest(builder);
return ListMySessionsRequest.endListMySessionsRequest(builder);
}
unpack(): ListMySessionsRequestT {
return new ListMySessionsRequestT();
}
unpackTo(_o: ListMySessionsRequestT): void {}
}
export class ListMySessionsRequestT implements flatbuffers.IGeneratedObject {
constructor(){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return ListMySessionsRequest.createListMySessionsRequest(builder);
}
}
@@ -0,0 +1,94 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { DeviceSessionView, DeviceSessionViewT } from './device-session-view.js';
export class ListMySessionsResponse implements flatbuffers.IUnpackableObject<ListMySessionsResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):ListMySessionsResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsListMySessionsResponse(bb:flatbuffers.ByteBuffer, obj?:ListMySessionsResponse):ListMySessionsResponse {
return (obj || new ListMySessionsResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsListMySessionsResponse(bb:flatbuffers.ByteBuffer, obj?:ListMySessionsResponse):ListMySessionsResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new ListMySessionsResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
items(index: number, obj?:DeviceSessionView):DeviceSessionView|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new DeviceSessionView()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null;
}
itemsLength():number {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0;
}
static startListMySessionsResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addItems(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, itemsOffset, 0);
}
static createItemsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
builder.startVector(4, data.length, 4);
for (let i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]!);
}
return builder.endVector();
}
static startItemsVector(builder:flatbuffers.Builder, numElems:number) {
builder.startVector(4, numElems, 4);
}
static endListMySessionsResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createListMySessionsResponse(builder:flatbuffers.Builder, itemsOffset:flatbuffers.Offset):flatbuffers.Offset {
ListMySessionsResponse.startListMySessionsResponse(builder);
ListMySessionsResponse.addItems(builder, itemsOffset);
return ListMySessionsResponse.endListMySessionsResponse(builder);
}
unpack(): ListMySessionsResponseT {
return new ListMySessionsResponseT(
this.bb!.createObjList<DeviceSessionView, DeviceSessionViewT>(this.items.bind(this), this.itemsLength())
);
}
unpackTo(_o: ListMySessionsResponseT): void {
_o.items = this.bb!.createObjList<DeviceSessionView, DeviceSessionViewT>(this.items.bind(this), this.itemsLength());
}
}
export class ListMySessionsResponseT implements flatbuffers.IGeneratedObject {
constructor(
public items: (DeviceSessionViewT)[] = []
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const items = ListMySessionsResponse.createItemsVector(builder, builder.createObjectOffsetList(this.items));
return ListMySessionsResponse.createListMySessionsResponse(builder,
items
);
}
}
@@ -0,0 +1,56 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class RevokeAllMySessionsRequest implements flatbuffers.IUnpackableObject<RevokeAllMySessionsRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):RevokeAllMySessionsRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsRevokeAllMySessionsRequest(bb:flatbuffers.ByteBuffer, obj?:RevokeAllMySessionsRequest):RevokeAllMySessionsRequest {
return (obj || new RevokeAllMySessionsRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsRevokeAllMySessionsRequest(bb:flatbuffers.ByteBuffer, obj?:RevokeAllMySessionsRequest):RevokeAllMySessionsRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new RevokeAllMySessionsRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static startRevokeAllMySessionsRequest(builder:flatbuffers.Builder) {
builder.startObject(0);
}
static endRevokeAllMySessionsRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createRevokeAllMySessionsRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
RevokeAllMySessionsRequest.startRevokeAllMySessionsRequest(builder);
return RevokeAllMySessionsRequest.endRevokeAllMySessionsRequest(builder);
}
unpack(): RevokeAllMySessionsRequestT {
return new RevokeAllMySessionsRequestT();
}
unpackTo(_o: RevokeAllMySessionsRequestT): void {}
}
export class RevokeAllMySessionsRequestT implements flatbuffers.IGeneratedObject {
constructor(){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
return RevokeAllMySessionsRequest.createRevokeAllMySessionsRequest(builder);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { DeviceSessionRevocationSummaryView, DeviceSessionRevocationSummaryViewT } from './device-session-revocation-summary-view.js';
export class RevokeAllMySessionsResponse implements flatbuffers.IUnpackableObject<RevokeAllMySessionsResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):RevokeAllMySessionsResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsRevokeAllMySessionsResponse(bb:flatbuffers.ByteBuffer, obj?:RevokeAllMySessionsResponse):RevokeAllMySessionsResponse {
return (obj || new RevokeAllMySessionsResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsRevokeAllMySessionsResponse(bb:flatbuffers.ByteBuffer, obj?:RevokeAllMySessionsResponse):RevokeAllMySessionsResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new RevokeAllMySessionsResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
summary(obj?:DeviceSessionRevocationSummaryView):DeviceSessionRevocationSummaryView|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new DeviceSessionRevocationSummaryView()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startRevokeAllMySessionsResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addSummary(builder:flatbuffers.Builder, summaryOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, summaryOffset, 0);
}
static endRevokeAllMySessionsResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createRevokeAllMySessionsResponse(builder:flatbuffers.Builder, summaryOffset:flatbuffers.Offset):flatbuffers.Offset {
RevokeAllMySessionsResponse.startRevokeAllMySessionsResponse(builder);
RevokeAllMySessionsResponse.addSummary(builder, summaryOffset);
return RevokeAllMySessionsResponse.endRevokeAllMySessionsResponse(builder);
}
unpack(): RevokeAllMySessionsResponseT {
return new RevokeAllMySessionsResponseT(
(this.summary() !== null ? this.summary()!.unpack() : null)
);
}
unpackTo(_o: RevokeAllMySessionsResponseT): void {
_o.summary = (this.summary() !== null ? this.summary()!.unpack() : null);
}
}
export class RevokeAllMySessionsResponseT implements flatbuffers.IGeneratedObject {
constructor(
public summary: DeviceSessionRevocationSummaryViewT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const summary = (this.summary !== null ? this.summary!.pack(builder) : 0);
return RevokeAllMySessionsResponse.createRevokeAllMySessionsResponse(builder,
summary
);
}
}
@@ -0,0 +1,78 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class RevokeMySessionRequest implements flatbuffers.IUnpackableObject<RevokeMySessionRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):RevokeMySessionRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsRevokeMySessionRequest(bb:flatbuffers.ByteBuffer, obj?:RevokeMySessionRequest):RevokeMySessionRequest {
return (obj || new RevokeMySessionRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsRevokeMySessionRequest(bb:flatbuffers.ByteBuffer, obj?:RevokeMySessionRequest):RevokeMySessionRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new RevokeMySessionRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
deviceSessionId():string|null
deviceSessionId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
deviceSessionId(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 startRevokeMySessionRequest(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addDeviceSessionId(builder:flatbuffers.Builder, deviceSessionIdOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, deviceSessionIdOffset, 0);
}
static endRevokeMySessionRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createRevokeMySessionRequest(builder:flatbuffers.Builder, deviceSessionIdOffset:flatbuffers.Offset):flatbuffers.Offset {
RevokeMySessionRequest.startRevokeMySessionRequest(builder);
RevokeMySessionRequest.addDeviceSessionId(builder, deviceSessionIdOffset);
return RevokeMySessionRequest.endRevokeMySessionRequest(builder);
}
unpack(): RevokeMySessionRequestT {
return new RevokeMySessionRequestT(
this.deviceSessionId()
);
}
unpackTo(_o: RevokeMySessionRequestT): void {
_o.deviceSessionId = this.deviceSessionId();
}
}
export class RevokeMySessionRequestT implements flatbuffers.IGeneratedObject {
constructor(
public deviceSessionId: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const deviceSessionId = (this.deviceSessionId !== null ? builder.createString(this.deviceSessionId!) : 0);
return RevokeMySessionRequest.createRevokeMySessionRequest(builder,
deviceSessionId
);
}
}
@@ -0,0 +1,77 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
import { DeviceSessionView, DeviceSessionViewT } from './device-session-view.js';
export class RevokeMySessionResponse implements flatbuffers.IUnpackableObject<RevokeMySessionResponseT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):RevokeMySessionResponse {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsRevokeMySessionResponse(bb:flatbuffers.ByteBuffer, obj?:RevokeMySessionResponse):RevokeMySessionResponse {
return (obj || new RevokeMySessionResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsRevokeMySessionResponse(bb:flatbuffers.ByteBuffer, obj?:RevokeMySessionResponse):RevokeMySessionResponse {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new RevokeMySessionResponse()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
session(obj?:DeviceSessionView):DeviceSessionView|null {
const offset = this.bb!.__offset(this.bb_pos, 4);
return offset ? (obj || new DeviceSessionView()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null;
}
static startRevokeMySessionResponse(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addSession(builder:flatbuffers.Builder, sessionOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, sessionOffset, 0);
}
static endRevokeMySessionResponse(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createRevokeMySessionResponse(builder:flatbuffers.Builder, sessionOffset:flatbuffers.Offset):flatbuffers.Offset {
RevokeMySessionResponse.startRevokeMySessionResponse(builder);
RevokeMySessionResponse.addSession(builder, sessionOffset);
return RevokeMySessionResponse.endRevokeMySessionResponse(builder);
}
unpack(): RevokeMySessionResponseT {
return new RevokeMySessionResponseT(
(this.session() !== null ? this.session()!.unpack() : null)
);
}
unpackTo(_o: RevokeMySessionResponseT): void {
_o.session = (this.session() !== null ? this.session()!.unpack() : null);
}
}
export class RevokeMySessionResponseT implements flatbuffers.IGeneratedObject {
constructor(
public session: DeviceSessionViewT|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const session = (this.session !== null ? this.session!.pack(builder) : 0);
return RevokeMySessionResponse.createRevokeMySessionResponse(builder,
session
);
}
}
@@ -0,0 +1,78 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class UpdateMyProfileRequest implements flatbuffers.IUnpackableObject<UpdateMyProfileRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):UpdateMyProfileRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsUpdateMyProfileRequest(bb:flatbuffers.ByteBuffer, obj?:UpdateMyProfileRequest):UpdateMyProfileRequest {
return (obj || new UpdateMyProfileRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsUpdateMyProfileRequest(bb:flatbuffers.ByteBuffer, obj?:UpdateMyProfileRequest):UpdateMyProfileRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new UpdateMyProfileRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
displayName():string|null
displayName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
displayName(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 startUpdateMyProfileRequest(builder:flatbuffers.Builder) {
builder.startObject(1);
}
static addDisplayName(builder:flatbuffers.Builder, displayNameOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, displayNameOffset, 0);
}
static endUpdateMyProfileRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createUpdateMyProfileRequest(builder:flatbuffers.Builder, displayNameOffset:flatbuffers.Offset):flatbuffers.Offset {
UpdateMyProfileRequest.startUpdateMyProfileRequest(builder);
UpdateMyProfileRequest.addDisplayName(builder, displayNameOffset);
return UpdateMyProfileRequest.endUpdateMyProfileRequest(builder);
}
unpack(): UpdateMyProfileRequestT {
return new UpdateMyProfileRequestT(
this.displayName()
);
}
unpackTo(_o: UpdateMyProfileRequestT): void {
_o.displayName = this.displayName();
}
}
export class UpdateMyProfileRequestT implements flatbuffers.IGeneratedObject {
constructor(
public displayName: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const displayName = (this.displayName !== null ? builder.createString(this.displayName!) : 0);
return UpdateMyProfileRequest.createUpdateMyProfileRequest(builder,
displayName
);
}
}
@@ -0,0 +1,95 @@
// automatically generated by the FlatBuffers compiler, do not modify
/* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
import * as flatbuffers from 'flatbuffers';
export class UpdateMySettingsRequest implements flatbuffers.IUnpackableObject<UpdateMySettingsRequestT> {
bb: flatbuffers.ByteBuffer|null = null;
bb_pos = 0;
__init(i:number, bb:flatbuffers.ByteBuffer):UpdateMySettingsRequest {
this.bb_pos = i;
this.bb = bb;
return this;
}
static getRootAsUpdateMySettingsRequest(bb:flatbuffers.ByteBuffer, obj?:UpdateMySettingsRequest):UpdateMySettingsRequest {
return (obj || new UpdateMySettingsRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
static getSizePrefixedRootAsUpdateMySettingsRequest(bb:flatbuffers.ByteBuffer, obj?:UpdateMySettingsRequest):UpdateMySettingsRequest {
bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH);
return (obj || new UpdateMySettingsRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb);
}
preferredLanguage():string|null
preferredLanguage(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
preferredLanguage(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;
}
timeZone():string|null
timeZone(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
timeZone(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;
}
static startUpdateMySettingsRequest(builder:flatbuffers.Builder) {
builder.startObject(2);
}
static addPreferredLanguage(builder:flatbuffers.Builder, preferredLanguageOffset:flatbuffers.Offset) {
builder.addFieldOffset(0, preferredLanguageOffset, 0);
}
static addTimeZone(builder:flatbuffers.Builder, timeZoneOffset:flatbuffers.Offset) {
builder.addFieldOffset(1, timeZoneOffset, 0);
}
static endUpdateMySettingsRequest(builder:flatbuffers.Builder):flatbuffers.Offset {
const offset = builder.endObject();
return offset;
}
static createUpdateMySettingsRequest(builder:flatbuffers.Builder, preferredLanguageOffset:flatbuffers.Offset, timeZoneOffset:flatbuffers.Offset):flatbuffers.Offset {
UpdateMySettingsRequest.startUpdateMySettingsRequest(builder);
UpdateMySettingsRequest.addPreferredLanguage(builder, preferredLanguageOffset);
UpdateMySettingsRequest.addTimeZone(builder, timeZoneOffset);
return UpdateMySettingsRequest.endUpdateMySettingsRequest(builder);
}
unpack(): UpdateMySettingsRequestT {
return new UpdateMySettingsRequestT(
this.preferredLanguage(),
this.timeZone()
);
}
unpackTo(_o: UpdateMySettingsRequestT): void {
_o.preferredLanguage = this.preferredLanguage();
_o.timeZone = this.timeZone();
}
}
export class UpdateMySettingsRequestT implements flatbuffers.IGeneratedObject {
constructor(
public preferredLanguage: string|Uint8Array|null = null,
public timeZone: string|Uint8Array|null = null
){}
pack(builder:flatbuffers.Builder): flatbuffers.Offset {
const preferredLanguage = (this.preferredLanguage !== null ? builder.createString(this.preferredLanguage!) : 0);
const timeZone = (this.timeZone !== null ? builder.createString(this.timeZone!) : 0);
return UpdateMySettingsRequest.createUpdateMySettingsRequest(builder,
preferredLanguage,
timeZone
);
}
}
+425 -32
View File
@@ -1,45 +1,206 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { onMount } from "svelte";
import { createEdgeGatewayClient } from "../../api/connect";
import { GalaxyClient } from "../../api/galaxy-client";
import {
LobbyError,
listMyApplications,
listMyGames,
listMyInvites,
listPublicGames,
redeemInvite,
declineInvite,
submitApplication,
type ApplicationSummary,
type GameSummary,
type InviteSummary,
} from "../../api/lobby";
import { ByteBuffer } from "flatbuffers";
import { AccountResponse } from "../../proto/galaxy/fbs/user";
import { GATEWAY_BASE_URL, GATEWAY_RESPONSE_PUBLIC_KEY } from "$lib/env";
import { i18n } from "$lib/i18n/index.svelte";
import { i18n, type TranslationKey } from "$lib/i18n/index.svelte";
import { loadCore } from "../../platform/core/index";
import { session } from "$lib/session-store.svelte";
import { Builder } from "flatbuffers";
import { GetMyAccountRequest } from "../../proto/galaxy/fbs/user";
let displayName: string | null = $state(null);
let accountError: string | null = $state(null);
let accountLoading = $state(true);
let configError: string | null = $state(null);
let listsLoading = $state(true);
let lobbyError: string | null = $state(null);
let myGames: GameSummary[] = $state([]);
let invitations: InviteSummary[] = $state([]);
let applications: ApplicationSummary[] = $state([]);
let publicGames: GameSummary[] = $state([]);
let openApplicationFor: string | null = $state(null);
let raceNameInput = $state("");
let raceNameError: string | null = $state(null);
let submittingApplication = $state(false);
let inviteActionInFlight: string | null = $state(null);
let client: GalaxyClient | null = null;
async function logout(): Promise<void> {
await session.signOut("user");
}
async function sha256(payload: Uint8Array): Promise<Uint8Array> {
const digest = await crypto.subtle.digest(
"SHA-256",
payload as BufferSource,
);
const digest = await crypto.subtle.digest("SHA-256", payload as BufferSource);
return new Uint8Array(digest);
}
function describeLobbyError(err: unknown): string {
if (err instanceof LobbyError) {
const key = `lobby.error.${err.code}` as TranslationKey;
const translated = i18n.t(key);
if (translated !== key) {
return translated;
}
return i18n.t("lobby.error.unknown", { message: err.message });
}
return err instanceof Error ? err.message : "request failed";
}
async function refreshAll(): Promise<void> {
if (client === null) return;
listsLoading = true;
lobbyError = null;
try {
const [games, invites, apps, publicPage] = await Promise.all([
listMyGames(client),
listMyInvites(client),
listMyApplications(client),
listPublicGames(client),
]);
myGames = games;
invitations = invites.filter((invite) => invite.status === "pending");
applications = apps;
publicGames = publicPage.items;
} catch (err) {
lobbyError = describeLobbyError(err);
} finally {
listsLoading = false;
}
}
function applicationStatusLabel(status: string): string {
const key = `lobby.application.status.${status}` as TranslationKey;
const translated = i18n.t(key);
if (translated === key) {
return i18n.t("lobby.application.status.unknown", { status });
}
return translated;
}
function openApplicationForm(gameId: string): void {
openApplicationFor = gameId;
raceNameInput = "";
raceNameError = null;
}
function cancelApplicationForm(): void {
openApplicationFor = null;
raceNameInput = "";
raceNameError = null;
}
async function submitApplicationFor(gameId: string): Promise<void> {
if (client === null) return;
const trimmed = raceNameInput.trim();
if (trimmed === "") {
raceNameError = i18n.t("lobby.application.race_name_required");
return;
}
submittingApplication = true;
raceNameError = null;
try {
const result = await submitApplication(client, gameId, trimmed);
applications = [result, ...applications];
openApplicationFor = null;
raceNameInput = "";
} catch (err) {
raceNameError = describeLobbyError(err);
} finally {
submittingApplication = false;
}
}
async function acceptInvite(invite: InviteSummary): Promise<void> {
if (client === null) return;
inviteActionInFlight = invite.inviteId;
try {
await redeemInvite(client, invite.gameId, invite.inviteId);
invitations = invitations.filter((i) => i.inviteId !== invite.inviteId);
myGames = await listMyGames(client);
} catch (err) {
lobbyError = describeLobbyError(err);
} finally {
inviteActionInFlight = null;
}
}
async function rejectInvite(invite: InviteSummary): Promise<void> {
if (client === null) return;
inviteActionInFlight = invite.inviteId;
try {
await declineInvite(client, invite.gameId, invite.inviteId);
invitations = invitations.filter((i) => i.inviteId !== invite.inviteId);
} catch (err) {
lobbyError = describeLobbyError(err);
} finally {
inviteActionInFlight = null;
}
}
async function loadGreeting(c: GalaxyClient): Promise<void> {
const builder = new Builder(32);
GetMyAccountRequest.startGetMyAccountRequest(builder);
builder.finish(GetMyAccountRequest.endGetMyAccountRequest(builder));
const result = await c.executeCommand("user.account.get", builder.asUint8Array());
if (result.resultCode !== "ok") {
return;
}
const response = AccountResponse.getRootAsAccountResponse(
new ByteBuffer(result.payloadBytes),
);
const account = response.account();
if (account === null) {
return;
}
const display = account.displayName();
const userName = account.userName();
displayName = display && display.length > 0 ? display : userName;
}
function gotoCreate(): void {
goto("/lobby/create");
}
function gotoGame(gameId: string): void {
goto(`/games/${gameId}/map`);
}
onMount(async () => {
if (
session.keypair === null ||
session.deviceSessionId === null ||
GATEWAY_RESPONSE_PUBLIC_KEY.length === 0
) {
accountLoading = false;
listsLoading = false;
if (GATEWAY_RESPONSE_PUBLIC_KEY.length === 0) {
accountError =
"VITE_GATEWAY_RESPONSE_PUBLIC_KEY is not configured";
configError = "VITE_GATEWAY_RESPONSE_PUBLIC_KEY is not configured";
}
return;
}
const keypair = session.keypair;
try {
const core = await loadCore();
const client = new GalaxyClient({
client = new GalaxyClient({
core,
edge: createEdgeGatewayClient(GATEWAY_BASE_URL),
signer: (canonical) => keypair.sign(canonical),
@@ -47,52 +208,284 @@
deviceSessionId: session.deviceSessionId,
gatewayResponsePublicKey: GATEWAY_RESPONSE_PUBLIC_KEY,
});
const payload = await client.executeCommand(
"user.account.get",
new TextEncoder().encode("{}"),
);
const decoded = JSON.parse(new TextDecoder().decode(payload)) as {
account?: { display_name?: string; user_name?: string };
};
displayName =
decoded.account?.display_name ?? decoded.account?.user_name ?? null;
loadGreeting(client).catch(() => {});
await refreshAll();
} catch (err) {
accountError = err instanceof Error ? err.message : "request failed";
} finally {
accountLoading = false;
lobbyError = describeLobbyError(err);
listsLoading = false;
}
});
</script>
<main>
<header>
<h1>{i18n.t("lobby.title")}</h1>
<p>
{i18n.t("lobby.device_session_id_label")}:
<code data-testid="device-session-id">{session.deviceSessionId ?? ""}</code>
</p>
{#if accountLoading}
<p>{i18n.t("lobby.account_loading")}</p>
{:else if displayName !== null}
{#if displayName !== null}
<p data-testid="account-greeting">
{i18n.t("lobby.greeting", { name: displayName })}
</p>
{:else if accountError !== null}
<p role="alert" data-testid="account-error">{accountError}</p>
{/if}
<button onclick={logout} data-testid="lobby-logout">
{i18n.t("lobby.logout")}
</button>
</header>
{#if configError !== null}
<p role="alert" data-testid="account-error">{configError}</p>
{:else if lobbyError !== null}
<p role="alert" data-testid="lobby-error">{lobbyError}</p>
{/if}
<section data-testid="lobby-create-section">
<button onclick={gotoCreate} data-testid="lobby-create-button">
{i18n.t("lobby.create_button")}
</button>
</section>
<section data-testid="lobby-my-games-section">
<h2>{i18n.t("lobby.section.my_games")}</h2>
{#if listsLoading}
<p>{i18n.t("lobby.list_loading")}</p>
{:else if myGames.length === 0}
<p data-testid="lobby-my-games-empty">{i18n.t("lobby.my_games.empty")}</p>
{:else}
<ul class="card-list">
{#each myGames as game (game.gameId)}
<li>
<button
class="card"
onclick={() => gotoGame(game.gameId)}
data-testid="lobby-my-game-card"
>
<strong>{game.gameName}</strong>
<span class="meta">{game.status}</span>
<span class="meta">{game.minPlayers}{game.maxPlayers} players</span>
</button>
</li>
{/each}
</ul>
{/if}
</section>
<section data-testid="lobby-invitations-section">
<h2>{i18n.t("lobby.section.invitations")}</h2>
{#if listsLoading}
<p>{i18n.t("lobby.list_loading")}</p>
{:else if invitations.length === 0}
<p data-testid="lobby-invitations-empty">{i18n.t("lobby.invitations.empty")}</p>
{:else}
<ul class="card-list">
{#each invitations as invite (invite.inviteId)}
<li class="card">
<strong>{invite.raceName}</strong>
<span class="meta">{invite.gameId}</span>
<div class="actions">
<button
onclick={() => acceptInvite(invite)}
disabled={inviteActionInFlight === invite.inviteId}
data-testid="lobby-invite-accept"
>
{i18n.t("lobby.invitation.accept")}
</button>
<button
onclick={() => rejectInvite(invite)}
disabled={inviteActionInFlight === invite.inviteId}
data-testid="lobby-invite-decline"
>
{i18n.t("lobby.invitation.decline")}
</button>
</div>
</li>
{/each}
</ul>
{/if}
</section>
<section data-testid="lobby-applications-section">
<h2>{i18n.t("lobby.section.applications")}</h2>
{#if listsLoading}
<p>{i18n.t("lobby.list_loading")}</p>
{:else if applications.length === 0}
<p data-testid="lobby-applications-empty">{i18n.t("lobby.applications.empty")}</p>
{:else}
<ul class="card-list">
{#each applications as app (app.applicationId)}
<li class="card" data-testid="lobby-application-card">
<strong>{app.raceName}</strong>
<span class="meta">{app.gameId}</span>
<span class="status" data-status={app.status}>
{applicationStatusLabel(app.status)}
</span>
</li>
{/each}
</ul>
{/if}
</section>
<section data-testid="lobby-public-games-section">
<h2>{i18n.t("lobby.section.public_games")}</h2>
{#if listsLoading}
<p>{i18n.t("lobby.list_loading")}</p>
{:else if publicGames.length === 0}
<p data-testid="lobby-public-games-empty">{i18n.t("lobby.public_games.empty")}</p>
{:else}
<ul class="card-list">
{#each publicGames as game (game.gameId)}
<li class="card">
<strong>{game.gameName}</strong>
<span class="meta">{game.status}</span>
<span class="meta">{game.minPlayers}{game.maxPlayers} players</span>
{#if openApplicationFor === game.gameId}
<form
onsubmit={(event) => {
event.preventDefault();
submitApplicationFor(game.gameId);
}}
data-testid="lobby-application-form"
>
<label>
{i18n.t("lobby.application.race_name_label")}
<input
type="text"
bind:value={raceNameInput}
data-testid="lobby-application-race-name"
autocomplete="off"
/>
</label>
{#if raceNameError !== null}
<p role="alert" data-testid="lobby-application-error">
{raceNameError}
</p>
{/if}
<div class="actions">
<button
type="submit"
disabled={submittingApplication}
data-testid="lobby-application-submit"
>
{i18n.t("lobby.application.submit")}
</button>
<button
type="button"
onclick={cancelApplicationForm}
data-testid="lobby-application-cancel"
>
{i18n.t("lobby.application.cancel")}
</button>
</div>
</form>
{:else}
<button
onclick={() => openApplicationForm(game.gameId)}
data-testid="lobby-public-game-apply"
>
{i18n.t("lobby.application.submit_for", { name: game.gameName })}
</button>
{/if}
</li>
{/each}
</ul>
{/if}
</section>
</main>
<style>
main {
padding: 2rem;
padding: 1.5rem 1rem;
max-width: 32rem;
margin: 0 auto;
font-family: system-ui, sans-serif;
}
button {
header {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
header h1 {
margin: 0;
}
header button {
align-self: flex-start;
}
section {
margin-bottom: 2rem;
}
section h2 {
font-size: 1.1rem;
margin: 0 0 0.75rem;
}
.card-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.card {
display: flex;
flex-direction: column;
gap: 0.25rem;
padding: 0.75rem;
border: 1px solid #ccc;
border-radius: 0.4rem;
background: #fafafa;
text-align: left;
font: inherit;
cursor: pointer;
width: 100%;
}
li.card {
cursor: default;
}
.meta {
color: #555;
font-size: 0.9rem;
}
.status {
align-self: flex-start;
padding: 0.1rem 0.5rem;
border-radius: 999px;
background: #e7e7e7;
font-size: 0.8rem;
}
.actions {
display: flex;
gap: 0.5rem;
margin-top: 0.25rem;
}
form {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-top: 0.5rem;
}
label {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
input[type="text"] {
font-size: 1rem;
padding: 0.5rem 1rem;
margin-top: 1rem;
padding: 0.4rem 0.5rem;
}
</style>
@@ -0,0 +1,292 @@
<script lang="ts">
import { goto } from "$app/navigation";
import { onMount } from "svelte";
import { createEdgeGatewayClient } from "../../../api/connect";
import { GalaxyClient } from "../../../api/galaxy-client";
import { LobbyError, createGame } from "../../../api/lobby";
import { GATEWAY_BASE_URL, GATEWAY_RESPONSE_PUBLIC_KEY } from "$lib/env";
import { i18n, type TranslationKey } from "$lib/i18n/index.svelte";
import { loadCore } from "../../../platform/core/index";
import { session } from "$lib/session-store.svelte";
const DEFAULT_MIN_PLAYERS = 2;
const DEFAULT_MAX_PLAYERS = 8;
const DEFAULT_START_GAP_HOURS = 24;
const DEFAULT_START_GAP_PLAYERS = 2;
const DEFAULT_TARGET_ENGINE_VERSION = "v1";
let gameName = $state("");
let description = $state("");
let turnSchedule = $state("0 0 * * *");
let enrollmentEndsAt = $state("");
let minPlayers = $state(DEFAULT_MIN_PLAYERS);
let maxPlayers = $state(DEFAULT_MAX_PLAYERS);
let startGapHours = $state(DEFAULT_START_GAP_HOURS);
let startGapPlayers = $state(DEFAULT_START_GAP_PLAYERS);
let targetEngineVersion = $state(DEFAULT_TARGET_ENGINE_VERSION);
let formError: string | null = $state(null);
let configError: string | null = $state(null);
let submitting = $state(false);
let client: GalaxyClient | null = null;
async function sha256(payload: Uint8Array): Promise<Uint8Array> {
const digest = await crypto.subtle.digest("SHA-256", payload as BufferSource);
return new Uint8Array(digest);
}
function describeLobbyError(err: unknown): string {
if (err instanceof LobbyError) {
const key = `lobby.error.${err.code}` as TranslationKey;
const translated = i18n.t(key);
if (translated !== key) {
return translated;
}
return i18n.t("lobby.error.unknown", { message: err.message });
}
return err instanceof Error ? err.message : "request failed";
}
function cancel(): void {
goto("/lobby");
}
async function submit(): Promise<void> {
formError = null;
const trimmedName = gameName.trim();
const trimmedSchedule = turnSchedule.trim();
const trimmedEnrollment = enrollmentEndsAt.trim();
if (trimmedName === "") {
formError = i18n.t("lobby.create.game_name_required");
return;
}
if (trimmedSchedule === "") {
formError = i18n.t("lobby.create.turn_schedule_required");
return;
}
if (trimmedEnrollment === "") {
formError = i18n.t("lobby.create.enrollment_ends_at_required");
return;
}
const enrollmentDate = new Date(trimmedEnrollment);
if (Number.isNaN(enrollmentDate.getTime())) {
formError = i18n.t("lobby.create.enrollment_ends_at_required");
return;
}
if (client === null) {
formError = configError ?? "client not ready";
return;
}
submitting = true;
try {
await createGame(client, {
gameName: trimmedName,
description: description.trim(),
minPlayers,
maxPlayers,
startGapHours,
startGapPlayers,
enrollmentEndsAt: enrollmentDate,
turnSchedule: trimmedSchedule,
targetEngineVersion: targetEngineVersion.trim() || DEFAULT_TARGET_ENGINE_VERSION,
});
goto("/lobby");
} catch (err) {
formError = describeLobbyError(err);
} finally {
submitting = false;
}
}
onMount(async () => {
if (
session.keypair === null ||
session.deviceSessionId === null ||
GATEWAY_RESPONSE_PUBLIC_KEY.length === 0
) {
if (GATEWAY_RESPONSE_PUBLIC_KEY.length === 0) {
configError = "VITE_GATEWAY_RESPONSE_PUBLIC_KEY is not configured";
}
return;
}
const keypair = session.keypair;
const core = await loadCore();
client = new GalaxyClient({
core,
edge: createEdgeGatewayClient(GATEWAY_BASE_URL),
signer: (canonical) => keypair.sign(canonical),
sha256,
deviceSessionId: session.deviceSessionId,
gatewayResponsePublicKey: GATEWAY_RESPONSE_PUBLIC_KEY,
});
});
</script>
<main>
<h1>{i18n.t("lobby.create.title")}</h1>
{#if configError !== null}
<p role="alert" data-testid="lobby-create-config-error">{configError}</p>
{/if}
<form
onsubmit={(event) => {
event.preventDefault();
submit();
}}
data-testid="lobby-create-form"
>
<label>
{i18n.t("lobby.create.game_name_label")}
<input
type="text"
bind:value={gameName}
data-testid="lobby-create-game-name"
autocomplete="off"
/>
</label>
<label>
{i18n.t("lobby.create.description_label")}
<textarea
bind:value={description}
data-testid="lobby-create-description"
rows="3"
></textarea>
</label>
<label>
{i18n.t("lobby.create.turn_schedule_label")}
<input
type="text"
bind:value={turnSchedule}
data-testid="lobby-create-turn-schedule"
autocomplete="off"
/>
<small>{i18n.t("lobby.create.turn_schedule_hint")}</small>
</label>
<label>
{i18n.t("lobby.create.enrollment_ends_at_label")}
<input
type="datetime-local"
bind:value={enrollmentEndsAt}
data-testid="lobby-create-enrollment-ends-at"
/>
</label>
<details data-testid="lobby-create-advanced">
<summary>{i18n.t("lobby.create.advanced")}</summary>
<label>
{i18n.t("lobby.create.min_players_label")}
<input
type="number"
min="1"
bind:value={minPlayers}
data-testid="lobby-create-min-players"
/>
</label>
<label>
{i18n.t("lobby.create.max_players_label")}
<input
type="number"
min="1"
bind:value={maxPlayers}
data-testid="lobby-create-max-players"
/>
</label>
<label>
{i18n.t("lobby.create.start_gap_hours_label")}
<input
type="number"
min="0"
bind:value={startGapHours}
data-testid="lobby-create-start-gap-hours"
/>
</label>
<label>
{i18n.t("lobby.create.start_gap_players_label")}
<input
type="number"
min="0"
bind:value={startGapPlayers}
data-testid="lobby-create-start-gap-players"
/>
</label>
<label>
{i18n.t("lobby.create.target_engine_version_label")}
<input
type="text"
bind:value={targetEngineVersion}
data-testid="lobby-create-target-engine-version"
autocomplete="off"
/>
</label>
</details>
{#if formError !== null}
<p role="alert" data-testid="lobby-create-error">{formError}</p>
{/if}
<div class="actions">
<button type="submit" disabled={submitting} data-testid="lobby-create-submit">
{submitting ? i18n.t("lobby.create.submitting") : i18n.t("lobby.create.submit")}
</button>
<button type="button" onclick={cancel} data-testid="lobby-create-cancel">
{i18n.t("lobby.create.cancel")}
</button>
</div>
</form>
</main>
<style>
main {
padding: 1.5rem 1rem;
max-width: 32rem;
margin: 0 auto;
font-family: system-ui, sans-serif;
}
form {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
label {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
input[type="text"],
input[type="number"],
input[type="datetime-local"],
textarea {
font-size: 1rem;
padding: 0.4rem 0.5rem;
}
details {
border: 1px solid #ddd;
border-radius: 0.4rem;
padding: 0.5rem 0.75rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
details > label {
margin-top: 0.5rem;
}
details summary {
cursor: pointer;
font-weight: 600;
}
.actions {
display: flex;
gap: 0.5rem;
margin-top: 0.5rem;
}
small {
color: #666;
}
</style>
@@ -0,0 +1,2 @@
export const ssr = false;
export const prerender = false;
+37 -7
View File
@@ -16,6 +16,13 @@ import { fromJson, type JsonValue } from "@bufbuild/protobuf";
import { expect, test, type Page } from "@playwright/test";
import { ExecuteCommandRequestSchema } from "../../src/proto/galaxy/gateway/v1/edge_gateway_pb";
import { forgeExecuteCommandResponseJson } from "./fixtures/sign-response";
import {
buildAccountResponsePayload,
buildMyApplicationsListPayload,
buildMyGamesListPayload,
buildMyInvitesListPayload,
buildPublicGamesListPayload,
} from "./fixtures/lobby-fbs";
interface MockSetup {
pendingSubscribes: Array<() => void>;
@@ -58,19 +65,36 @@ async function mockGatewayHappyPath(
ExecuteCommandRequestSchema,
JSON.parse(reqText) as JsonValue,
);
const accountJson = JSON.stringify({
account: {
user_id: "user-1",
let payload: Uint8Array;
switch (req.messageType) {
case "user.account.get":
payload = buildAccountResponsePayload({
userId: "user-1",
email: "pilot@example.com",
user_name: "player-test",
display_name: displayName,
},
userName: "player-test",
displayName,
});
break;
case "lobby.my.games.list":
payload = buildMyGamesListPayload([]);
break;
case "lobby.public.games.list":
payload = buildPublicGamesListPayload([]);
break;
case "lobby.my.invites.list":
payload = buildMyInvitesListPayload([]);
break;
case "lobby.my.applications.list":
payload = buildMyApplicationsListPayload([]);
break;
default:
payload = new Uint8Array();
}
const responseJson = await forgeExecuteCommandResponseJson({
requestId: req.requestId,
timestampMs: BigInt(Date.now()),
resultCode: "ok",
payloadBytes: new TextEncoder().encode(accountJson),
payloadBytes: payload,
});
await route.fulfill({
status: 200,
@@ -122,9 +146,14 @@ async function mockGatewayHappyPath(
async function completeLogin(page: Page): Promise<void> {
await page.goto("/");
await expect(page).toHaveURL(/\/login$/);
// Inputs render `readonly` initially as a Safari autofill-suppression
// workaround; the attribute drops on first focus. Click first so the
// onfocus handler runs before fill checks editability.
await page.getByTestId("login-email-input").click();
await page.getByTestId("login-email-input").fill("pilot@example.com");
await page.getByTestId("login-email-submit").click();
await expect(page.getByTestId("login-code-input")).toBeVisible();
await page.getByTestId("login-code-input").click();
await page.getByTestId("login-code-input").fill("123456");
await page.getByTestId("login-code-submit").click();
await expect(page).toHaveURL(/\/lobby$/);
@@ -213,6 +242,7 @@ test.describe("Phase 7 — auth flow", () => {
"отправить код",
);
await page.getByTestId("login-email-input").click();
await page.getByTestId("login-email-input").fill("pilot@example.com");
await page.getByTestId("login-email-submit").click();
await expect(page.getByTestId("login-code-input")).toBeVisible();
+258
View File
@@ -0,0 +1,258 @@
// Helpers that build FlatBuffers payloads for the lobby Playwright
// suite. Mirrors what `pkg/transcoder/lobby.go` produces in production,
// so the forged response goes through the same TS decoder the lobby
// page uses.
import { Builder } from "flatbuffers";
import {
AccountResponse,
AccountView,
EntitlementSnapshot,
} from "../../../src/proto/galaxy/fbs/user";
import {
ApplicationSubmitResponse,
ApplicationSummary,
GameCreateResponse,
GameSummary,
InviteDeclineResponse,
InviteRedeemResponse,
InviteSummary,
MyApplicationsListResponse,
MyGamesListResponse,
MyInvitesListResponse,
PublicGamesListResponse,
} from "../../../src/proto/galaxy/fbs/lobby";
export interface GameFixture {
gameId: string;
gameName: string;
gameType: string;
status: string;
ownerUserId?: string;
minPlayers?: number;
maxPlayers?: number;
enrollmentEndsAtMs?: bigint;
createdAtMs?: bigint;
updatedAtMs?: bigint;
}
export interface ApplicationFixture {
applicationId: string;
gameId: string;
applicantUserId: string;
raceName: string;
status: string;
createdAtMs?: bigint;
decidedAtMs?: bigint;
}
export interface InviteFixture {
inviteId: string;
gameId: string;
inviterUserId: string;
invitedUserId?: string;
code?: string;
raceName: string;
status: string;
createdAtMs?: bigint;
expiresAtMs?: bigint;
decidedAtMs?: bigint;
}
const DEFAULT_TIME_MS = 1_780_000_000_000n;
function encodeGame(builder: Builder, game: GameFixture): number {
const gameId = builder.createString(game.gameId);
const gameName = builder.createString(game.gameName);
const gameType = builder.createString(game.gameType);
const status = builder.createString(game.status);
const ownerUserId = builder.createString(game.ownerUserId ?? "");
GameSummary.startGameSummary(builder);
GameSummary.addGameId(builder, gameId);
GameSummary.addGameName(builder, gameName);
GameSummary.addGameType(builder, gameType);
GameSummary.addStatus(builder, status);
GameSummary.addOwnerUserId(builder, ownerUserId);
GameSummary.addMinPlayers(builder, game.minPlayers ?? 2);
GameSummary.addMaxPlayers(builder, game.maxPlayers ?? 8);
GameSummary.addEnrollmentEndsAtMs(builder, game.enrollmentEndsAtMs ?? DEFAULT_TIME_MS);
GameSummary.addCreatedAtMs(builder, game.createdAtMs ?? DEFAULT_TIME_MS);
GameSummary.addUpdatedAtMs(builder, game.updatedAtMs ?? DEFAULT_TIME_MS);
return GameSummary.endGameSummary(builder);
}
function encodeApplication(builder: Builder, app: ApplicationFixture): number {
const applicationId = builder.createString(app.applicationId);
const gameId = builder.createString(app.gameId);
const applicantUserId = builder.createString(app.applicantUserId);
const raceName = builder.createString(app.raceName);
const status = builder.createString(app.status);
ApplicationSummary.startApplicationSummary(builder);
ApplicationSummary.addApplicationId(builder, applicationId);
ApplicationSummary.addGameId(builder, gameId);
ApplicationSummary.addApplicantUserId(builder, applicantUserId);
ApplicationSummary.addRaceName(builder, raceName);
ApplicationSummary.addStatus(builder, status);
ApplicationSummary.addCreatedAtMs(builder, app.createdAtMs ?? DEFAULT_TIME_MS);
ApplicationSummary.addDecidedAtMs(builder, app.decidedAtMs ?? 0n);
return ApplicationSummary.endApplicationSummary(builder);
}
function encodeInvite(builder: Builder, invite: InviteFixture): number {
const inviteId = builder.createString(invite.inviteId);
const gameId = builder.createString(invite.gameId);
const inviterUserId = builder.createString(invite.inviterUserId);
const invitedUserId = builder.createString(invite.invitedUserId ?? "");
const code = builder.createString(invite.code ?? "");
const raceName = builder.createString(invite.raceName);
const status = builder.createString(invite.status);
InviteSummary.startInviteSummary(builder);
InviteSummary.addInviteId(builder, inviteId);
InviteSummary.addGameId(builder, gameId);
InviteSummary.addInviterUserId(builder, inviterUserId);
InviteSummary.addInvitedUserId(builder, invitedUserId);
InviteSummary.addCode(builder, code);
InviteSummary.addRaceName(builder, raceName);
InviteSummary.addStatus(builder, status);
InviteSummary.addCreatedAtMs(builder, invite.createdAtMs ?? DEFAULT_TIME_MS);
InviteSummary.addExpiresAtMs(builder, invite.expiresAtMs ?? DEFAULT_TIME_MS);
InviteSummary.addDecidedAtMs(builder, invite.decidedAtMs ?? 0n);
return InviteSummary.endInviteSummary(builder);
}
export function buildMyGamesListPayload(games: GameFixture[]): Uint8Array {
const builder = new Builder(256);
const offsets = games.map((g) => encodeGame(builder, g));
const items = MyGamesListResponse.createItemsVector(builder, offsets);
MyGamesListResponse.startMyGamesListResponse(builder);
MyGamesListResponse.addItems(builder, items);
builder.finish(MyGamesListResponse.endMyGamesListResponse(builder));
return builder.asUint8Array();
}
export function buildPublicGamesListPayload(
games: GameFixture[],
page = 1,
pageSize = 50,
): Uint8Array {
const builder = new Builder(256);
const offsets = games.map((g) => encodeGame(builder, g));
const items = PublicGamesListResponse.createItemsVector(builder, offsets);
PublicGamesListResponse.startPublicGamesListResponse(builder);
PublicGamesListResponse.addItems(builder, items);
PublicGamesListResponse.addPage(builder, page);
PublicGamesListResponse.addPageSize(builder, pageSize);
PublicGamesListResponse.addTotal(builder, games.length);
builder.finish(PublicGamesListResponse.endPublicGamesListResponse(builder));
return builder.asUint8Array();
}
export function buildMyApplicationsListPayload(
applications: ApplicationFixture[],
): Uint8Array {
const builder = new Builder(256);
const offsets = applications.map((a) => encodeApplication(builder, a));
const items = MyApplicationsListResponse.createItemsVector(builder, offsets);
MyApplicationsListResponse.startMyApplicationsListResponse(builder);
MyApplicationsListResponse.addItems(builder, items);
builder.finish(MyApplicationsListResponse.endMyApplicationsListResponse(builder));
return builder.asUint8Array();
}
export function buildMyInvitesListPayload(invites: InviteFixture[]): Uint8Array {
const builder = new Builder(256);
const offsets = invites.map((i) => encodeInvite(builder, i));
const items = MyInvitesListResponse.createItemsVector(builder, offsets);
MyInvitesListResponse.startMyInvitesListResponse(builder);
MyInvitesListResponse.addItems(builder, items);
builder.finish(MyInvitesListResponse.endMyInvitesListResponse(builder));
return builder.asUint8Array();
}
export function buildGameCreateResponsePayload(game: GameFixture): Uint8Array {
const builder = new Builder(256);
const summary = encodeGame(builder, game);
GameCreateResponse.startGameCreateResponse(builder);
GameCreateResponse.addGame(builder, summary);
builder.finish(GameCreateResponse.endGameCreateResponse(builder));
return builder.asUint8Array();
}
export function buildApplicationSubmitResponsePayload(
application: ApplicationFixture,
): Uint8Array {
const builder = new Builder(128);
const app = encodeApplication(builder, application);
ApplicationSubmitResponse.startApplicationSubmitResponse(builder);
ApplicationSubmitResponse.addApplication(builder, app);
builder.finish(ApplicationSubmitResponse.endApplicationSubmitResponse(builder));
return builder.asUint8Array();
}
export function buildInviteRedeemResponsePayload(invite: InviteFixture): Uint8Array {
const builder = new Builder(128);
const summary = encodeInvite(builder, invite);
InviteRedeemResponse.startInviteRedeemResponse(builder);
InviteRedeemResponse.addInvite(builder, summary);
builder.finish(InviteRedeemResponse.endInviteRedeemResponse(builder));
return builder.asUint8Array();
}
export function buildInviteDeclineResponsePayload(invite: InviteFixture): Uint8Array {
const builder = new Builder(128);
const summary = encodeInvite(builder, invite);
InviteDeclineResponse.startInviteDeclineResponse(builder);
InviteDeclineResponse.addInvite(builder, summary);
builder.finish(InviteDeclineResponse.endInviteDeclineResponse(builder));
return builder.asUint8Array();
}
export interface AccountFixture {
userId: string;
email: string;
userName: string;
displayName: string;
}
export function buildAccountResponsePayload(account: AccountFixture): Uint8Array {
const builder = new Builder(256);
const planCode = builder.createString("free");
const source = builder.createString("internal");
const reasonCode = builder.createString("");
EntitlementSnapshot.startEntitlementSnapshot(builder);
EntitlementSnapshot.addPlanCode(builder, planCode);
EntitlementSnapshot.addIsPaid(builder, false);
EntitlementSnapshot.addSource(builder, source);
EntitlementSnapshot.addReasonCode(builder, reasonCode);
EntitlementSnapshot.addStartsAtMs(builder, 0n);
EntitlementSnapshot.addEndsAtMs(builder, 0n);
EntitlementSnapshot.addUpdatedAtMs(builder, 0n);
const entitlement = EntitlementSnapshot.endEntitlementSnapshot(builder);
const userId = builder.createString(account.userId);
const email = builder.createString(account.email);
const userName = builder.createString(account.userName);
const displayName = builder.createString(account.displayName);
const preferredLanguage = builder.createString("en");
const timeZone = builder.createString("UTC");
const declaredCountry = builder.createString("");
AccountView.startAccountView(builder);
AccountView.addUserId(builder, userId);
AccountView.addEmail(builder, email);
AccountView.addUserName(builder, userName);
AccountView.addDisplayName(builder, displayName);
AccountView.addPreferredLanguage(builder, preferredLanguage);
AccountView.addTimeZone(builder, timeZone);
AccountView.addDeclaredCountry(builder, declaredCountry);
AccountView.addEntitlement(builder, entitlement);
AccountView.addCreatedAtMs(builder, 0n);
AccountView.addUpdatedAtMs(builder, 0n);
const view = AccountView.endAccountView(builder);
AccountResponse.startAccountResponse(builder);
AccountResponse.addAccount(builder, view);
builder.finish(AccountResponse.endAccountResponse(builder));
return builder.asUint8Array();
}
+340
View File
@@ -0,0 +1,340 @@
// Phase 8 lobby end-to-end coverage. The gateway is mocked through
// `page.route(...)` like in the Phase 7 spec; this spec dispatches by
// `messageType` so each lobby command can return its own forged
// FlatBuffers payload. The flows under test:
//
// 1) Land on /lobby with empty lists; create a private game; verify
// the new game appears in My Games after the redirect.
// 2) Submit an application to a public game; verify the application
// shows up in My Applications.
// 3) Accept an invitation; verify the invite card disappears.
import { fromJson, type JsonValue } from "@bufbuild/protobuf";
import { expect, test, type Page } from "@playwright/test";
import { ByteBuffer } from "flatbuffers";
import { ExecuteCommandRequestSchema } from "../../src/proto/galaxy/gateway/v1/edge_gateway_pb";
import { GameCreateRequest } from "../../src/proto/galaxy/fbs/lobby";
import { forgeExecuteCommandResponseJson } from "./fixtures/sign-response";
import {
buildAccountResponsePayload,
buildApplicationSubmitResponsePayload,
buildGameCreateResponsePayload,
buildInviteRedeemResponsePayload,
buildMyApplicationsListPayload,
buildMyGamesListPayload,
buildMyInvitesListPayload,
buildPublicGamesListPayload,
type ApplicationFixture,
type GameFixture,
type InviteFixture,
} from "./fixtures/lobby-fbs";
interface LobbyState {
myGames: GameFixture[];
publicGames: GameFixture[];
invitations: InviteFixture[];
applications: ApplicationFixture[];
}
interface LobbyMocks {
state: LobbyState;
pendingSubscribes: Array<() => void>;
createGameCalls: GameFixture[];
applicationSubmitCalls: Array<{ gameId: string; raceName: string }>;
inviteRedeemCalls: Array<{ gameId: string; inviteId: string }>;
}
async function mockGateway(page: Page, initial: Partial<LobbyState> = {}): Promise<LobbyMocks> {
const mocks: LobbyMocks = {
state: {
myGames: initial.myGames ?? [],
publicGames: initial.publicGames ?? [],
invitations: initial.invitations ?? [],
applications: initial.applications ?? [],
},
pendingSubscribes: [],
createGameCalls: [],
applicationSubmitCalls: [],
inviteRedeemCalls: [],
};
await page.route("**/api/v1/public/auth/send-email-code", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ challenge_id: "ch-test-1" }),
});
});
await page.route("**/api/v1/public/auth/confirm-email-code", async (route) => {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ device_session_id: "dev-test-1" }),
});
});
await page.route("**/galaxy.gateway.v1.EdgeGateway/ExecuteCommand", async (route) => {
const reqText = route.request().postData();
if (reqText === null) {
await route.fulfill({ status: 400 });
return;
}
const req = fromJson(
ExecuteCommandRequestSchema,
JSON.parse(reqText) as JsonValue,
);
let resultCode = "ok";
let payload: Uint8Array;
switch (req.messageType) {
case "user.account.get":
payload = buildAccountResponsePayload({
userId: "user-1",
email: "pilot@example.com",
userName: "pilot",
displayName: "Pilot",
});
break;
case "lobby.my.games.list":
payload = buildMyGamesListPayload(mocks.state.myGames);
break;
case "lobby.public.games.list":
payload = buildPublicGamesListPayload(mocks.state.publicGames);
break;
case "lobby.my.invites.list":
payload = buildMyInvitesListPayload(mocks.state.invitations);
break;
case "lobby.my.applications.list":
payload = buildMyApplicationsListPayload(mocks.state.applications);
break;
case "lobby.game.create": {
const decoded = GameCreateRequest.getRootAsGameCreateRequest(
new ByteBuffer(req.payloadBytes),
);
const created: GameFixture = {
gameId: "private-newly-created",
gameName: decoded.gameName() ?? "",
gameType: "private",
status: "draft",
ownerUserId: "user-1",
minPlayers: decoded.minPlayers(),
maxPlayers: decoded.maxPlayers(),
enrollmentEndsAtMs: decoded.enrollmentEndsAtMs(),
createdAtMs: BigInt(Date.now()),
updatedAtMs: BigInt(Date.now()),
};
mocks.createGameCalls.push(created);
mocks.state.myGames = [...mocks.state.myGames, created];
payload = buildGameCreateResponsePayload(created);
break;
}
case "lobby.application.submit": {
const builder = req.payloadBytes;
const submitReq = await import("../../src/proto/galaxy/fbs/lobby");
const decoded = submitReq.ApplicationSubmitRequest.getRootAsApplicationSubmitRequest(
new ByteBuffer(builder),
);
const application: ApplicationFixture = {
applicationId: `app-${mocks.applicationSubmitCalls.length + 1}`,
gameId: decoded.gameId() ?? "",
applicantUserId: "user-1",
raceName: decoded.raceName() ?? "",
status: "pending",
createdAtMs: BigInt(Date.now()),
};
mocks.applicationSubmitCalls.push({
gameId: application.gameId,
raceName: application.raceName,
});
mocks.state.applications = [application, ...mocks.state.applications];
payload = buildApplicationSubmitResponsePayload(application);
break;
}
case "lobby.invite.redeem": {
const redeemMod = await import("../../src/proto/galaxy/fbs/lobby");
const decoded = redeemMod.InviteRedeemRequest.getRootAsInviteRedeemRequest(
new ByteBuffer(req.payloadBytes),
);
const gameId = decoded.gameId() ?? "";
const inviteId = decoded.inviteId() ?? "";
mocks.inviteRedeemCalls.push({ gameId, inviteId });
const original = mocks.state.invitations.find((i) => i.inviteId === inviteId);
const invite: InviteFixture = {
...(original ?? {
inviteId,
gameId,
inviterUserId: "user-host",
invitedUserId: "user-1",
raceName: "",
}),
status: "accepted",
decidedAtMs: BigInt(Date.now()),
};
mocks.state.invitations = mocks.state.invitations.filter(
(i) => i.inviteId !== inviteId,
);
const newGame: GameFixture = {
gameId,
gameName: "Invited Game",
gameType: "private",
status: "enrollment_open",
ownerUserId: "user-host",
minPlayers: 2,
maxPlayers: 8,
enrollmentEndsAtMs: BigInt(Date.now() + 1_000_000),
};
mocks.state.myGames = [...mocks.state.myGames, newGame];
payload = buildInviteRedeemResponsePayload(invite);
break;
}
default:
resultCode = "internal_error";
payload = new Uint8Array();
break;
}
const responseJson = await forgeExecuteCommandResponseJson({
requestId: req.requestId,
timestampMs: BigInt(Date.now()),
resultCode,
payloadBytes: payload,
});
await route.fulfill({
status: 200,
contentType: "application/json",
body: responseJson,
});
});
await page.route(
"**/galaxy.gateway.v1.EdgeGateway/SubscribeEvents",
async (route) => {
const action = await new Promise<"endOfStream" | "abort">((resolve) => {
mocks.pendingSubscribes.push(() => resolve("endOfStream"));
});
if (action === "abort") {
await route.abort();
return;
}
const body = new TextEncoder().encode("{}");
const frame = new Uint8Array(5 + body.length);
frame[0] = 0x02;
new DataView(frame.buffer).setUint32(1, body.length, false);
frame.set(body, 5);
await route.fulfill({
status: 200,
contentType: "application/connect+json",
body: Buffer.from(frame),
});
},
);
return mocks;
}
async function completeLogin(page: Page): Promise<void> {
await page.goto("/");
await expect(page).toHaveURL(/\/login$/);
// The login page renders the inputs `readonly` as a Safari
// autofill-suppression workaround; the readonly attribute is
// dropped on first focus. Playwright's `fill()` checks editability
// before its own focus call, so emulate the user gesture explicitly:
// click the input (focus → readonly drops), then fill.
await page.getByTestId("login-email-input").click();
await page.getByTestId("login-email-input").fill("pilot@example.com");
await page.getByTestId("login-email-submit").click();
await expect(page.getByTestId("login-code-input")).toBeVisible();
await page.getByTestId("login-code-input").click();
await page.getByTestId("login-code-input").fill("123456");
await page.getByTestId("login-code-submit").click();
await expect(page).toHaveURL(/\/lobby$/);
}
test.describe("Phase 8 — lobby flow", () => {
test("create-game flow lands the new game in My Games", async ({ page }) => {
const mocks = await mockGateway(page);
await completeLogin(page);
await expect(page.getByTestId("lobby-my-games-empty")).toBeVisible();
await expect(page.getByTestId("lobby-public-games-empty")).toBeVisible();
await page.getByTestId("lobby-create-button").click();
await expect(page).toHaveURL(/\/lobby\/create$/);
await page.getByTestId("lobby-create-game-name").click();
await page.getByTestId("lobby-create-game-name").fill("First Contact");
await page.getByTestId("lobby-create-turn-schedule").click();
await page.getByTestId("lobby-create-turn-schedule").fill("0 0 * * *");
await page
.getByTestId("lobby-create-enrollment-ends-at")
.fill("2026-06-01T12:00");
await page.getByTestId("lobby-create-submit").click();
await expect(page).toHaveURL(/\/lobby$/);
await expect(page.getByTestId("lobby-my-game-card")).toContainText("First Contact");
expect(mocks.createGameCalls.length).toBe(1);
expect(mocks.createGameCalls[0]!.gameName).toBe("First Contact");
mocks.pendingSubscribes.forEach((resolve) => resolve());
});
test("submitting an application produces a pending applications card", async ({
page,
}) => {
const mocks = await mockGateway(page, {
publicGames: [
{
gameId: "public-1",
gameName: "Open Lobby",
gameType: "public",
status: "enrollment_open",
},
],
});
await completeLogin(page);
await expect(page.getByTestId("lobby-public-game-apply")).toBeVisible();
await page.getByTestId("lobby-public-game-apply").click();
await page
.getByTestId("lobby-application-race-name")
.fill("Vegan Federation");
await page.getByTestId("lobby-application-submit").click();
await expect(page.getByTestId("lobby-application-card")).toBeVisible();
expect(mocks.applicationSubmitCalls).toEqual([
{ gameId: "public-1", raceName: "Vegan Federation" },
]);
mocks.pendingSubscribes.forEach((resolve) => resolve());
});
test("accepting an invitation removes it and adds the game to My Games", async ({
page,
}) => {
const mocks = await mockGateway(page, {
invitations: [
{
inviteId: "invite-1",
gameId: "private-1",
inviterUserId: "user-host",
invitedUserId: "user-1",
raceName: "Vegan Federation",
status: "pending",
},
],
});
await completeLogin(page);
await expect(page.getByTestId("lobby-invite-accept")).toBeVisible();
await page.getByTestId("lobby-invite-accept").click();
await expect(page.getByTestId("lobby-invite-accept")).toBeHidden();
await expect(page.getByTestId("lobby-my-game-card")).toContainText("Invited Game");
expect(mocks.inviteRedeemCalls).toEqual([
{ gameId: "private-1", inviteId: "invite-1" },
]);
mocks.pendingSubscribes.forEach((resolve) => resolve());
});
});
+2 -1
View File
@@ -83,7 +83,8 @@ describe("GalaxyClient.executeCommand", () => {
new TextEncoder().encode("client-payload"),
);
expect(Array.from(out)).toEqual(Array.from(responsePayload));
expect(out.resultCode).toBe("ok");
expect(Array.from(out.payloadBytes)).toEqual(Array.from(responsePayload));
expect(signer).toHaveBeenCalledWith(canonicalBytes);
expect(sha256).toHaveBeenCalledTimes(1);
expect(core.signRequest).toHaveBeenCalledTimes(1);
+335
View File
@@ -0,0 +1,335 @@
// Unit tests for the typed lobby.ts wrappers. They invoke the
// wrappers against a minimal stub of `GalaxyClient.executeCommand`
// that captures the message type and FlatBuffers request payload,
// then returns a forged FlatBuffers response payload built with the
// generated TS bindings. No network, no signing — the test confirms
// the encoder/decoder shape matches the gateway contract and that
// non-`ok` result codes are surfaced as a `LobbyError`.
import { Builder, ByteBuffer } from "flatbuffers";
import { describe, expect, test, vi } from "vitest";
import {
LobbyError,
createGame,
declineInvite,
listMyApplications,
listMyGames,
listMyInvites,
listPublicGames,
redeemInvite,
submitApplication,
} from "../src/api/lobby";
import {
ApplicationSubmitResponse,
ApplicationSummary,
ErrorBody,
ErrorResponse,
GameCreateResponse,
GameSummary,
InviteDeclineResponse,
InviteRedeemResponse,
InviteSummary,
MyApplicationsListResponse,
MyGamesListResponse,
MyInvitesListResponse,
PublicGamesListResponse,
} from "../src/proto/galaxy/fbs/lobby";
import type { GalaxyClient } from "../src/api/galaxy-client";
import {
GameCreateRequest,
PublicGamesListRequest,
ApplicationSubmitRequest,
InviteRedeemRequest,
InviteDeclineRequest,
} from "../src/proto/galaxy/fbs/lobby";
interface Captured {
messageType: string;
payload: Uint8Array;
}
function makeStub(
respondWith: (c: Captured) => { resultCode?: string; payloadBytes: Uint8Array },
): {
client: GalaxyClient;
captured: Captured[];
} {
const captured: Captured[] = [];
const stub = {
executeCommand: vi.fn(async (messageType: string, payload: Uint8Array) => {
const c = { messageType, payload };
captured.push(c);
const result = respondWith(c);
return {
resultCode: result.resultCode ?? "ok",
payloadBytes: result.payloadBytes,
};
}),
} as unknown as GalaxyClient;
return { client: stub, captured };
}
function encodeGameSummary(builder: Builder): number {
const gameId = builder.createString("g-1");
const gameName = builder.createString("Test Game");
const gameType = builder.createString("private");
const status = builder.createString("draft");
const ownerUserId = builder.createString("user-1");
GameSummary.startGameSummary(builder);
GameSummary.addGameId(builder, gameId);
GameSummary.addGameName(builder, gameName);
GameSummary.addGameType(builder, gameType);
GameSummary.addStatus(builder, status);
GameSummary.addOwnerUserId(builder, ownerUserId);
GameSummary.addMinPlayers(builder, 2);
GameSummary.addMaxPlayers(builder, 8);
GameSummary.addEnrollmentEndsAtMs(builder, 1_780_000_000_000n);
GameSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
GameSummary.addUpdatedAtMs(builder, 1_770_000_000_000n);
return GameSummary.endGameSummary(builder);
}
function encodeApplicationSummary(builder: Builder, status: string): number {
const applicationId = builder.createString("app-1");
const gameId = builder.createString("g-1");
const applicantUserId = builder.createString("user-1");
const raceName = builder.createString("Vegan Federation");
const statusOff = builder.createString(status);
ApplicationSummary.startApplicationSummary(builder);
ApplicationSummary.addApplicationId(builder, applicationId);
ApplicationSummary.addGameId(builder, gameId);
ApplicationSummary.addApplicantUserId(builder, applicantUserId);
ApplicationSummary.addRaceName(builder, raceName);
ApplicationSummary.addStatus(builder, statusOff);
ApplicationSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
ApplicationSummary.addDecidedAtMs(builder, status === "pending" ? 0n : 1_770_010_000_000n);
return ApplicationSummary.endApplicationSummary(builder);
}
function encodeInviteSummary(builder: Builder, status: string): number {
const inviteId = builder.createString("invite-1");
const gameId = builder.createString("g-1");
const inviter = builder.createString("user-host");
const invited = builder.createString("user-1");
const code = builder.createString("");
const race = builder.createString("Vegan Federation");
const statusOff = builder.createString(status);
InviteSummary.startInviteSummary(builder);
InviteSummary.addInviteId(builder, inviteId);
InviteSummary.addGameId(builder, gameId);
InviteSummary.addInviterUserId(builder, inviter);
InviteSummary.addInvitedUserId(builder, invited);
InviteSummary.addCode(builder, code);
InviteSummary.addRaceName(builder, race);
InviteSummary.addStatus(builder, statusOff);
InviteSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
InviteSummary.addExpiresAtMs(builder, 1_780_000_000_000n);
InviteSummary.addDecidedAtMs(builder, status === "pending" ? 0n : 1_770_010_000_000n);
return InviteSummary.endInviteSummary(builder);
}
describe("lobby.ts wrappers", () => {
test("listMyGames decodes the response and reports the message type", async () => {
const { client, captured } = makeStub(() => {
const builder = new Builder(256);
const item = encodeGameSummary(builder);
const items = MyGamesListResponse.createItemsVector(builder, [item]);
MyGamesListResponse.startMyGamesListResponse(builder);
MyGamesListResponse.addItems(builder, items);
builder.finish(MyGamesListResponse.endMyGamesListResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const games = await listMyGames(client);
expect(captured[0]!.messageType).toBe("lobby.my.games.list");
expect(games.length).toBe(1);
expect(games[0]!.gameId).toBe("g-1");
expect(games[0]!.minPlayers).toBe(2);
});
test("listPublicGames passes pagination and decodes pageSize/total", async () => {
const { client, captured } = makeStub(() => {
const builder = new Builder(256);
const item = encodeGameSummary(builder);
const items = PublicGamesListResponse.createItemsVector(builder, [item]);
PublicGamesListResponse.startPublicGamesListResponse(builder);
PublicGamesListResponse.addItems(builder, items);
PublicGamesListResponse.addPage(builder, 2);
PublicGamesListResponse.addPageSize(builder, 25);
PublicGamesListResponse.addTotal(builder, 51);
builder.finish(PublicGamesListResponse.endPublicGamesListResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const page = await listPublicGames(client, { page: 2, pageSize: 25 });
expect(captured[0]!.messageType).toBe("lobby.public.games.list");
const decodedRequest = PublicGamesListRequest.getRootAsPublicGamesListRequest(
new ByteBuffer(captured[0]!.payload),
);
expect(decodedRequest.page()).toBe(2);
expect(decodedRequest.pageSize()).toBe(25);
expect(page.items.length).toBe(1);
expect(page.page).toBe(2);
expect(page.pageSize).toBe(25);
expect(page.total).toBe(51);
});
test("listMyApplications decodes pending and decided records", async () => {
const { client } = makeStub(() => {
const builder = new Builder(256);
const pending = encodeApplicationSummary(builder, "pending");
const approved = encodeApplicationSummary(builder, "approved");
const items = MyApplicationsListResponse.createItemsVector(builder, [pending, approved]);
MyApplicationsListResponse.startMyApplicationsListResponse(builder);
MyApplicationsListResponse.addItems(builder, items);
builder.finish(MyApplicationsListResponse.endMyApplicationsListResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const applications = await listMyApplications(client);
expect(applications.length).toBe(2);
expect(applications[0]!.status).toBe("pending");
expect(applications[0]!.decidedAt).toBeNull();
expect(applications[1]!.status).toBe("approved");
expect(applications[1]!.decidedAt).not.toBeNull();
});
test("listMyInvites decodes user-bound invites", async () => {
const { client } = makeStub(() => {
const builder = new Builder(256);
const invite = encodeInviteSummary(builder, "pending");
const items = MyInvitesListResponse.createItemsVector(builder, [invite]);
MyInvitesListResponse.startMyInvitesListResponse(builder);
MyInvitesListResponse.addItems(builder, items);
builder.finish(MyInvitesListResponse.endMyInvitesListResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const invites = await listMyInvites(client);
expect(invites.length).toBe(1);
expect(invites[0]!.invitedUserId).toBe("user-1");
expect(invites[0]!.status).toBe("pending");
expect(invites[0]!.decidedAt).toBeNull();
});
test("createGame encodes every field and decodes the returned summary", async () => {
const { client, captured } = makeStub(() => {
const builder = new Builder(256);
const game = encodeGameSummary(builder);
GameCreateResponse.startGameCreateResponse(builder);
GameCreateResponse.addGame(builder, game);
builder.finish(GameCreateResponse.endGameCreateResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const enrollment = new Date(1_780_000_000_000);
const result = await createGame(client, {
gameName: "First Contact",
description: "",
minPlayers: 2,
maxPlayers: 8,
startGapHours: 24,
startGapPlayers: 2,
enrollmentEndsAt: enrollment,
turnSchedule: "0 0 * * *",
targetEngineVersion: "v1",
});
expect(captured[0]!.messageType).toBe("lobby.game.create");
const request = GameCreateRequest.getRootAsGameCreateRequest(
new ByteBuffer(captured[0]!.payload),
);
expect(request.gameName()).toBe("First Contact");
expect(request.turnSchedule()).toBe("0 0 * * *");
expect(request.targetEngineVersion()).toBe("v1");
expect(request.minPlayers()).toBe(2);
expect(request.maxPlayers()).toBe(8);
expect(request.enrollmentEndsAtMs()).toBe(BigInt(enrollment.getTime()));
expect(result.gameId).toBe("g-1");
});
test("submitApplication encodes game_id and race_name", async () => {
const { client, captured } = makeStub(() => {
const builder = new Builder(128);
const app = encodeApplicationSummary(builder, "pending");
ApplicationSubmitResponse.startApplicationSubmitResponse(builder);
ApplicationSubmitResponse.addApplication(builder, app);
builder.finish(ApplicationSubmitResponse.endApplicationSubmitResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const submitted = await submitApplication(client, "public-1", "Vegan Federation");
expect(captured[0]!.messageType).toBe("lobby.application.submit");
const decoded = ApplicationSubmitRequest.getRootAsApplicationSubmitRequest(
new ByteBuffer(captured[0]!.payload),
);
expect(decoded.gameId()).toBe("public-1");
expect(decoded.raceName()).toBe("Vegan Federation");
expect(submitted.applicationId).toBe("app-1");
});
test("redeemInvite and declineInvite hit their respective message types", async () => {
const stubRedeem = makeStub(() => {
const builder = new Builder(128);
const invite = encodeInviteSummary(builder, "accepted");
InviteRedeemResponse.startInviteRedeemResponse(builder);
InviteRedeemResponse.addInvite(builder, invite);
builder.finish(InviteRedeemResponse.endInviteRedeemResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const redeemed = await redeemInvite(stubRedeem.client, "private-1", "invite-1");
expect(stubRedeem.captured[0]!.messageType).toBe("lobby.invite.redeem");
const redeemReq = InviteRedeemRequest.getRootAsInviteRedeemRequest(
new ByteBuffer(stubRedeem.captured[0]!.payload),
);
expect(redeemReq.gameId()).toBe("private-1");
expect(redeemReq.inviteId()).toBe("invite-1");
expect(redeemed.status).toBe("accepted");
const stubDecline = makeStub(() => {
const builder = new Builder(128);
const invite = encodeInviteSummary(builder, "declined");
InviteDeclineResponse.startInviteDeclineResponse(builder);
InviteDeclineResponse.addInvite(builder, invite);
builder.finish(InviteDeclineResponse.endInviteDeclineResponse(builder));
return { payloadBytes: builder.asUint8Array() };
});
const declined = await declineInvite(stubDecline.client, "private-1", "invite-1");
expect(stubDecline.captured[0]!.messageType).toBe("lobby.invite.decline");
const declineReq = InviteDeclineRequest.getRootAsInviteDeclineRequest(
new ByteBuffer(stubDecline.captured[0]!.payload),
);
expect(declineReq.gameId()).toBe("private-1");
expect(declineReq.inviteId()).toBe("invite-1");
expect(declined.status).toBe("declined");
});
test("non-ok result codes are surfaced as a LobbyError with code and message", async () => {
const { client } = makeStub(() => {
const builder = new Builder(128);
const code = builder.createString("conflict");
const message = builder.createString("game is not in enrollment_open");
ErrorBody.startErrorBody(builder);
ErrorBody.addCode(builder, code);
ErrorBody.addMessage(builder, message);
const errorOff = ErrorBody.endErrorBody(builder);
ErrorResponse.startErrorResponse(builder);
ErrorResponse.addError(builder, errorOff);
builder.finish(ErrorResponse.endErrorResponse(builder));
return { resultCode: "conflict", payloadBytes: builder.asUint8Array() };
});
await expect(submitApplication(client, "public-1", "race")).rejects.toThrow(LobbyError);
try {
await submitApplication(client, "public-1", "race");
} catch (err) {
const lobbyError = err as LobbyError;
expect(lobbyError.code).toBe("conflict");
expect(lobbyError.message).toBe("game is not in enrollment_open");
expect(lobbyError.resultCode).toBe("conflict");
}
});
});
+195
View File
@@ -0,0 +1,195 @@
// Component tests for the create-game form. The lobby API is mocked
// at module level; the GalaxyClient is replaced with a stub that does
// nothing (the test only asserts the createGame wrapper is invoked
// with the right shape).
import "fake-indexeddb/auto";
import { fireEvent, render, waitFor } from "@testing-library/svelte";
import {
afterEach,
beforeEach,
describe,
expect,
test,
vi,
} from "vitest";
import type { IDBPDatabase } from "idb";
import { i18n } from "../src/lib/i18n/index.svelte";
import { session } from "../src/lib/session-store.svelte";
import { type GalaxyDB, openGalaxyDB } from "../src/platform/store/idb";
import { IDBCache } from "../src/platform/store/idb-cache";
import { WebCryptoKeyStore } from "../src/platform/store/webcrypto-keystore";
const gotoSpy = vi.fn<(url: string) => Promise<void>>(async () => {});
vi.mock("$app/navigation", () => ({
goto: (url: string) => gotoSpy(url),
}));
const createGameSpy = vi.fn();
vi.mock("../src/api/lobby", async () => {
const actual = await vi.importActual<typeof import("../src/api/lobby")>(
"../src/api/lobby",
);
return {
...actual,
createGame: (...args: unknown[]) => createGameSpy(...args),
};
});
vi.mock("../src/lib/env", () => ({
GATEWAY_BASE_URL: "http://gateway.test",
GATEWAY_RESPONSE_PUBLIC_KEY: new Uint8Array(32).fill(0x55),
}));
vi.mock("../src/api/connect", () => ({
createEdgeGatewayClient: vi.fn(() => ({})),
}));
vi.mock("../src/api/galaxy-client", () => {
class FakeGalaxyClient {
executeCommand = vi.fn(async () => ({
resultCode: "ok",
payloadBytes: new Uint8Array(),
}));
}
return { GalaxyClient: FakeGalaxyClient };
});
vi.mock("../src/platform/core/index", () => ({
loadCore: async () => ({
signRequest: () => new Uint8Array(),
verifyResponse: () => true,
verifyEvent: () => true,
verifyPayloadHash: () => true,
}),
}));
let db: IDBPDatabase<GalaxyDB>;
let dbName: string;
beforeEach(async () => {
dbName = `galaxy-ui-test-${crypto.randomUUID()}`;
db = await openGalaxyDB(dbName);
const store = {
keyStore: new WebCryptoKeyStore(db),
cache: new IDBCache(db),
};
session.resetForTests();
session.setStoreLoaderForTests(async () => store);
await session.init();
await session.signIn("device-1");
i18n.resetForTests("en");
createGameSpy.mockReset();
gotoSpy.mockReset();
});
afterEach(async () => {
session.resetForTests();
i18n.resetForTests("en");
db.close();
await new Promise<void>((resolve) => {
const req = indexedDB.deleteDatabase(dbName);
req.onsuccess = () => resolve();
req.onerror = () => resolve();
req.onblocked = () => resolve();
});
});
async function importCreatePage(): Promise<typeof import("../src/routes/lobby/create/+page.svelte")> {
return import("../src/routes/lobby/create/+page.svelte");
}
describe("lobby/create page", () => {
test("submitting a valid form invokes createGame with the entered values and navigates back", async () => {
createGameSpy.mockResolvedValue({
gameId: "private-new",
gameName: "First Contact",
gameType: "private",
status: "draft",
ownerUserId: "user-1",
minPlayers: 2,
maxPlayers: 8,
enrollmentEndsAt: new Date(),
createdAt: new Date(),
updatedAt: new Date(),
});
const Page = (await importCreatePage()).default;
const ui = render(Page);
await waitFor(() =>
expect(ui.getByTestId("lobby-create-form")).toBeInTheDocument(),
);
await fireEvent.input(ui.getByTestId("lobby-create-game-name"), {
target: { value: "First Contact" },
});
await fireEvent.input(ui.getByTestId("lobby-create-description"), {
target: { value: "" },
});
await fireEvent.input(ui.getByTestId("lobby-create-turn-schedule"), {
target: { value: "0 0 * * *" },
});
await fireEvent.input(ui.getByTestId("lobby-create-enrollment-ends-at"), {
target: { value: "2026-06-01T12:00" },
});
await fireEvent.click(ui.getByTestId("lobby-create-submit"));
await waitFor(() => {
expect(createGameSpy).toHaveBeenCalledTimes(1);
const call = createGameSpy.mock.calls[0]!;
const input = call[1] as Record<string, unknown>;
expect(input.gameName).toBe("First Contact");
expect(input.turnSchedule).toBe("0 0 * * *");
expect(input.minPlayers).toBe(2);
expect(input.maxPlayers).toBe(8);
expect(input.startGapHours).toBe(24);
expect(input.startGapPlayers).toBe(2);
expect(input.targetEngineVersion).toBe("v1");
expect(input.enrollmentEndsAt).toBeInstanceOf(Date);
expect(gotoSpy).toHaveBeenCalledWith("/lobby");
});
});
test("submitting with an empty game name surfaces a validation error and does not call the API", async () => {
const Page = (await importCreatePage()).default;
const ui = render(Page);
await waitFor(() =>
expect(ui.getByTestId("lobby-create-form")).toBeInTheDocument(),
);
// turn_schedule starts populated with the default; clear game_name to trigger the error
await fireEvent.input(ui.getByTestId("lobby-create-game-name"), {
target: { value: " " },
});
await fireEvent.input(ui.getByTestId("lobby-create-enrollment-ends-at"), {
target: { value: "2026-06-01T12:00" },
});
await fireEvent.click(ui.getByTestId("lobby-create-submit"));
await waitFor(() => {
expect(ui.getByTestId("lobby-create-error")).toHaveTextContent(
"game name must not be empty",
);
expect(createGameSpy).not.toHaveBeenCalled();
});
});
test("cancel button navigates back to /lobby without calling the API", async () => {
const Page = (await importCreatePage()).default;
const ui = render(Page);
await waitFor(() =>
expect(ui.getByTestId("lobby-create-cancel")).toBeInTheDocument(),
);
await fireEvent.click(ui.getByTestId("lobby-create-cancel"));
await waitFor(() => {
expect(gotoSpy).toHaveBeenCalledWith("/lobby");
expect(createGameSpy).not.toHaveBeenCalled();
});
});
});
+494
View File
@@ -0,0 +1,494 @@
// Round-trip tests for the generated TS FlatBuffers bindings under
// `src/proto/galaxy/fbs/lobby/`. These guard against codegen drift —
// if the wire schema and the bindings disagree, the round-trip fails
// instead of letting a broken binding ship silently.
import { Builder, ByteBuffer } from "flatbuffers";
import { describe, expect, test } from "vitest";
import {
ApplicationSubmitRequest,
ApplicationSubmitResponse,
ApplicationSummary,
ErrorBody,
ErrorResponse,
GameCreateRequest,
GameCreateResponse,
GameSummary,
InviteDeclineRequest,
InviteDeclineResponse,
InviteRedeemRequest,
InviteRedeemResponse,
InviteSummary,
MyApplicationsListRequest,
MyApplicationsListResponse,
MyGamesListRequest,
MyGamesListResponse,
MyInvitesListRequest,
MyInvitesListResponse,
OpenEnrollmentRequest,
OpenEnrollmentResponse,
PublicGamesListRequest,
PublicGamesListResponse,
} from "../src/proto/galaxy/fbs/lobby";
interface GameSummaryFixture {
gameId: string;
gameName: string;
gameType: string;
status: string;
ownerUserId: string;
minPlayers: number;
maxPlayers: number;
enrollmentEndsAtMs: bigint;
createdAtMs: bigint;
updatedAtMs: bigint;
}
const PRIVATE_GAME: GameSummaryFixture = {
gameId: "game-private-7c8f",
gameName: "First Contact",
gameType: "private",
status: "draft",
ownerUserId: "user-9912",
minPlayers: 2,
maxPlayers: 8,
enrollmentEndsAtMs: 1_780_000_000_000n,
createdAtMs: 1_770_000_000_000n,
updatedAtMs: 1_770_000_300_000n,
};
const PUBLIC_GAME: GameSummaryFixture = {
gameId: "game-public-aabb",
gameName: "Open Lobby",
gameType: "public",
status: "enrollment_open",
ownerUserId: "",
minPlayers: 4,
maxPlayers: 12,
enrollmentEndsAtMs: 1_780_500_000_000n,
createdAtMs: 1_770_500_000_000n,
updatedAtMs: 1_770_600_000_000n,
};
function encodeGameSummary(builder: Builder, value: GameSummaryFixture): number {
const gameId = builder.createString(value.gameId);
const gameName = builder.createString(value.gameName);
const gameType = builder.createString(value.gameType);
const status = builder.createString(value.status);
const ownerUserId = builder.createString(value.ownerUserId);
GameSummary.startGameSummary(builder);
GameSummary.addGameId(builder, gameId);
GameSummary.addGameName(builder, gameName);
GameSummary.addGameType(builder, gameType);
GameSummary.addStatus(builder, status);
GameSummary.addOwnerUserId(builder, ownerUserId);
GameSummary.addMinPlayers(builder, value.minPlayers);
GameSummary.addMaxPlayers(builder, value.maxPlayers);
GameSummary.addEnrollmentEndsAtMs(builder, value.enrollmentEndsAtMs);
GameSummary.addCreatedAtMs(builder, value.createdAtMs);
GameSummary.addUpdatedAtMs(builder, value.updatedAtMs);
return GameSummary.endGameSummary(builder);
}
function expectGameSummary(actual: GameSummary | null, want: GameSummaryFixture): void {
expect(actual).not.toBeNull();
const got = actual!;
expect(got.gameId()).toBe(want.gameId);
expect(got.gameName()).toBe(want.gameName);
expect(got.gameType()).toBe(want.gameType);
expect(got.status()).toBe(want.status);
expect(got.ownerUserId()).toBe(want.ownerUserId);
expect(got.minPlayers()).toBe(want.minPlayers);
expect(got.maxPlayers()).toBe(want.maxPlayers);
expect(got.enrollmentEndsAtMs()).toBe(want.enrollmentEndsAtMs);
expect(got.createdAtMs()).toBe(want.createdAtMs);
expect(got.updatedAtMs()).toBe(want.updatedAtMs);
}
describe("lobby FlatBuffers TS bindings", () => {
test("MyGamesListRequest round-trips an empty body", () => {
const builder = new Builder(32);
MyGamesListRequest.startMyGamesListRequest(builder);
builder.finish(MyGamesListRequest.endMyGamesListRequest(builder));
const bytes = builder.asUint8Array();
const decoded = MyGamesListRequest.getRootAsMyGamesListRequest(new ByteBuffer(bytes));
expect(decoded).toBeDefined();
});
test("MyGamesListResponse encodes and decodes multiple summaries", () => {
const builder = new Builder(512);
const item0 = encodeGameSummary(builder, PRIVATE_GAME);
const item1 = encodeGameSummary(builder, PUBLIC_GAME);
const items = MyGamesListResponse.createItemsVector(builder, [item0, item1]);
MyGamesListResponse.startMyGamesListResponse(builder);
MyGamesListResponse.addItems(builder, items);
builder.finish(MyGamesListResponse.endMyGamesListResponse(builder));
const bytes = builder.asUint8Array();
const decoded = MyGamesListResponse.getRootAsMyGamesListResponse(new ByteBuffer(bytes));
expect(decoded.itemsLength()).toBe(2);
expectGameSummary(decoded.items(0), PRIVATE_GAME);
expectGameSummary(decoded.items(1), PUBLIC_GAME);
});
test("PublicGamesListResponse preserves pagination metadata", () => {
const builder = new Builder(256);
const item = encodeGameSummary(builder, PUBLIC_GAME);
const items = PublicGamesListResponse.createItemsVector(builder, [item]);
PublicGamesListResponse.startPublicGamesListResponse(builder);
PublicGamesListResponse.addItems(builder, items);
PublicGamesListResponse.addPage(builder, 3);
PublicGamesListResponse.addPageSize(builder, 25);
PublicGamesListResponse.addTotal(builder, 51);
builder.finish(PublicGamesListResponse.endPublicGamesListResponse(builder));
const bytes = builder.asUint8Array();
const decoded = PublicGamesListResponse.getRootAsPublicGamesListResponse(
new ByteBuffer(bytes),
);
expect(decoded.itemsLength()).toBe(1);
expectGameSummary(decoded.items(0), PUBLIC_GAME);
expect(decoded.page()).toBe(3);
expect(decoded.pageSize()).toBe(25);
expect(decoded.total()).toBe(51);
});
test("PublicGamesListRequest round-trips page numbers", () => {
const builder = new Builder(32);
PublicGamesListRequest.startPublicGamesListRequest(builder);
PublicGamesListRequest.addPage(builder, 2);
PublicGamesListRequest.addPageSize(builder, 10);
builder.finish(PublicGamesListRequest.endPublicGamesListRequest(builder));
const decoded = PublicGamesListRequest.getRootAsPublicGamesListRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded.page()).toBe(2);
expect(decoded.pageSize()).toBe(10);
});
test("ApplicationSummary preserves pending and decided records", () => {
const builder = new Builder(256);
const pendingId = builder.createString("app-1");
const pendingGameId = builder.createString("public-1");
const pendingApplicant = builder.createString("user-1");
const pendingRace = builder.createString("Vegan Federation");
const pendingStatus = builder.createString("pending");
ApplicationSummary.startApplicationSummary(builder);
ApplicationSummary.addApplicationId(builder, pendingId);
ApplicationSummary.addGameId(builder, pendingGameId);
ApplicationSummary.addApplicantUserId(builder, pendingApplicant);
ApplicationSummary.addRaceName(builder, pendingRace);
ApplicationSummary.addStatus(builder, pendingStatus);
ApplicationSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
ApplicationSummary.addDecidedAtMs(builder, 0n);
const pending = ApplicationSummary.endApplicationSummary(builder);
const approvedId = builder.createString("app-2");
const approvedGameId = builder.createString("public-2");
const approvedApplicant = builder.createString("user-1");
const approvedRace = builder.createString("Lithic Compact");
const approvedStatus = builder.createString("approved");
ApplicationSummary.startApplicationSummary(builder);
ApplicationSummary.addApplicationId(builder, approvedId);
ApplicationSummary.addGameId(builder, approvedGameId);
ApplicationSummary.addApplicantUserId(builder, approvedApplicant);
ApplicationSummary.addRaceName(builder, approvedRace);
ApplicationSummary.addStatus(builder, approvedStatus);
ApplicationSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
ApplicationSummary.addDecidedAtMs(builder, 1_770_010_000_000n);
const approved = ApplicationSummary.endApplicationSummary(builder);
const items = MyApplicationsListResponse.createItemsVector(builder, [pending, approved]);
MyApplicationsListResponse.startMyApplicationsListResponse(builder);
MyApplicationsListResponse.addItems(builder, items);
builder.finish(MyApplicationsListResponse.endMyApplicationsListResponse(builder));
const decoded = MyApplicationsListResponse.getRootAsMyApplicationsListResponse(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded.itemsLength()).toBe(2);
const first = decoded.items(0)!;
expect(first.status()).toBe("pending");
expect(first.decidedAtMs()).toBe(0n);
const second = decoded.items(1)!;
expect(second.status()).toBe("approved");
expect(second.decidedAtMs()).toBe(1_770_010_000_000n);
});
test("MyApplicationsListRequest round-trips an empty body", () => {
const builder = new Builder(32);
MyApplicationsListRequest.startMyApplicationsListRequest(builder);
builder.finish(MyApplicationsListRequest.endMyApplicationsListRequest(builder));
const decoded = MyApplicationsListRequest.getRootAsMyApplicationsListRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded).toBeDefined();
});
test("InviteSummary preserves invited_user_id and code fields", () => {
const builder = new Builder(256);
const userBoundId = builder.createString("invite-user-bound");
const userBoundGame = builder.createString("private-1");
const userBoundInviter = builder.createString("user-host");
const userBoundInvited = builder.createString("user-1");
const userBoundCode = builder.createString("");
const userBoundRace = builder.createString("Vegan Federation");
const userBoundStatus = builder.createString("pending");
InviteSummary.startInviteSummary(builder);
InviteSummary.addInviteId(builder, userBoundId);
InviteSummary.addGameId(builder, userBoundGame);
InviteSummary.addInviterUserId(builder, userBoundInviter);
InviteSummary.addInvitedUserId(builder, userBoundInvited);
InviteSummary.addCode(builder, userBoundCode);
InviteSummary.addRaceName(builder, userBoundRace);
InviteSummary.addStatus(builder, userBoundStatus);
InviteSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
InviteSummary.addExpiresAtMs(builder, 1_780_000_000_000n);
InviteSummary.addDecidedAtMs(builder, 0n);
const userBound = InviteSummary.endInviteSummary(builder);
const codeBasedId = builder.createString("invite-code-based");
const codeBasedGame = builder.createString("private-2");
const codeBasedInviter = builder.createString("user-host");
const codeBasedInvited = builder.createString("");
const codeBasedCode = builder.createString("ABCDEF12");
const codeBasedRace = builder.createString("Lithic Compact");
const codeBasedStatus = builder.createString("pending");
InviteSummary.startInviteSummary(builder);
InviteSummary.addInviteId(builder, codeBasedId);
InviteSummary.addGameId(builder, codeBasedGame);
InviteSummary.addInviterUserId(builder, codeBasedInviter);
InviteSummary.addInvitedUserId(builder, codeBasedInvited);
InviteSummary.addCode(builder, codeBasedCode);
InviteSummary.addRaceName(builder, codeBasedRace);
InviteSummary.addStatus(builder, codeBasedStatus);
InviteSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
InviteSummary.addExpiresAtMs(builder, 1_780_000_000_000n);
InviteSummary.addDecidedAtMs(builder, 0n);
const codeBased = InviteSummary.endInviteSummary(builder);
const items = MyInvitesListResponse.createItemsVector(builder, [userBound, codeBased]);
MyInvitesListResponse.startMyInvitesListResponse(builder);
MyInvitesListResponse.addItems(builder, items);
builder.finish(MyInvitesListResponse.endMyInvitesListResponse(builder));
const decoded = MyInvitesListResponse.getRootAsMyInvitesListResponse(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded.itemsLength()).toBe(2);
const first = decoded.items(0)!;
expect(first.invitedUserId()).toBe("user-1");
expect(first.code()).toBe("");
const second = decoded.items(1)!;
expect(second.invitedUserId()).toBe("");
expect(second.code()).toBe("ABCDEF12");
});
test("MyInvitesListRequest round-trips an empty body", () => {
const builder = new Builder(32);
MyInvitesListRequest.startMyInvitesListRequest(builder);
builder.finish(MyInvitesListRequest.endMyInvitesListRequest(builder));
const decoded = MyInvitesListRequest.getRootAsMyInvitesListRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded).toBeDefined();
});
test("OpenEnrollmentRequest and Response round-trip", () => {
const builder = new Builder(64);
const gameId = builder.createString("game-private-7c8f");
OpenEnrollmentRequest.startOpenEnrollmentRequest(builder);
OpenEnrollmentRequest.addGameId(builder, gameId);
builder.finish(OpenEnrollmentRequest.endOpenEnrollmentRequest(builder));
const reqDecoded = OpenEnrollmentRequest.getRootAsOpenEnrollmentRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(reqDecoded.gameId()).toBe("game-private-7c8f");
const respBuilder = new Builder(64);
const respGameId = respBuilder.createString("game-private-7c8f");
const status = respBuilder.createString("enrollment_open");
OpenEnrollmentResponse.startOpenEnrollmentResponse(respBuilder);
OpenEnrollmentResponse.addGameId(respBuilder, respGameId);
OpenEnrollmentResponse.addStatus(respBuilder, status);
respBuilder.finish(OpenEnrollmentResponse.endOpenEnrollmentResponse(respBuilder));
const respDecoded = OpenEnrollmentResponse.getRootAsOpenEnrollmentResponse(
new ByteBuffer(respBuilder.asUint8Array()),
);
expect(respDecoded.gameId()).toBe("game-private-7c8f");
expect(respDecoded.status()).toBe("enrollment_open");
});
test("GameCreateRequest and Response round-trip", () => {
const builder = new Builder(256);
const name = builder.createString("First Contact");
const description = builder.createString("");
const turnSchedule = builder.createString("0 0 * * *");
const targetVersion = builder.createString("v1");
GameCreateRequest.startGameCreateRequest(builder);
GameCreateRequest.addGameName(builder, name);
GameCreateRequest.addDescription(builder, description);
GameCreateRequest.addMinPlayers(builder, 2);
GameCreateRequest.addMaxPlayers(builder, 8);
GameCreateRequest.addStartGapHours(builder, 24);
GameCreateRequest.addStartGapPlayers(builder, 2);
GameCreateRequest.addEnrollmentEndsAtMs(builder, 1_780_000_000_000n);
GameCreateRequest.addTurnSchedule(builder, turnSchedule);
GameCreateRequest.addTargetEngineVersion(builder, targetVersion);
builder.finish(GameCreateRequest.endGameCreateRequest(builder));
const reqDecoded = GameCreateRequest.getRootAsGameCreateRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(reqDecoded.gameName()).toBe("First Contact");
expect(reqDecoded.minPlayers()).toBe(2);
expect(reqDecoded.maxPlayers()).toBe(8);
expect(reqDecoded.turnSchedule()).toBe("0 0 * * *");
expect(reqDecoded.targetEngineVersion()).toBe("v1");
expect(reqDecoded.enrollmentEndsAtMs()).toBe(1_780_000_000_000n);
const respBuilder = new Builder(256);
const game = encodeGameSummary(respBuilder, PRIVATE_GAME);
GameCreateResponse.startGameCreateResponse(respBuilder);
GameCreateResponse.addGame(respBuilder, game);
respBuilder.finish(GameCreateResponse.endGameCreateResponse(respBuilder));
const respDecoded = GameCreateResponse.getRootAsGameCreateResponse(
new ByteBuffer(respBuilder.asUint8Array()),
);
expectGameSummary(respDecoded.game(), PRIVATE_GAME);
});
test("ApplicationSubmitRequest and Response round-trip", () => {
const builder = new Builder(128);
const gameId = builder.createString("public-1");
const raceName = builder.createString("Vegan Federation");
ApplicationSubmitRequest.startApplicationSubmitRequest(builder);
ApplicationSubmitRequest.addGameId(builder, gameId);
ApplicationSubmitRequest.addRaceName(builder, raceName);
builder.finish(ApplicationSubmitRequest.endApplicationSubmitRequest(builder));
const reqDecoded = ApplicationSubmitRequest.getRootAsApplicationSubmitRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(reqDecoded.gameId()).toBe("public-1");
expect(reqDecoded.raceName()).toBe("Vegan Federation");
const respBuilder = new Builder(128);
const appId = respBuilder.createString("app-3");
const appGameId = respBuilder.createString("public-1");
const applicant = respBuilder.createString("user-1");
const race = respBuilder.createString("Vegan Federation");
const status = respBuilder.createString("pending");
ApplicationSummary.startApplicationSummary(respBuilder);
ApplicationSummary.addApplicationId(respBuilder, appId);
ApplicationSummary.addGameId(respBuilder, appGameId);
ApplicationSummary.addApplicantUserId(respBuilder, applicant);
ApplicationSummary.addRaceName(respBuilder, race);
ApplicationSummary.addStatus(respBuilder, status);
ApplicationSummary.addCreatedAtMs(respBuilder, 1_770_000_000_000n);
ApplicationSummary.addDecidedAtMs(respBuilder, 0n);
const app = ApplicationSummary.endApplicationSummary(respBuilder);
ApplicationSubmitResponse.startApplicationSubmitResponse(respBuilder);
ApplicationSubmitResponse.addApplication(respBuilder, app);
respBuilder.finish(ApplicationSubmitResponse.endApplicationSubmitResponse(respBuilder));
const respDecoded = ApplicationSubmitResponse.getRootAsApplicationSubmitResponse(
new ByteBuffer(respBuilder.asUint8Array()),
);
const application = respDecoded.application();
expect(application).not.toBeNull();
expect(application!.applicationId()).toBe("app-3");
expect(application!.status()).toBe("pending");
});
test("InviteRedeem and InviteDecline requests round-trip", () => {
for (const ctor of [InviteRedeemRequest, InviteDeclineRequest] as const) {
const builder = new Builder(128);
const gameId = builder.createString("private-1");
const inviteId = builder.createString("invite-1");
if (ctor === InviteRedeemRequest) {
InviteRedeemRequest.startInviteRedeemRequest(builder);
InviteRedeemRequest.addGameId(builder, gameId);
InviteRedeemRequest.addInviteId(builder, inviteId);
builder.finish(InviteRedeemRequest.endInviteRedeemRequest(builder));
const decoded = InviteRedeemRequest.getRootAsInviteRedeemRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded.gameId()).toBe("private-1");
expect(decoded.inviteId()).toBe("invite-1");
} else {
InviteDeclineRequest.startInviteDeclineRequest(builder);
InviteDeclineRequest.addGameId(builder, gameId);
InviteDeclineRequest.addInviteId(builder, inviteId);
builder.finish(InviteDeclineRequest.endInviteDeclineRequest(builder));
const decoded = InviteDeclineRequest.getRootAsInviteDeclineRequest(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded.gameId()).toBe("private-1");
expect(decoded.inviteId()).toBe("invite-1");
}
}
});
test("InviteRedeemResponse and InviteDeclineResponse carry an InviteSummary", () => {
for (const status of ["accepted", "declined"]) {
const builder = new Builder(128);
const inviteId = builder.createString("invite-1");
const gameId = builder.createString("private-1");
const inviter = builder.createString("user-host");
const invited = builder.createString("user-1");
const code = builder.createString("");
const race = builder.createString("Vegan Federation");
const statusStr = builder.createString(status);
InviteSummary.startInviteSummary(builder);
InviteSummary.addInviteId(builder, inviteId);
InviteSummary.addGameId(builder, gameId);
InviteSummary.addInviterUserId(builder, inviter);
InviteSummary.addInvitedUserId(builder, invited);
InviteSummary.addCode(builder, code);
InviteSummary.addRaceName(builder, race);
InviteSummary.addStatus(builder, statusStr);
InviteSummary.addCreatedAtMs(builder, 1_770_000_000_000n);
InviteSummary.addExpiresAtMs(builder, 1_780_000_000_000n);
InviteSummary.addDecidedAtMs(builder, 1_770_010_000_000n);
const summary = InviteSummary.endInviteSummary(builder);
if (status === "accepted") {
InviteRedeemResponse.startInviteRedeemResponse(builder);
InviteRedeemResponse.addInvite(builder, summary);
builder.finish(InviteRedeemResponse.endInviteRedeemResponse(builder));
const decoded = InviteRedeemResponse.getRootAsInviteRedeemResponse(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded.invite()?.status()).toBe("accepted");
} else {
InviteDeclineResponse.startInviteDeclineResponse(builder);
InviteDeclineResponse.addInvite(builder, summary);
builder.finish(InviteDeclineResponse.endInviteDeclineResponse(builder));
const decoded = InviteDeclineResponse.getRootAsInviteDeclineResponse(
new ByteBuffer(builder.asUint8Array()),
);
expect(decoded.invite()?.status()).toBe("declined");
}
}
});
test("ErrorResponse round-trips a code/message pair", () => {
const builder = new Builder(128);
const code = builder.createString("conflict");
const message = builder.createString("request conflicts with current state");
ErrorBody.startErrorBody(builder);
ErrorBody.addCode(builder, code);
ErrorBody.addMessage(builder, message);
const errorOff = ErrorBody.endErrorBody(builder);
ErrorResponse.startErrorResponse(builder);
ErrorResponse.addError(builder, errorOff);
builder.finish(ErrorResponse.endErrorResponse(builder));
const decoded = ErrorResponse.getRootAsErrorResponse(
new ByteBuffer(builder.asUint8Array()),
);
const error = decoded.error();
expect(error).not.toBeNull();
expect(error!.code()).toBe("conflict");
expect(error!.message()).toBe("request conflicts with current state");
});
});
+361
View File
@@ -0,0 +1,361 @@
// Component tests for the Phase 8 lobby page. The lobby API and the
// gateway client are mocked at module level; the session singleton is
// wired to a per-test `SessionStore`-backing IndexedDB so the page's
// boot path settles on `authenticated` and constructs a real
// GalaxyClient (which is then never called because the lobby API
// wrappers are stubs). The tests assert the section rendering, the
// inline race-name form for public games, and the invitation Accept
// flow.
import "fake-indexeddb/auto";
import { fireEvent, render, waitFor } from "@testing-library/svelte";
import {
afterEach,
beforeEach,
describe,
expect,
test,
vi,
} from "vitest";
import type { IDBPDatabase } from "idb";
import { i18n } from "../src/lib/i18n/index.svelte";
import { session } from "../src/lib/session-store.svelte";
import { type GalaxyDB, openGalaxyDB } from "../src/platform/store/idb";
import { IDBCache } from "../src/platform/store/idb-cache";
import { WebCryptoKeyStore } from "../src/platform/store/webcrypto-keystore";
vi.mock("$app/navigation", () => ({
goto: vi.fn(async () => {}),
}));
const listMyGamesSpy = vi.fn();
const listPublicGamesSpy = vi.fn();
const listMyInvitesSpy = vi.fn();
const listMyApplicationsSpy = vi.fn();
const submitApplicationSpy = vi.fn();
const redeemInviteSpy = vi.fn();
const declineInviteSpy = vi.fn();
vi.mock("../src/api/lobby", async () => {
const actual = await vi.importActual<typeof import("../src/api/lobby")>(
"../src/api/lobby",
);
return {
...actual,
listMyGames: (...args: unknown[]) => listMyGamesSpy(...args),
listPublicGames: (...args: unknown[]) => listPublicGamesSpy(...args),
listMyInvites: (...args: unknown[]) => listMyInvitesSpy(...args),
listMyApplications: (...args: unknown[]) => listMyApplicationsSpy(...args),
submitApplication: (...args: unknown[]) => submitApplicationSpy(...args),
redeemInvite: (...args: unknown[]) => redeemInviteSpy(...args),
declineInvite: (...args: unknown[]) => declineInviteSpy(...args),
};
});
vi.mock("../src/lib/env", () => ({
GATEWAY_BASE_URL: "http://gateway.test",
GATEWAY_RESPONSE_PUBLIC_KEY: new Uint8Array(32).fill(0x55),
}));
vi.mock("../src/api/connect", () => ({
createEdgeGatewayClient: vi.fn(() => ({})),
}));
vi.mock("../src/api/galaxy-client", () => {
class FakeGalaxyClient {
executeCommand = vi.fn(async () => ({
resultCode: "ok",
payloadBytes: new Uint8Array(),
}));
}
return { GalaxyClient: FakeGalaxyClient };
});
vi.mock("../src/platform/core/index", () => ({
loadCore: async () => ({
signRequest: () => new Uint8Array(),
verifyResponse: () => true,
verifyEvent: () => true,
verifyPayloadHash: () => true,
}),
}));
let db: IDBPDatabase<GalaxyDB>;
let dbName: string;
beforeEach(async () => {
dbName = `galaxy-ui-test-${crypto.randomUUID()}`;
db = await openGalaxyDB(dbName);
const store = {
keyStore: new WebCryptoKeyStore(db),
cache: new IDBCache(db),
};
session.resetForTests();
session.setStoreLoaderForTests(async () => store);
await session.init();
await session.signIn("device-1");
i18n.resetForTests("en");
listMyGamesSpy.mockReset();
listPublicGamesSpy.mockReset();
listMyInvitesSpy.mockReset();
listMyApplicationsSpy.mockReset();
submitApplicationSpy.mockReset();
redeemInviteSpy.mockReset();
declineInviteSpy.mockReset();
});
afterEach(async () => {
session.resetForTests();
i18n.resetForTests("en");
db.close();
await new Promise<void>((resolve) => {
const req = indexedDB.deleteDatabase(dbName);
req.onsuccess = () => resolve();
req.onerror = () => resolve();
req.onblocked = () => resolve();
});
});
async function importLobbyPage(): Promise<typeof import("../src/routes/lobby/+page.svelte")> {
return import("../src/routes/lobby/+page.svelte");
}
const baseDate = new Date("2026-05-07T10:00:00Z");
function makeGame(id: string, name: string, status = "draft") {
return {
gameId: id,
gameName: name,
gameType: "private",
status,
ownerUserId: "user-1",
minPlayers: 2,
maxPlayers: 8,
enrollmentEndsAt: baseDate,
createdAt: baseDate,
updatedAt: baseDate,
};
}
function makePublicGame(id: string, name: string) {
return {
gameId: id,
gameName: name,
gameType: "public",
status: "enrollment_open",
ownerUserId: "",
minPlayers: 4,
maxPlayers: 12,
enrollmentEndsAt: baseDate,
createdAt: baseDate,
updatedAt: baseDate,
};
}
function makeInvite(id: string) {
return {
inviteId: id,
gameId: "private-1",
inviterUserId: "host",
invitedUserId: "user-1",
code: "",
raceName: "Vegan Federation",
status: "pending",
createdAt: baseDate,
expiresAt: baseDate,
decidedAt: null,
};
}
function makeApplication(id: string, status: string) {
return {
applicationId: id,
gameId: "public-1",
applicantUserId: "user-1",
raceName: "Vegan Federation",
status,
createdAt: baseDate,
decidedAt: status === "pending" ? null : baseDate,
};
}
describe("lobby page", () => {
test("renders empty states for every section when API returns no items", async () => {
listMyGamesSpy.mockResolvedValue([]);
listPublicGamesSpy.mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 });
listMyInvitesSpy.mockResolvedValue([]);
listMyApplicationsSpy.mockResolvedValue([]);
const Page = (await importLobbyPage()).default;
const ui = render(Page);
await waitFor(() => {
expect(ui.getByTestId("lobby-my-games-empty")).toBeInTheDocument();
expect(ui.getByTestId("lobby-invitations-empty")).toBeInTheDocument();
expect(ui.getByTestId("lobby-applications-empty")).toBeInTheDocument();
expect(ui.getByTestId("lobby-public-games-empty")).toBeInTheDocument();
});
});
test("renders my-game cards and public-game cards when items are present", async () => {
listMyGamesSpy.mockResolvedValue([makeGame("private-1", "First Contact")]);
listPublicGamesSpy.mockResolvedValue({
items: [makePublicGame("public-1", "Open Lobby")],
page: 1,
pageSize: 50,
total: 1,
});
listMyInvitesSpy.mockResolvedValue([]);
listMyApplicationsSpy.mockResolvedValue([]);
const Page = (await importLobbyPage()).default;
const ui = render(Page);
await waitFor(() => {
expect(ui.getAllByTestId("lobby-my-game-card").length).toBe(1);
expect(ui.getByText("First Contact")).toBeInTheDocument();
expect(ui.getByText("Open Lobby")).toBeInTheDocument();
});
});
test("submitting an application opens the inline form and posts race_name", async () => {
listMyGamesSpy.mockResolvedValue([]);
listPublicGamesSpy.mockResolvedValue({
items: [makePublicGame("public-1", "Open Lobby")],
page: 1,
pageSize: 50,
total: 1,
});
listMyInvitesSpy.mockResolvedValue([]);
listMyApplicationsSpy.mockResolvedValue([]);
submitApplicationSpy.mockResolvedValue(makeApplication("app-1", "pending"));
const Page = (await importLobbyPage()).default;
const ui = render(Page);
await waitFor(() => {
expect(ui.getByTestId("lobby-public-game-apply")).toBeInTheDocument();
});
await fireEvent.click(ui.getByTestId("lobby-public-game-apply"));
await waitFor(() => {
expect(ui.getByTestId("lobby-application-form")).toBeInTheDocument();
});
await fireEvent.input(ui.getByTestId("lobby-application-race-name"), {
target: { value: "Vegan Federation" },
});
await fireEvent.click(ui.getByTestId("lobby-application-submit"));
await waitFor(() => {
expect(submitApplicationSpy).toHaveBeenCalledWith(
expect.anything(),
"public-1",
"Vegan Federation",
);
expect(ui.getByTestId("lobby-application-card")).toBeInTheDocument();
});
});
test("submitting an empty race name surfaces a validation error and does not call the API", async () => {
listMyGamesSpy.mockResolvedValue([]);
listPublicGamesSpy.mockResolvedValue({
items: [makePublicGame("public-1", "Open Lobby")],
page: 1,
pageSize: 50,
total: 1,
});
listMyInvitesSpy.mockResolvedValue([]);
listMyApplicationsSpy.mockResolvedValue([]);
const Page = (await importLobbyPage()).default;
const ui = render(Page);
await waitFor(() =>
expect(ui.getByTestId("lobby-public-game-apply")).toBeInTheDocument(),
);
await fireEvent.click(ui.getByTestId("lobby-public-game-apply"));
await fireEvent.click(ui.getByTestId("lobby-application-submit"));
await waitFor(() => {
expect(ui.getByTestId("lobby-application-error")).toBeInTheDocument();
expect(submitApplicationSpy).not.toHaveBeenCalled();
});
});
test("accepting an invitation calls redeemInvite and removes the card", async () => {
listMyGamesSpy.mockResolvedValue([]);
listPublicGamesSpy.mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 });
listMyInvitesSpy.mockResolvedValue([makeInvite("invite-1")]);
listMyApplicationsSpy.mockResolvedValue([]);
redeemInviteSpy.mockResolvedValue(makeInvite("invite-1"));
const Page = (await importLobbyPage()).default;
const ui = render(Page);
await waitFor(() =>
expect(ui.getByTestId("lobby-invite-accept")).toBeInTheDocument(),
);
await fireEvent.click(ui.getByTestId("lobby-invite-accept"));
await waitFor(() => {
expect(redeemInviteSpy).toHaveBeenCalledWith(
expect.anything(),
"private-1",
"invite-1",
);
expect(ui.queryByTestId("lobby-invite-accept")).not.toBeInTheDocument();
expect(ui.getByTestId("lobby-invitations-empty")).toBeInTheDocument();
});
});
test("declining an invitation calls declineInvite and removes the card", async () => {
listMyGamesSpy.mockResolvedValue([]);
listPublicGamesSpy.mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 });
listMyInvitesSpy.mockResolvedValue([makeInvite("invite-2")]);
listMyApplicationsSpy.mockResolvedValue([]);
declineInviteSpy.mockResolvedValue({ ...makeInvite("invite-2"), status: "declined" });
const Page = (await importLobbyPage()).default;
const ui = render(Page);
await waitFor(() =>
expect(ui.getByTestId("lobby-invite-decline")).toBeInTheDocument(),
);
await fireEvent.click(ui.getByTestId("lobby-invite-decline"));
await waitFor(() => {
expect(declineInviteSpy).toHaveBeenCalledWith(
expect.anything(),
"private-1",
"invite-2",
);
expect(ui.queryByTestId("lobby-invite-decline")).not.toBeInTheDocument();
});
});
test("application status badges localise pending and approved states", async () => {
listMyGamesSpy.mockResolvedValue([]);
listPublicGamesSpy.mockResolvedValue({ items: [], page: 1, pageSize: 50, total: 0 });
listMyInvitesSpy.mockResolvedValue([]);
listMyApplicationsSpy.mockResolvedValue([
makeApplication("app-1", "pending"),
makeApplication("app-2", "approved"),
]);
const Page = (await importLobbyPage()).default;
const ui = render(Page);
await waitFor(() => {
const cards = ui.getAllByTestId("lobby-application-card");
expect(cards.length).toBe(2);
expect(cards[0]!.querySelector(".status")?.textContent?.trim()).toBe("pending");
expect(cards[1]!.querySelector(".status")?.textContent?.trim()).toBe("approved");
});
});
});
+8
View File
@@ -8,6 +8,9 @@ importers:
frontend:
dependencies:
flatbuffers:
specifier: ^25.9.23
version: 25.9.23
idb:
specifier: ^8.0.3
version: 8.0.3
@@ -577,6 +580,9 @@ packages:
picomatch:
optional: true
flatbuffers@25.9.23:
resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==}
form-data@4.0.5:
resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==}
engines: {node: '>= 6'}
@@ -1515,6 +1521,8 @@ snapshots:
optionalDependencies:
picomatch: 4.0.4
flatbuffers@25.9.23: {}
form-data@4.0.5:
dependencies:
asynckit: 0.4.0