UNPKG

goban

Version:

[![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/online-go/goban)

806 lines (805 loc) 28.2 kB
import type { JGOFMove, JGOFPlayerClock, JGOFSealingIntersection } from "../formats/JGOF"; import type { ReviewMessage } from "../GobanEngine"; import type { ConditionalMoveResponse } from "../ConditionalMoveTree"; /** Messages that clients send, regardless of target server */ export interface ClientToServerBase { /** Authenticate with the server. * * Prior to authentication, you should perform a GET request to * `/api/v1/ui/config` * to get the current configuration. Within the returned JSON * you will find all of the necessary fields to authenticate. */ "authenticate": (data: { /** The JSON Web Token (`user_jwt` field) from `/api/v1/ui/config`. If * connecting as a guest, send "" */ jwt: string; /** Client generated unique id for the device. */ device_id?: string; /** Browser user agent (or websocket library) */ user_agent?: string; /** ISO 639-1 language code used on this device. */ language?: string; /** The version of the translation dictionary. */ language_version?: string; /** Client name (your application name) */ client?: string; /** Client version string. */ client_version?: string; /** Bot username connecting, if applicable */ bot_username?: string; /** Bot API key, if applicable */ bot_apikey?: string; }) => { id: number; username: string; } | undefined; /** Sends a ping to the server. This message should be * sent regularly. The default interval is 10 seconds. * This keeps the connection alive and allows a client * to measure clock drift and latency, both of which * are vital to adjusting the client's game clock displays. */ "net/ping": (data: { /** Client timestamp - milliseconds since epoch */ client: number; /** Last clock drift measurement, or `0` */ drift: number; /** Last latency measurement, or `0` */ latency: number; }) => void; } /** This is an exhaustive list of the messages that the client can send * to the server. * * This documentation is generated from the official typescript interface. * To interpret it, you will every message organized as the name of the * message followed by a function taking the message data parameters and * returning what you can expect tor receive back. * * For example, the authentication message documentation looks like this: * * ```typescript * authenticate: ((data: { * bot_apikey?: string; * bot_username?: string; * client?: string; * client_version?: string; * device_id?: string; * jwt: string; * language?: string; * language_version?: string; * user_agent?: string; * }) => undefined | { * id: number; * username: string; * }) * ``` * * The command you will send is `authenticate`, the data you send will be an object with the following format: * ```typescript * { * bot_apikey?: string; * bot_username?: string; * client?: string; * client_version?: string; * device_id?: string; * jwt: string; * language?: string; * language_version?: string; * user_agent?: string; * } * ``` * * and you can expect to receive back either `undefined` or `{id: number, username: string}` * */ export interface ClientToServer extends ClientToServerBase { /** Get active automatch entries for the current user */ "automatch/list": (data: {}) => void; /** Message to let the server know the client is still interested * in the specified blitz or live challenge. These should be sent * about once a second to prevent the server from canceling the challenge. */ "challenge/keepalive": (data: { challenge_id: number; game_id: number; }) => void; /** Connect to a game. Once connected, the client will receive game * updates relevant to the game. */ "game/connect": (data: { /** The game id to connect to */ game_id: number; /** If true, the client will receive the game chat log and new chat events */ chat?: boolean; }) => void; /** Disconnect from a game. This will stop game updates for a particular game. */ "game/disconnect": (data: { game_id: number; }) => void; /** Sets removed stones in the stone removal phase. */ "game/removed_stones/set": (data: { /** The game id */ game_id: number; /** True if the stones should be marked as removed (or intersections marked * as dame if there is no stone there), false if they should be marked as * not removed / open area. */ removed: boolean; /** List of intersections that are to be removed. */ stones: JGOFMove[] | string; /** List of intersections that need to be sealed before the game can be * correctly scored. Note, if this is undefined, the value will not * be changed on the server side. To specify there are no more intersections * that need to be cleared, set it to `[]` specifically. */ needs_sealing?: JGOFSealingIntersection[]; /** Japanese rules technically have some special scoring rules about * whether territory in seki should be counted or not. This is supported * by the backend but the official client no longer displays this as an * option to the user as it was very largely unused and was a large * source of confusion. This field is deprecated and will likely be * removed in the future.*/ strict_seki_mode?: boolean; }) => void; /** Rejects the removed stones and resumes the game from the stone removal phase */ "game/removed_stones/reject": (data: { /** The game id */ game_id: number; }) => void; /** Accepts the stones as removed. Once both players have accepted the same * stones, the stone removal phase will conclude and the game will finish. */ "game/removed_stones/accept": (data: { /** The game id */ game_id: number; /** All of the stones that are accepted as removed, and all * intersections marked as dame */ stones: string; /** Japanese rules technically have some special scoring rules about * whether territory in seki should be counted or not. This is supported * by the backend but clients should always set this to false in this * era of the game, the official client no longer displays this as an * option to the user as it was very largely unused and was a large * source of confusion. */ strict_seki_mode: boolean; }) => void; /** Submit a move for a game */ "game/move": (data: { /** The game id */ game_id: number; /** The move number to play at */ move: string; /** Maximum number of milliseconds the client was out of focus between * the last move and this move */ blur?: number; /** Clock according to the client. If this is within the margin of * error of the server's clock, the server will accept the new * clock value. If not provided, the server clock will be used. */ clock?: JGOFPlayerClock; }) => void; /** Requests an undo */ "game/undo/request": (data: { /** The game id */ game_id: number; /** The current move number */ move_number: number; }) => void; /** Accepts an undo */ "game/undo/accept": (data: { /** The game id */ game_id: number; /** The current move number */ move_number: number; }) => void; /** Cancels an undo request */ "game/undo/cancel": (data: { /** The game id */ game_id: number; /** The current move number */ move_number: number; }) => void; /** Pauses the game clocks */ "game/pause": (data: { /** The game id */ game_id: number; }) => void; /** Resumes the game clocks */ "game/resume": (data: { /** The game id */ game_id: number; }) => void; /** Resigns from the game */ "game/resign": (data: { /** The game id */ game_id: number; }) => void; "game/delayed_resign": (data: { /** The game id */ game_id: number; }) => void; "game/clear_delayed_resign": (data: { /** The game id */ game_id: number; }) => void; /** Cancels a game. This is effectively the same as resign, except the * game will not be ranked. This is only allowed within the first few * moves of the game. (See GobanEngine.gameCanBeCancelled for cancellation ) */ "game/cancel": (data: { /** The game id */ game_id: number; }) => void; /** In Japanese rules, if the game is found to be repeating, the players * may opt to annul the entire game and start over. * * This is largely undesired in an online setting and support for this * will probably be removed in the future, dont' bother implementing * this. */ "game/annul": (data: { /** The game id */ game_id: number; }) => void; /** Request the server end a game that is being stalled by one of the * players. This will only work if the server agrees in the outcome. */ "game/prevent_stalling": (data: { /** The game id */ game_id: number; /** The proposed winner */ winner: "black" | "white"; }) => void; /** Request the server end a game that someone has left without resigning * from */ "game/prevent_escaping": (data: { /** The game id */ game_id: number; /** The proposed winner */ winner: "black" | "white"; /** Request that the game be annulled or not */ annul: boolean; }) => void; /** Inform the server that the client believes it's clock has timed out * and the game should be ended in a timeout. This is not strictly necessary * to implement as the server will also timeout games, however there is * a grace period to account for network latency, so well behaved clients * can (and should) send this message to be very exact with timeouts. */ "game/timed_out": (data: { /** The game id */ game_id: number; }) => void; /** Sets conditional moves to be made on behalf of the player in response * to a move by the opponent. */ "game/conditional_moves/set": (data: { /** The game id */ game_id: number; /** The move number from which the conditional moves are rooted in */ move_number: number; /** The conditional moves. The top level should be an array that looks * like `[null, { ... }]` where the second element contains the responses * to the opponent's move. */ conditional_moves: ConditionalMoveResponse; }) => void; /** Sends a chat message to a game */ "game/chat": (data: { /** The game id */ game_id: number; /** The type of chat message being sent */ type: "main" | "malkovich" | "moderator" | "hidden" | "personal"; /** The move number currently being viewed */ move_number: number; /** The chat message */ body: string | GameChatTranslatedMessage | GameChatAnalysisMessage | GameChatReviewMessage; }) => void; /** Update your latency information for a particular game. This is used * for clock synchronization. It is not strictly required, however strongly * suggested for live games. */ "game/latency": (data: { /** The game id */ game_id: number; /** Network latency, measured in milliseconds. See net/ping to measure this. */ latency: number; }) => void; /** Connects to a review */ "review/connect": (data: { /** The review id */ review_id: number; }) => void; /** Disconnects from a review */ "review/disconnect": (data: { /** The review id */ review_id: number; }) => void; /** Append a review action to the review log. */ "review/append": (data: ReviewMessage) => void; /** Sends a chat message to a review */ "review/chat": (data: { /** The review id */ review_id: number; /** The root of the branch the user is viewing */ from: number; /** The analysis branch the user is viewing */ moves: string; /** The chat message */ body: string; }) => void; /** Request the number of unique authenticated players * online within the given interval */ "stats/online": (data: { /** Interval in seconds */ interval: number; }) => number; /** Deletes a notification */ "notification/delete": (data: { notification_id: string; }) => void; /** Connects to the game list count. * Once connected you'll start receiving `gamelist-count` or * `gamelist-count-${channel}` messages. */ "gamelist/count/subscribe": (data: { /** The group or tournament channel to subscribe to. If no * channel is provided, the global server counts will be * sent */ channel?: string; }) => void; /** Disconnects from the game list count */ "gamelist/count/unsubscribe": (data: { /** The group or tournament channel to unsubscribe from. If no * channel is provided, the global server counts will be * unsubscribed from */ channel?: string; }) => void; /** Queries the server for a list of games */ "gamelist/query": (data: { list: "live" | "corr" | "kidsgo"; sort_by: "rank"; /** Filtering options */ where: GameListWhere; /** The number of games to skip before returning results */ from: number; /** Number of games to return, between 1 and 300 */ limit: number; /** The group or tournament channel to query */ channel?: string; }) => undefined | { list: string; by: string; size: number; where: GameListWhere; from: number; limit: number; results: GameListEntry[]; }; /** Returns an event log for the given game. This is primarily * for moderation purposes, although the endpoint is generally * available to all users. */ "game/log": (data: { game_id: number; }) => { timestamp: string; event: string; data: any; }[]; /** Subscribes to online status updates for the given player ids */ "user/monitor": (data: { user_ids: number[]; }) => void; /** Sends an "Inter Tab Communication" message to all other connected * clients for the current user. This includes other devices, so the * "Tab" part is a bit of a misnomer. */ "itc": (data: { /** User defined event string */ event: string; /** User defined data */ data: any; }) => void; /** Set the given key in the remote storage system for this user * * For more details on the remote storage replication system see: * https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts */ "remote_storage/set": (data: { key: string; value: any; replication: RemoteStorageReplication; }) => { error?: string; retry?: boolean; } | { success: true; }; /** Remove the given key from remote storage system for this user * * For more details on the remote storage replication system see: * https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts */ "remote_storage/remove": (data: { key: string; replication: RemoteStorageReplication; }) => { error?: string; retry?: boolean; } | { success: true; }; /** Requests all updated key/value pairs for this user since the * provided timestamp (as as ISO 8601 string). * * For more details on the remote storage replication system see: * https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts */ "remote_storage/sync": (data: { /** ISO 8601 timestamp. Updates made after this timestamp will be sent to the client. */ since: string; }) => { error?: string; retry?: boolean; } | { success: true; }; /** Sets a channel topic */ "chat/topic": (data: { channel: string; topic: string; }) => void; /** Sends a chat message to the given channel */ "chat/send": (data: { /** Channel to send the message to */ channel: string; /** ID for the message */ uuid: string; /** Message text */ message: string; }) => void; /** Join a chat channel */ "chat/join": (data: { /** Channel to join */ channel: string; }) => void; /** Leave a channel */ "chat/part": (data: { /** Channel to leave */ channel: string; }) => void; /** Subscribes to UI related push event messages sent to a particular channel */ "ui-pushes/subscribe": (data: { channel: string; }) => void; /** Un-Subscribes to UI related push event messages sent to a particular channel */ "ui-pushes/unsubscribe": (data: { channel: string; }) => void; /** Subscribes to the seek graph events. The channel is required to be "global" * for now and the foreseeable future. */ "seek_graph/connect": (data: { channel: "global"; }) => void; /** Un-Subscribes to the seek graph events. The channel is required to be "global" * for now and the foreseeable future. */ "seek_graph/disconnect": (data: { channel: "global"; }) => void; /** Send a private message to another user */ "chat/pm": (data: { /** Player ID of the recipient */ player_id: number; /** Username of the recipient */ username: string; /** UUID for the message */ uid: string; /** Message text */ message: string; /** Moderator option to send the chat from the system not from their personal PM */ as_system?: true; }) => undefined | { from: User; to: { id: number; username: string; }; message: { i: string; t: number; m: string; }; }; /** Loads the current user's private message session history with the given player id */ "chat/pm/load": (data: { player_id: number; }) => void; /** Closes the current user's private message session with the given player id */ "chat/pm/close": (data: { player_id: number; }) => void; /** Begins a "super chat" session with the given player id, which creates an * unclosable dialog if enable is true, and makes the dialog closable again * if enable is false. This is only available to moderators. */ "chat/pm/superchat": (data: { player_id: number; /** Username of the recipient */ username: string; /** Set to true if you want the modal to be unclosable, false if you want * the modal to be closable again */ enable: boolean; }) => void; /** Moderator only command to remove all chat messages for a given player */ "chat/remove_all": (data: { /** Player id to remove all messages for */ player_id: number; }) => void; /** Moderator only command to remove a single chat message */ "chat/remove": (data: { uuid: string; }) => void; /** Moderator only command to remove a single chat message from a game */ "game/chat/remove": (data: { game_id: number; channel: string; chat_id: string; }) => void; /** Moderator only command to remove a single chat message from a game */ "review/chat/remove": (data: { review_id: number; channel: string; chat_id: string; }) => void; /** Retrieve host information for the termination server you are connected to */ "hostinfo": (data: {}) => { "hostname": string; "clients": number; "uptime": number; "ggs-version": string; }; /** Request a match via the automatch system */ "automatch/find_match": (data: AutomatchPreferences) => void; /** Cancel a match request */ "automatch/cancel": (data: { uuid: string; }) => void; /** Subscribe to automatch offers */ "automatch/available/subscribe": () => void; /** Unsubscribe from automatch offers */ "automatch/available/unsubscribe": () => void; /** Updates the config for the bot */ "bot/config": (config: BotConfig) => void; /** Update the number of games that the bot is currently playing */ "bot/status": (data: { ongoing_blitz_count: number; ongoing_live_count: number; ongoing_correspondence_count: number; }) => void; } export interface BotAllowedClockSettingsV1 { simple?: { per_move_time_range: [number, number]; }; byoyomi?: { main_time_range: [number, number]; period_time_range: [number, number]; periods_range: [number, number]; }; fischer?: { max_time_range: [number, number]; time_increment_range: [number, number]; }; concurrent_games?: number; } export interface BotAllowedClockSettingsV2 { simple?: { per_move_time_range: [number, number]; }; byoyomi?: { main_time_range: [number, number]; period_time_range: [number, number]; periods_range: [number, number]; }; fischer?: { initial_time_range: [number, number]; max_time_range: [number, number]; time_increment_range: [number, number]; }; concurrent_games?: number; } export interface BotConfigV0 { _config_version: 0; } export interface BotConfigV1 { _config_version: 1; hidden: boolean; bot_id: number; username: string; allowed_time_control_systems: ("simple" | "byoyomi" | "fischer")[]; allowed_board_sizes: number[] | "all" | "square" | number; allowed_blitz_settings?: BotAllowedClockSettingsV1; allowed_rapid_settings?: BotAllowedClockSettingsV1; allowed_live_settings?: BotAllowedClockSettingsV1; allowed_correspondence_settings?: BotAllowedClockSettingsV1; allow_ranked: boolean; allow_unranked: boolean; allowed_rank_range: [string, string]; allow_ranked_handicap: boolean; allow_unranked_handicap: boolean; allowed_komi_range: [number, number]; decline_new_challenges: boolean; min_move_time: number; max_games_per_player: number; } export interface BotConfigV2 { _config_version: 2; hidden: boolean; bot_id: number; username: string; allowed_time_control_systems: ("simple" | "byoyomi" | "fischer")[]; allowed_board_sizes: number[] | "all" | "square" | number; allowed_blitz_settings?: BotAllowedClockSettingsV2; allowed_rapid_settings?: BotAllowedClockSettingsV2; allowed_live_settings?: BotAllowedClockSettingsV2; allowed_correspondence_settings?: BotAllowedClockSettingsV2; allow_ranked: boolean; allow_unranked: boolean; allowed_rank_range: [string, string]; allow_ranked_handicap: boolean; allow_unranked_handicap: boolean; allowed_komi_range: [number, number]; decline_new_challenges: boolean; min_move_time: number; max_games_per_player: number; } export type BotConfig = BotConfigV0 | BotConfigV1 | BotConfigV2; export type Speed = "blitz" | "rapid" | "live" | "correspondence"; export type Size = "9x9" | "13x13" | "19x19"; export type AutomatchCondition = "required" | "preferred" | "no-preference"; export type RuleSet = "japanese" | "chinese" | "aga" | "korean" | "nz" | "ing"; export interface AutomatchPreferences { uuid: string; size_speed_options: Array<{ size: Size; speed: Speed; system: "fischer" | "byoyomi"; }>; timestamp?: number; lower_rank_diff: number; upper_rank_diff: number; rules: { condition: AutomatchCondition; value: "japanese" | "chinese" | "aga" | "korean" | "nz" | "ing"; }; handicap: { condition: AutomatchCondition; value: "enabled" | "disabled"; }; } /** This enum defines the various replication strategies for the remote storage * system. For more details on the remote storage replication system see: * https://github.com/online-go/online-go.com/blob/devel/src/lib/data.ts */ export declare enum RemoteStorageReplication { /** No replication of this change */ NONE = 0, /** Locally set data will overwrite remotely set data, but if not * set will default to remotely set data */ LOCAL_OVERWRITES_REMOTE = 1, /** Remotely set data will overwrite locally set data */ REMOTE_OVERWRITES_LOCAL = 2, /** Remotely set data, but do not update our local value */ REMOTE_ONLY = 4 } /** Parameters for the `gamelist/query` message */ export interface GameListWhere { hide_ranked?: boolean; hide_unranked?: boolean; rengo_only?: boolean; hide_19x19?: boolean; hide_9x9?: boolean; hide_13x13?: boolean; hide_other?: boolean; hide_tournament?: boolean; hide_ladder?: boolean; hide_open?: boolean; hide_handicap?: boolean; hide_even?: boolean; hide_bot_games?: boolean; hide_beginning?: boolean; hide_middle?: boolean; hide_end?: boolean; players?: Array<number>; tournament_id?: number; ladder_id?: number; malk_only?: boolean; } interface GameListPlayer { username: string; id: number; rank: number; professional: boolean; accepted: boolean; ratings: { version: number; overall: { rating: number; deviation: number; volatility: number; }; }; } export interface GameListEntry { id: number; group_ids?: Array<number>; group_ids_map?: { [id: string]: boolean; }; kidsgo_game?: boolean; phase: string; name: string; player_to_move: number; width: number; height: number; move_number: number; paused: boolean; private: boolean; black: GameListPlayer; white: GameListPlayer; rengo: boolean; rengo_teams: { black: Array<User>; white: Array<User>; }; dropped_player: number; rengo_casual_mode: boolean; _participants?: Array<number>; time_per_move: number; clock_expiration: number; bot_game?: boolean; ranked?: boolean; handicap?: number; tournament_id?: number; ladder_id?: number; komi?: number; socket_id?: any; in_beginning?: boolean; in_middle?: boolean; in_end?: boolean; malkovich_present?: boolean; } export interface User { id: number; username: string; ratings?: { [speed_size: string]: Glicko2; }; ranking?: number; professional?: boolean; country?: string; ui_class?: string; } export interface Glicko2 { rating: number; deviation: number; volatility: number; games_played?: number; } export interface GameChatTranslatedMessage { type: "translated"; en: string; [lang: string]: string; } export interface GameChatAnalysisMessage { type: "analysis"; name?: string; branch_move?: number; from?: number; moves?: string; marks?: { [mark: string]: string; }; pen_marks?: unknown[]; engine_analysis?: { win_rate: number; score?: number; visits?: number; [key: string]: number | undefined; }; } export interface GameChatReviewMessage { type: "review"; review_id: number; } export {};