@tableverse/contracts 0.0.1

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - `GameSessionContext`, `CurrentUser`, `SessionPlayer` types describing the
13
+ session payload passed by the shell into the game.
14
+ - `GameFinishedEvent` discriminated union (`GameFinishedWin`,
15
+ `GameFinishedDraw`, `GameFinishedAborted`) for the `'finished'` CustomEvent.
16
+ - `PlatformBridge` interface and `Window.__PLATFORM__` global augmentation.
17
+ Subscription methods return an unsubscribe function.
18
+ - `CONTRACT_VERSION` constant kept in sync with `package.json` via
19
+ `scripts/sync-version.cjs`.
20
+ - ESM build pipeline, ESLint flat config, compile-time type tests,
21
+ and CI/publish GitHub Actions workflows.
package/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # @tableverse/contracts
2
+
3
+ [English](./README.md) | [Українська](./README.uk.md)
4
+
5
+ TypeScript contracts shared between the Table Verse shell and games. The package
6
+ contains only **types and constants** — no runtime logic, no DOM access, no
7
+ side effects.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install --save-dev @tableverse/contracts
13
+ ```
14
+
15
+ The package is intended as a `devDependency`. Games are shipped as
16
+ self-contained bundles, so consumers should not bundle these types into their
17
+ runtime output.
18
+
19
+ ## Usage
20
+
21
+ ```ts
22
+ import type {
23
+ GameSessionContext,
24
+ GameFinishedEvent,
25
+ PlatformBridge,
26
+ } from '@tableverse/contracts';
27
+ import { CONTRACT_VERSION } from '@tableverse/contracts';
28
+ ```
29
+
30
+ ### Custom Element wiring (game side)
31
+
32
+ ```ts
33
+ class MyGame extends HTMLElement {
34
+ static readonly observedAttributes = ['data-contract-version'];
35
+
36
+ set sessionContext(ctx: GameSessionContext) {
37
+ // store and use ctx
38
+ }
39
+
40
+ private finish(event: GameFinishedEvent) {
41
+ this.dispatchEvent(new CustomEvent('finished', { detail: event }));
42
+ }
43
+ }
44
+
45
+ customElements.define('my-game', MyGame);
46
+ ```
47
+
48
+ The game advertises the contract version it was built against:
49
+
50
+ ```html
51
+ <my-game data-contract-version="0.0.0"></my-game>
52
+ ```
53
+
54
+ ### Reading the platform bridge
55
+
56
+ ```ts
57
+ const token = window.__PLATFORM__.getToken();
58
+
59
+ const unsubscribe = window.__PLATFORM__.onTokenChange((newToken) => {
60
+ // reconnect with the fresh token
61
+ });
62
+ // later: unsubscribe();
63
+ ```
64
+
65
+ ## Exports
66
+
67
+ | Export | Kind | Description |
68
+ | --------------------- | --------- | -------------------------------------------------- |
69
+ | `GameSessionContext` | interface | Session payload passed by the shell into the game. |
70
+ | `CurrentUser` | interface | The user playing on this client. |
71
+ | `SessionPlayer` | interface | A single player in the session. |
72
+ | `GameFinishedEvent` | union | Discriminated union for the `'finished'` event. |
73
+ | `GameFinishedWin` | interface | Variant: someone won. |
74
+ | `GameFinishedDraw` | interface | Variant: draw. |
75
+ | `GameFinishedAborted` | interface | Variant: game was aborted. |
76
+ | `PlatformBridge` | interface | `window.__PLATFORM__` shape. |
77
+ | `CONTRACT_VERSION` | constant | Current contract version (semver string). |
78
+
79
+ ## Versioning
80
+
81
+ The package follows [Semantic Versioning](https://semver.org/):
82
+
83
+ - **MAJOR** — breaking change in any exported type.
84
+ - **MINOR** — additive change (new optional field, new variant in a union).
85
+ - **PATCH** — documentation, refactor, no public API change.
86
+
87
+ The shell verifies major-version compatibility against
88
+ `data-contract-version` before mounting a game.
89
+
90
+ ## License
91
+
92
+ MIT
package/README.uk.md ADDED
@@ -0,0 +1,91 @@
1
+ # @tableverse/contracts
2
+
3
+ [English](./README.md) | [Українська](./README.uk.md)
4
+
5
+ TypeScript-контракти, спільні між shell-ом Table Verse та іграми. Пакет містить
6
+ **лише типи та константи** — жодної runtime-логіки, доступу до DOM чи
7
+ сайд-ефектів.
8
+
9
+ ## Встановлення
10
+
11
+ ```bash
12
+ npm install --save-dev @tableverse/contracts
13
+ ```
14
+
15
+ Пакет призначений як `devDependency`. Ігри постачаються самодостатніми бандлами,
16
+ тому ці типи не повинні потрапляти в runtime-вивід.
17
+
18
+ ## Використання
19
+
20
+ ```ts
21
+ import type {
22
+ GameSessionContext,
23
+ GameFinishedEvent,
24
+ PlatformBridge,
25
+ } from '@tableverse/contracts';
26
+ import { CONTRACT_VERSION } from '@tableverse/contracts';
27
+ ```
28
+
29
+ ### Інтеграція через Custom Element (на боці гри)
30
+
31
+ ```ts
32
+ class MyGame extends HTMLElement {
33
+ static readonly observedAttributes = ['data-contract-version'];
34
+
35
+ set sessionContext(ctx: GameSessionContext) {
36
+ // зберегти й використати ctx
37
+ }
38
+
39
+ private finish(event: GameFinishedEvent) {
40
+ this.dispatchEvent(new CustomEvent('finished', { detail: event }));
41
+ }
42
+ }
43
+
44
+ customElements.define('my-game', MyGame);
45
+ ```
46
+
47
+ Гра оголошує версію контракту, проти якої її зібрали:
48
+
49
+ ```html
50
+ <my-game data-contract-version="0.0.0"></my-game>
51
+ ```
52
+
53
+ ### Робота з platform bridge
54
+
55
+ ```ts
56
+ const token = window.__PLATFORM__.getToken();
57
+
58
+ const unsubscribe = window.__PLATFORM__.onTokenChange((newToken) => {
59
+ // перепідключити WebSocket із новим токеном
60
+ });
61
+ // пізніше: unsubscribe();
62
+ ```
63
+
64
+ ## Експорти
65
+
66
+ | Експорт | Тип | Опис |
67
+ | --------------------- | --------- | ----------------------------------------------------- |
68
+ | `GameSessionContext` | interface | Контекст сесії, який shell передає у гру. |
69
+ | `CurrentUser` | interface | Користувач, який грає на цьому клієнті. |
70
+ | `SessionPlayer` | interface | Один гравець у сесії. |
71
+ | `GameFinishedEvent` | union | Discriminated union для події `'finished'`. |
72
+ | `GameFinishedWin` | interface | Варіант: хтось переміг. |
73
+ | `GameFinishedDraw` | interface | Варіант: нічия. |
74
+ | `GameFinishedAborted` | interface | Варіант: гру перервано. |
75
+ | `PlatformBridge` | interface | Форма `window.__PLATFORM__`. |
76
+ | `CONTRACT_VERSION` | constant | Поточна версія контракту (semver-рядок). |
77
+
78
+ ## Версіонування
79
+
80
+ Пакет дотримується [Semantic Versioning](https://semver.org/):
81
+
82
+ - **MAJOR** — breaking-зміна в будь-якому експортованому типі.
83
+ - **MINOR** — additive-зміна (нове необов'язкове поле, новий варіант у union).
84
+ - **PATCH** — документація, рефакторинг, без зміни публічного API.
85
+
86
+ Shell перевіряє сумісність за major-версією через атрибут
87
+ `data-contract-version` перед монтуванням гри.
88
+
89
+ ## Ліцензія
90
+
91
+ MIT
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Game-finished event the game emits via a CustomEvent named `'finished'`.
3
+ *
4
+ * Discriminated union keyed on the `kind` field. Consumers should handle every
5
+ * variant via an exhaustive switch so that adding a new variant is caught at
6
+ * compile time.
7
+ */
8
+ export type GameFinishedEvent = GameFinishedWin | GameFinishedDraw | GameFinishedAborted;
9
+ /**
10
+ * Game ended with a winner.
11
+ */
12
+ export interface GameFinishedWin {
13
+ readonly kind: 'win';
14
+ /** Identifier of the winning player. */
15
+ readonly winnerId: string;
16
+ /** Final scores keyed by player id. */
17
+ readonly scores: Readonly<Record<string, number>>;
18
+ }
19
+ /**
20
+ * Game ended in a draw.
21
+ */
22
+ export interface GameFinishedDraw {
23
+ readonly kind: 'draw';
24
+ /** Final scores keyed by player id. */
25
+ readonly scores: Readonly<Record<string, number>>;
26
+ }
27
+ /**
28
+ * Game was aborted before reaching a normal terminal state
29
+ * (e.g. a player left, network failure, server shutdown).
30
+ */
31
+ export interface GameFinishedAborted {
32
+ readonly kind: 'aborted';
33
+ /** Human-readable reason describing why the game was aborted. */
34
+ readonly reason: string;
35
+ }
36
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAC1B,eAAe,GACf,gBAAgB,GAChB,mBAAmB,CAAC;AAEvB;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAErB,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAClD;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAEzB,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB"}
package/dist/events.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ export * from './session';
2
+ export * from './events';
3
+ export * from './platform-bridge';
4
+ export * from './version';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,mBAAmB,CAAC;AAClC,cAAc,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './session';
2
+ export * from './events';
3
+ export * from './platform-bridge';
4
+ export * from './version';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Global bridge for cross-cutting platform services (e.g. authentication)
3
+ * exposed by the shell. Available inside the game via `window.__PLATFORM__`.
4
+ *
5
+ * The game does not store the auth token itself. Each request calls
6
+ * {@link PlatformBridge.getToken} to obtain the freshest value, and subscribes
7
+ * to {@link PlatformBridge.onTokenChange} for proactive updates.
8
+ */
9
+ export interface PlatformBridge {
10
+ /**
11
+ * Returns the current JWT token. The shell is responsible for refreshing
12
+ * the token before expiry, so the value returned here is always fresh.
13
+ */
14
+ getToken(): string;
15
+ /**
16
+ * Subscribes to token updates (e.g. to reconnect a WebSocket with the new
17
+ * token). Returns an unsubscribe function.
18
+ */
19
+ onTokenChange(callback: (newToken: string) => void): () => void;
20
+ /**
21
+ * Subscribes to logout events. The game must close its WebSocket and
22
+ * emit a `leave` event when this fires. Returns an unsubscribe function.
23
+ */
24
+ onLogout(callback: () => void): () => void;
25
+ }
26
+ declare global {
27
+ interface Window {
28
+ /**
29
+ * Platform bridge installed by the shell before any game is mounted.
30
+ * Always present in production; games may assume it is non-null.
31
+ */
32
+ readonly __PLATFORM__: PlatformBridge;
33
+ }
34
+ }
35
+ //# sourceMappingURL=platform-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-bridge.d.ts","sourceRoot":"","sources":["../src/platform-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,QAAQ,IAAI,MAAM,CAAC;IAEnB;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAEhE;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC3C;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf;;;WAGG;QACH,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC;KACtC;CACD"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Game session context that the shell passes into the game via the property
3
+ * setter on its Custom Element. The game uses this object as the single source
4
+ * of truth about the current session.
5
+ */
6
+ export interface GameSessionContext {
7
+ /** Unique session identifier the game uses when calling the Game Server. */
8
+ readonly sessionId: string;
9
+ /** WebSocket URL of the Game Server for real-time communication. */
10
+ readonly serverUrl: string;
11
+ /** Current user locale (BCP 47 code, e.g. 'uk', 'en'). */
12
+ readonly locale: string;
13
+ /** The current user — the one playing on this client. */
14
+ readonly currentUser: CurrentUser;
15
+ /** All players in the session, including the current user. */
16
+ readonly players: ReadonlyArray<SessionPlayer>;
17
+ }
18
+ /**
19
+ * The current user (the one viewing the game in the browser).
20
+ */
21
+ export interface CurrentUser {
22
+ /** Stable user identifier issued by the platform. */
23
+ readonly id: string;
24
+ /** Display name shown in the UI. */
25
+ readonly displayName: string;
26
+ }
27
+ /**
28
+ * Information about a single player participating in the session.
29
+ */
30
+ export interface SessionPlayer {
31
+ /** Stable user identifier issued by the platform. */
32
+ readonly userId: string;
33
+ /** Display name shown in the UI. */
34
+ readonly displayName: string;
35
+ /** Avatar image URL, or `null` if the player has no avatar. */
36
+ readonly avatarUrl: string | null;
37
+ }
38
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,oEAAoE;IACpE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAElC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,qDAAqD;IACrD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAEpB,oCAAoC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC7B,qDAAqD;IACrD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,oCAAoC;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Contract version. MUST stay in sync with the `version` field of
3
+ * `package.json` — this is enforced by `scripts/sync-version.cjs` via the
4
+ * `npm version` hook.
5
+ *
6
+ * The game exports this constant as the `data-contract-version` attribute on
7
+ * its Custom Element, and the shell verifies major-version compatibility
8
+ * before mounting the game.
9
+ */
10
+ export declare const CONTRACT_VERSION = "0.0.1";
11
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,UAAU,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Contract version. MUST stay in sync with the `version` field of
3
+ * `package.json` — this is enforced by `scripts/sync-version.cjs` via the
4
+ * `npm version` hook.
5
+ *
6
+ * The game exports this constant as the `data-contract-version` attribute on
7
+ * its Custom Element, and the shell verifies major-version compatibility
8
+ * before mounting the game.
9
+ */
10
+ export const CONTRACT_VERSION = '0.0.1';
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@tableverse/contracts",
3
+ "version": "0.0.1",
4
+ "description": "TypeScript contracts for the Table Verse game platform",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "README.uk.md",
13
+ "CHANGELOG.md"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "scripts": {
19
+ "build": "tsc -p tsconfig.build.json",
20
+ "lint": "eslint src --ext .ts",
21
+ "test": "tsc -p tests/tsconfig.json --noEmit",
22
+ "version": "node scripts/sync-version.cjs && git add src/version.ts",
23
+ "prepublishOnly": "npm run lint && npm run test && npm run build"
24
+ },
25
+ "keywords": [
26
+ "contracts",
27
+ "types",
28
+ "platform",
29
+ "tableverse"
30
+ ],
31
+ "author": "Table Verse",
32
+ "license": "MIT",
33
+ "devDependencies": {
34
+ "@types/node": "^25.6.0",
35
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
36
+ "@typescript-eslint/parser": "^8.0.0",
37
+ "eslint": "^10.0.0",
38
+ "typescript": "^6.0.3"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/TableVerse/contracts.git"
43
+ },
44
+ "engines": {
45
+ "node": ">=20"
46
+ }
47
+ }