@anweather/game-plugin-ssdk 1.25.0 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,8 @@ export type { ServePluginOptions, PluginServiceDefinition, PluginApp, RunningPlu
6
6
  export { createRegistrationLoop } from "./registration";
7
7
  export type { RegistrationOptions, RegistrationLoop } from "./registration";
8
8
  export { runConformance, assertConformance } from "./conformance";
9
+ export { validatePresentation, assertPresentation, PRESENTATION_CATEGORIES, MAX_PRESENTATION_BYTES } from "./presentation";
10
+ export type { PluginPresentation, PresentationCategory } from "./presentation";
9
11
  export type { ConformanceOptions, ConformanceReport } from "./conformance";
10
12
  export { PLUGIN_PROTOCOL_VERSION, runtimeVersion } from "./version";
11
13
  export { createBlobClient, casUpdate, blobOwner, allBlobOwners, BlobStoreError, isVersionConflict } from "./blobClient";
@@ -0,0 +1,68 @@
1
+ export declare const PRESENTATION_CATEGORIES: readonly ["classic", "strategy", "cards", "word", "wip"];
2
+ export type PresentationCategory = (typeof PRESENTATION_CATEGORIES)[number];
3
+ /** The platform refuses a registration whose presentation serialises
4
+ * larger than this. */
5
+ export declare const MAX_PRESENTATION_BYTES: number;
6
+ export interface PluginPresentation {
7
+ catalogue?: {
8
+ /** Shown instead of GetMetadata's displayName wherever the platform
9
+ * names the game (tile, game page, lists). Absent: displayName. */
10
+ title?: string;
11
+ /** The catalogue tab the tile lives under. Default "wip". */
12
+ category?: PresentationCategory;
13
+ /** Also list the tile under the catalogue's Featured tab. Default false. */
14
+ featured?: boolean;
15
+ /** The tile's gradient, top-left to bottom-right, and its text colour,
16
+ * as Tailwind palette tokens ("amber-700", or "white"/"black"). Absent: a neutral slate. */
17
+ poster?: {
18
+ from: string;
19
+ to: string;
20
+ text: string;
21
+ };
22
+ };
23
+ /** "How to play", one entry per bullet. */
24
+ rules?: string[];
25
+ board?: {
26
+ /** "fullscreen" (default): edge to edge, the platform's chrome in a
27
+ * corner menu. "page": a card on the game page, with `page` options. */
28
+ layout?: "fullscreen" | "page";
29
+ /** Only read for layout "page". nameplates: "split" (default; opponents
30
+ * above, you below), "below" (everyone under the board) or "none" (the
31
+ * board draws its own). fullBleed: no padding around the board. */
32
+ page?: {
33
+ nameplates?: "split" | "below" | "none";
34
+ fullBleed?: boolean;
35
+ };
36
+ /** Who shows a refused move. "platform" (default): a banner. "board":
37
+ * the move promise rejects and the board shows it -- only for a board
38
+ * that actually catches it, or the player sees nothing at all. */
39
+ moveErrors?: "platform" | "board";
40
+ /** The browser's own long press (callout, magnifier, context menu,
41
+ * text selection) over the board. Default: "suppress" in full screen,
42
+ * "allow" on a page. "allow" is the opt-out for copyable text. */
43
+ nativeGestures?: "suppress" | "allow";
44
+ /** The Recap button. Absent or false (default): no recap. An object
45
+ * turns it on; stepMs holds each replayed state (default 900). Only
46
+ * for a board that animates the change between consecutive views. */
47
+ recap?: false | {
48
+ stepMs?: number;
49
+ };
50
+ /** The ShadowMount host box. overflowX default "auto", width default
51
+ * "fit". */
52
+ host?: {
53
+ overflowX?: "auto" | "hidden" | "clip";
54
+ width?: "fit" | "full";
55
+ };
56
+ };
57
+ /** A two-seat game whose seats have names (chess: ["White", "Black"]):
58
+ * the sole winner picks their seat for the rematch. */
59
+ rematch?: {
60
+ seatNames: [string, string];
61
+ };
62
+ }
63
+ /** Every problem with `value` as a presentation, strictest reading: wrong
64
+ * types, unknown enum values, and unknown fields. Empty means valid. */
65
+ export declare function validatePresentation(value: unknown): string[];
66
+ /** validatePresentation, throwing the whole list. servePlugin calls this at
67
+ * startup, so a bad presentation fails the container, not the platform. */
68
+ export declare function assertPresentation(value: unknown): asserts value is PluginPresentation;
@@ -5,6 +5,7 @@ import type { GamePluginService, GamePluginServiceOperations } from "../src/serv
5
5
  import type { OptionalGamePluginService, RequiredGamePluginService } from "./defaultService";
6
6
  import { type RegistrationLoop } from "./registration";
7
7
  import { type LiveServer } from "./live/server";
8
+ import { type PluginPresentation } from "./presentation";
8
9
  import type { LiveOptions } from "./live/rooms";
9
10
  /** What a plugin supplies: every operation createGamePluginService requires,
10
11
  * except Health, which servePlugin answers itself unless overridden. */
@@ -47,6 +48,12 @@ export interface ServePluginOptions<Context = Record<string, never>> {
47
48
  * platform opens one room link per active channel to /v1/live on this
48
49
  * same server, behind the same X-Plugin-Auth token. Absent: no /v1/live. */
49
50
  live?: LiveOptions;
51
+ /** How the platform's frontend shows this game type (catalogue tile,
52
+ * rules, board layout): added to GetMetadata as `presentation` unless
53
+ * the service's own GetMetadata already sets one. Checked strictly at
54
+ * startup (validatePresentation), so a bad one fails this container
55
+ * rather than reaching the platform. See ./presentation.ts. */
56
+ presentation?: PluginPresentation;
50
57
  }
51
58
  export interface PluginApp {
52
59
  app: Express;
@@ -289,6 +289,7 @@ export interface GameTypeMetadata {
289
289
  * @public
290
290
  */
291
291
  live?: LiveCapability | undefined;
292
+ presentation?: __DocumentType | undefined;
292
293
  }
293
294
  export declare namespace GameTypeMetadata {
294
295
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@anweather/game-plugin-ssdk",
3
3
  "description": "Generated GamePlugin RPC types/server (plugin-protocol/model/game-plugin.smithy) plus a hand-written Express bridge and default-handler wrapper (./runtime) -- see plugin-protocol/CLAUDE.md's \"Publishing for cross-repo plugins\".",
4
- "version": "1.25.0",
4
+ "version": "1.27.0",
5
5
  "scripts": {
6
6
  "build": "concurrently 'npm:build:cjs' 'npm:build:es' 'npm:build:types'",
7
7
  "build:cjs": "tsc -p tsconfig.cjs.json",