import type { ChannelsAPI } from '../domains/channels.js'; import type { EngineDetector } from './engine.js'; import type { GameModelAPI } from '../domains/gameModel.js'; import type { UdpAPI } from '../domains/udp.js'; import type { Scalars } from '../generated/graphql.js'; import { type KitInvokeResult } from './shared.js'; /** Options for {@link MatchesKit}. Must match the deployed matches blueprint. */ export interface MatchesKitOptions { /** * The compute module driving server-side match lifecycle when the app * runs an engine. Defaults to `'match-engine'`. */ engineModuleName?: string; /** The `typePrefix` the matches blueprint was deployed with. */ typePrefix?: string; /** * The 32-ASCII-char actor uuid used as the sender id on channel pings. * Defaults to a random uuid per kit instance. */ actorUuid?: string; } /** A parsed view of one match. */ export interface KitMatch { /** The session backing the match (participants + turn order). */ sessionId: string; /** The MatchMeta container id (the `self` of the lifecycle functions). */ metaId: string; displayName: string; creatorUserId: number; mode: string; state: string; round: number; maxPlayers: number; winnerUserId: number; /** The per-match notification channel (0 when none was wired). */ channelId: string; /** Present when the blueprint was deployed with `turnTick`. */ tickCount?: number; /** * The current turn's sequence number. Present only when the blueprint was * deployed with `turnTimer`, which is how the helpers detect that turns * carry a deadline. */ turnSeq?: number; /** The highest turn sequence whose deadline elapsed. See {@link turnExpired}. */ turnExpiredSeq?: number; } /** * Whether the match's current turn has run out of time — true once the * deadline for the open turn has fired. Always false for a match deployed * without `turnTimer`, and false for a deadline stranded by an earlier turn, * since those record a lower sequence than the one now open. */ export declare function turnExpired(match: KitMatch): boolean; /** One row of the match standings. */ export interface KitMatchScore { containerId: string; ownerUserId: string | null; points: number; } /** * Runtime helpers for the {@link matchesBlueprint} conventions: sessions ARE * the match primitive — `create` makes a session + a `MatchMeta` + a * per-match channel; turn order goes through the platform's session-turn * authority; lifecycle functions ping the channel post-commit and * {@link onMatchChanged} wraps the notify-to-pull loop (subscribe → * `"match_changed"` ping → re-pull state). * * Obtained via `client.kit(appId).matches`. */ export declare class MatchesKit { private readonly appId; private readonly gameModel; private readonly channels; private readonly udp; private readonly engines?; private readonly names; private readonly actorUuid; private readonly engineModuleName; constructor(appId: Scalars['BigInt']['input'], gameModel: GameModelAPI, channels: ChannelsAPI | undefined, udp: UdpAPI | undefined, options?: MatchesKitOptions, engines?: EngineDetector | undefined); private requireChannels; private requireUdp; /** * Create a match: a session (the platform match primitive), a per-match * notification channel, and the session-scoped `MatchMeta`. * * @param input.creatorUserId - The calling player's user id (stored so the * creator may start/advance/end the match). */ create(input: { creatorUserId: Scalars['BigInt']['input']; mode?: string; maxPlayers?: number; displayName?: string; }): Promise; /** List joinable matches (metas still in the lobby state). */ open(): Promise; /** Read one match by its MatchMeta container. */ get(metaId: string): Promise; /** Join a match: session participation + the notification channel. */ join(match: KitMatch): Promise<{ __typename?: "GmSessionParticipant"; sessionId: string; userId: string; role: string; }>; /** Start the match (creator or host). Pings the match channel post-commit. */ start(match: KitMatch): Promise>; /** Advance to the next round (creator or host). */ advanceRound(match: KitMatch): Promise>; /** Whether it is `userId`'s session turn right now. */ myTurn(match: KitMatch, userId: Scalars['BigInt']['input']): Promise; /** * Pass the turn to the next player via the platform's session-turn * authority (current holder, host, or admin — enforced by the service), * then ping the match channel so everyone re-pulls. * * For a match deployed with `turnTimer`, this opens the incoming turn first * so it arrives with a deadline already running. Opening it before the * handover also means the outgoing holder is still the session's turn user, * which is what authorizes them to do it. */ endTurn(match: KitMatch, nextUserId: Scalars['BigInt']['input']): Promise<{ __typename?: "GmSession"; sessionId: string; appId: string; name: string | null; status: string; createdByUserId: string | null; currentTurnUserId: string | null; metadataJson: string; }>; /** * Open a turn and arm its deadline (`turnTimer` deployments only) — the * deadline replaces any still pending for this match. `endTurn` calls this * for you; call it directly to give the current player a fresh clock, e.g. * after granting extra time. */ beginTurn(match: KitMatch): Promise>; /** * Cancel the pending turn deadline for this match, if any. Returns how many * timers were dropped. Ending a match already strands its deadline, so this * is only needed when you want turns to stop being timed while play * continues. */ cancelTurnDeadline(match: KitMatch): Promise; /** Find-or-create a player's session-scoped Score row. */ ensureScore(match: KitMatch, ownerUserId: Scalars['BigInt']['input']): Promise<{ __typename?: "GmContainer"; containerId: string; appId: string; sessionId: string | null; typeName: string; displayName: string; description: string | null; ownerUserId: string | null; metadataJson: string; }>; /** * Add points to a Score row — trusted (host-refereed by default). * Resolves with the new points. */ score(match: KitMatch, scoreId: string, points: number): Promise>; /** The match standings, highest points first (client-side sort). */ standings(match: KitMatch): Promise; /** * Finish the match and record the winner (creator or host). Also drops the * pending turn deadline on a `turnTimer` match — `end_match` already * strands it, so this just saves the pointless fire and channel ping. */ finish(match: KitMatch, winnerUserId: Scalars['BigInt']['input']): Promise>; /** * Manually ping the match channel with `"match_changed"` (the lifecycle * functions do this automatically via their declared notifications; use * this after out-of-band changes such as `endTurn`). */ notifyChanged(match: KitMatch): Promise; /** * The notify-to-pull loop, wrapped: subscribe to the app's notifications, * and on every ping of THIS match's channel re-pull the match state and * hand it to `callback`. Returns the unsubscribe function. */ onMatchChanged(match: KitMatch, callback: (match: KitMatch) => void): () => void; private toMatch; /** * Is a match compute engine deployed + enabled (cached per session)? When * true the engine owns transitions (ready checks, turn order + timeouts, * authoritative scoring); the blueprint's creator-driven functions remain * for model-only deployments. */ engineAvailable(): Promise; /** * Declare ready on an engine match (a MatchMeta container id). The match * starts server-side once every expected player is ready. */ engineReady(matchId: string): Promise>; /** Submit your move (the engine validates the turn + resolves). */ engineSubmitMove(matchId: string, params?: Record): Promise>; /** Forfeit an engine match. */ engineForfeit(matchId: string): Promise>; /** The engine's live view: turn holder, timers, standings, summary. */ engineStatus(matchId: string): Promise>; /** * Resolve a matchmaking proposal to the match the engine created for it * (poll after everyone accepts; see `kit.matchmaking`). */ findByProposal(proposalId: string): Promise; private engineInvoke; } //# sourceMappingURL=matches.d.ts.map