@rydr/game-sdk 1.7.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.
Files changed (82) hide show
  1. package/README.md +220 -0
  2. package/dist/client/HardwareStore.d.ts +40 -0
  3. package/dist/client/HardwareStore.d.ts.map +1 -0
  4. package/dist/client/HardwareStore.js +36 -0
  5. package/dist/client/HardwareStore.js.map +1 -0
  6. package/dist/client/PlatformClient.d.ts +182 -0
  7. package/dist/client/PlatformClient.d.ts.map +1 -0
  8. package/dist/client/PlatformClient.js +374 -0
  9. package/dist/client/PlatformClient.js.map +1 -0
  10. package/dist/client/Room.d.ts +127 -0
  11. package/dist/client/Room.d.ts.map +1 -0
  12. package/dist/client/Room.js +235 -0
  13. package/dist/client/Room.js.map +1 -0
  14. package/dist/client/adminContent.d.ts +65 -0
  15. package/dist/client/adminContent.d.ts.map +1 -0
  16. package/dist/client/adminContent.js +75 -0
  17. package/dist/client/adminContent.js.map +1 -0
  18. package/dist/client/index.d.ts +7 -0
  19. package/dist/client/index.d.ts.map +1 -0
  20. package/dist/client/index.js +7 -0
  21. package/dist/client/index.js.map +1 -0
  22. package/dist/client/replayCodec.d.ts +27 -0
  23. package/dist/client/replayCodec.d.ts.map +1 -0
  24. package/dist/client/replayCodec.js +74 -0
  25. package/dist/client/replayCodec.js.map +1 -0
  26. package/dist/host/PlatformHost.d.ts +169 -0
  27. package/dist/host/PlatformHost.d.ts.map +1 -0
  28. package/dist/host/PlatformHost.js +248 -0
  29. package/dist/host/PlatformHost.js.map +1 -0
  30. package/dist/host/index.d.ts +3 -0
  31. package/dist/host/index.d.ts.map +1 -0
  32. package/dist/host/index.js +3 -0
  33. package/dist/host/index.js.map +1 -0
  34. package/dist/index.d.ts +12 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +12 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/protocol/boards.d.ts +61 -0
  39. package/dist/protocol/boards.d.ts.map +1 -0
  40. package/dist/protocol/boards.js +53 -0
  41. package/dist/protocol/boards.js.map +1 -0
  42. package/dist/protocol/buttons.d.ts +13 -0
  43. package/dist/protocol/buttons.d.ts.map +1 -0
  44. package/dist/protocol/buttons.js +2 -0
  45. package/dist/protocol/buttons.js.map +1 -0
  46. package/dist/protocol/capabilities.d.ts +23 -0
  47. package/dist/protocol/capabilities.d.ts.map +1 -0
  48. package/dist/protocol/capabilities.js +10 -0
  49. package/dist/protocol/capabilities.js.map +1 -0
  50. package/dist/protocol/gamedata.d.ts +23 -0
  51. package/dist/protocol/gamedata.d.ts.map +1 -0
  52. package/dist/protocol/gamedata.js +2 -0
  53. package/dist/protocol/gamedata.js.map +1 -0
  54. package/dist/protocol/guards.d.ts +15 -0
  55. package/dist/protocol/guards.d.ts.map +1 -0
  56. package/dist/protocol/guards.js +45 -0
  57. package/dist/protocol/guards.js.map +1 -0
  58. package/dist/protocol/identity.d.ts +21 -0
  59. package/dist/protocol/identity.d.ts.map +1 -0
  60. package/dist/protocol/identity.js +2 -0
  61. package/dist/protocol/identity.js.map +1 -0
  62. package/dist/protocol/index.d.ts +12 -0
  63. package/dist/protocol/index.d.ts.map +1 -0
  64. package/dist/protocol/index.js +12 -0
  65. package/dist/protocol/index.js.map +1 -0
  66. package/dist/protocol/messages.d.ts +407 -0
  67. package/dist/protocol/messages.d.ts.map +1 -0
  68. package/dist/protocol/messages.js +2 -0
  69. package/dist/protocol/messages.js.map +1 -0
  70. package/dist/protocol/replays.d.ts +67 -0
  71. package/dist/protocol/replays.d.ts.map +1 -0
  72. package/dist/protocol/replays.js +14 -0
  73. package/dist/protocol/replays.js.map +1 -0
  74. package/dist/protocol/room.d.ts +55 -0
  75. package/dist/protocol/room.d.ts.map +1 -0
  76. package/dist/protocol/room.js +13 -0
  77. package/dist/protocol/room.js.map +1 -0
  78. package/dist/protocol/version.d.ts +12 -0
  79. package/dist/protocol/version.d.ts.map +1 -0
  80. package/dist/protocol/version.js +12 -0
  81. package/dist/protocol/version.js.map +1 -0
  82. package/package.json +37 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/protocol/messages.ts"],"names":[],"mappings":""}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Replay/ghost types — the frame contract, the decoded body, the derived display meta, and the
3
+ * `session.getReplays(boardId)` result shape.
4
+ *
5
+ * A replay is an array of {@link ReplayFrame} the game saves with {@link PlatformSession.saveReplay}
6
+ * keyed by the session's `runId`. The SDK encodes the frames into a compressed blob and derives a
7
+ * {@link ReplayMeta} summary stored alongside it. Replays align to leaderboard standings through the
8
+ * shared `runId`: the `boards` party stamps `runId` on each entry, so "the ghosts for the top-N" is
9
+ * the leaderboard's top-N entries' replays. `getReplays` composes that — it reads the leaderboard
10
+ * page, then fetches each ranked entry's blob + meta — returning one {@link ReplayRef} per ranked
11
+ * entry; decode a specific one's frames with `getReplay`/`decodeReplay`.
12
+ */
13
+ /**
14
+ * One replay frame. A replay is an array of these — the time-series a game interpolates over to
15
+ * render a ghost. `t` and `power` are MANDATORY and platform-readable (so the timeline + power of
16
+ * any replay are legible without understanding the game); `customData` is the game's own opaque
17
+ * per-frame payload. Frames need not be evenly spaced — timing lives entirely in `t`, so there is
18
+ * no global sample rate / frame count to drift out of sync.
19
+ */
20
+ export interface ReplayFrame {
21
+ /** Elapsed time from replay start, in ms. */
22
+ t: number;
23
+ /** Instantaneous power, in watts. */
24
+ power: number;
25
+ /** Game-specific per-frame payload (position, lean, animation…). Opaque to the platform. */
26
+ customData?: unknown;
27
+ }
28
+ /**
29
+ * The decoded body of a replay blob: a versioned array of {@link ReplayFrame}. `version` lets a
30
+ * game evolve its frame/`customData` shape and still recognise (or reject) older replays.
31
+ * Produced/consumed by `encodeReplay`/`decodeReplay`.
32
+ */
33
+ export interface ReplayBody {
34
+ version: number;
35
+ frames: ReplayFrame[];
36
+ }
37
+ /**
38
+ * A small, platform-visible summary of a replay, DERIVED from its frames at save time. Lets a
39
+ * ghost/replay list render (length + power) without fetching and decompressing every blob.
40
+ *
41
+ * Who/score/when are intentionally NOT here — they live on the leaderboard entry sharing the same
42
+ * `runId` (`displayName`/`value`/`ts`). Meta only adds what the timeline itself knows.
43
+ */
44
+ export interface ReplayMeta {
45
+ /** Total replay length in ms (the last frame's `t`). */
46
+ durationMs: number;
47
+ /** Mean of every frame's `power`, in watts. */
48
+ avgPower: number;
49
+ /** Peak frame `power`, in watts. */
50
+ maxPower: number;
51
+ }
52
+ /** One ranked leaderboard entry paired with its stored replay (if any). */
53
+ export interface ReplayRef {
54
+ /** The run this replay/entry came from. */
55
+ runId: string;
56
+ /** 1-based rank on the board this came from. */
57
+ rank: number;
58
+ /** The entry's display name (for labelling the ghost). */
59
+ displayName: string;
60
+ /** The entry's board value (e.g. lap time in ms). */
61
+ value: number;
62
+ /** The opaque replay blob (base64), or `null` if no replay was stored for this run. */
63
+ blob: string | null;
64
+ /** Derived display summary of the replay, or `null` when no replay/meta was stored. */
65
+ meta: ReplayMeta | null;
66
+ }
67
+ //# sourceMappingURL=replays.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replays.d.ts","sourceRoot":"","sources":["../../src/protocol/replays.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,CAAC,EAAE,MAAM,CAAC;IACV,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,4FAA4F;IAC5F,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,2EAA2E;AAC3E,MAAM,WAAW,SAAS;IACxB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,uFAAuF;IACvF,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Replay/ghost types — the frame contract, the decoded body, the derived display meta, and the
3
+ * `session.getReplays(boardId)` result shape.
4
+ *
5
+ * A replay is an array of {@link ReplayFrame} the game saves with {@link PlatformSession.saveReplay}
6
+ * keyed by the session's `runId`. The SDK encodes the frames into a compressed blob and derives a
7
+ * {@link ReplayMeta} summary stored alongside it. Replays align to leaderboard standings through the
8
+ * shared `runId`: the `boards` party stamps `runId` on each entry, so "the ghosts for the top-N" is
9
+ * the leaderboard's top-N entries' replays. `getReplays` composes that — it reads the leaderboard
10
+ * page, then fetches each ranked entry's blob + meta — returning one {@link ReplayRef} per ranked
11
+ * entry; decode a specific one's frames with `getReplay`/`decodeReplay`.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=replays.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replays.js","sourceRoot":"","sources":["../../src/protocol/replays.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Realtime room types — the shell-vouched fields shared by every room, kept separate from the
3
+ * opaque game payloads (mirrors how {@link ReplayMeta} sits beside the opaque replay blob).
4
+ *
5
+ * A room carries three kinds of traffic over one shell-owned connection:
6
+ * - **presence** — who's here ({@link RoomMember}); shell-stamped identity.
7
+ * - **telemetry** — each member's live, real hardware reading ({@link RoomTelemetry}); injected by
8
+ * the shell that owns the hardware, so it can't be forged by a game. The mandatory, typed part.
9
+ * - **message / state** — the game's own opaque payloads (`send`/`setState`); the platform never
10
+ * parses them. The blob part.
11
+ */
12
+ /** A player present in a room. Identity is shell-stamped; `name` is the public display name. */
13
+ export interface RoomMember {
14
+ playerId: string;
15
+ name?: string;
16
+ }
17
+ /**
18
+ * A trusted, live hardware reading for one room member, broadcast by that member's shell. Raw
19
+ * measured signals only — speed/position is a game-computed output and belongs in the opaque
20
+ * `send`/`state` payloads, not here. Fields are optional because a given sample may carry only
21
+ * some of them (e.g. an HRM update with no power).
22
+ */
23
+ export interface RoomTelemetry {
24
+ /** The member this reading belongs to (server-stamped — never self-reported). */
25
+ playerId: string;
26
+ /** Instantaneous power, in watts. */
27
+ power?: number;
28
+ /** Pedalling cadence, in rpm. */
29
+ cadence?: number;
30
+ /** Heart rate, in bpm. */
31
+ heartRate?: number;
32
+ /** ms timestamp from the originating shell's clock. */
33
+ t: number;
34
+ }
35
+ /**
36
+ * A server-stamped, genre-neutral orchestration event — the "referee whistle" / match clock. A
37
+ * member schedules one (`room.scheduleEvent`); the server stamps it on a shared clock and broadcasts
38
+ * it to everyone, so all clients act on the same wall-clock instant with no host head start.
39
+ *
40
+ * The room knows nothing about what `name` means — a game's host-run orchestrator gives it meaning
41
+ * (a race uses `"start"`/`"grace"`/`"advance"`/`"finished"`; a match could use `"point"`/`"set"`).
42
+ * Timing-sensitive events carry a future `at`; clients self-schedule against their skew-corrected
43
+ * clock until then (the server runs no timers).
44
+ */
45
+ export interface RoomEvent {
46
+ /** Game-defined event name. Opaque to the platform. */
47
+ name: string;
48
+ /** Game-defined opaque payload. */
49
+ payload: unknown;
50
+ /** Server-stamped wall-clock time (ms) to act on. Immediate events: ≈ broadcast time. */
51
+ at: number;
52
+ /** playerId that scheduled it (server-stamped — never the message body). */
53
+ from: string;
54
+ }
55
+ //# sourceMappingURL=room.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room.d.ts","sourceRoot":"","sources":["../../src/protocol/room.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gGAAgG;AAChG,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,CAAC,EAAE,MAAM,CAAC;CACX;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,SAAS;IACxB,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,EAAE,EAAE,MAAM,CAAC;IACX,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Realtime room types — the shell-vouched fields shared by every room, kept separate from the
3
+ * opaque game payloads (mirrors how {@link ReplayMeta} sits beside the opaque replay blob).
4
+ *
5
+ * A room carries three kinds of traffic over one shell-owned connection:
6
+ * - **presence** — who's here ({@link RoomMember}); shell-stamped identity.
7
+ * - **telemetry** — each member's live, real hardware reading ({@link RoomTelemetry}); injected by
8
+ * the shell that owns the hardware, so it can't be forged by a game. The mandatory, typed part.
9
+ * - **message / state** — the game's own opaque payloads (`send`/`setState`); the platform never
10
+ * parses them. The blob part.
11
+ */
12
+ export {};
13
+ //# sourceMappingURL=room.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"room.js","sourceRoot":"","sources":["../../src/protocol/room.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Wire-protocol version of the platform↔game boundary.
3
+ *
4
+ * Bumped only for protocol-shape changes. The platform shell advertises a
5
+ * supported range and up-converts older messages via an adapter, so a game
6
+ * built against an older protocol keeps working. Evolve the protocol
7
+ * ADDITIVELY — never change or remove an existing message shape.
8
+ */
9
+ export declare const RYDR_PROTOCOL_VERSION: 2;
10
+ /** Semver of this SDK build. Sent in the handshake for telemetry/debugging. */
11
+ export declare const RYDR_SDK_VERSION = "1.7.0";
12
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/protocol/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,EAAG,CAAU,CAAC;AAEhD,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB,UAAU,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Wire-protocol version of the platform↔game boundary.
3
+ *
4
+ * Bumped only for protocol-shape changes. The platform shell advertises a
5
+ * supported range and up-converts older messages via an adapter, so a game
6
+ * built against an older protocol keeps working. Evolve the protocol
7
+ * ADDITIVELY — never change or remove an existing message shape.
8
+ */
9
+ export const RYDR_PROTOCOL_VERSION = 2;
10
+ /** Semver of this SDK build. Sent in the handshake for telemetry/debugging. */
11
+ export const RYDR_SDK_VERSION = "1.7.0";
12
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/protocol/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAU,CAAC;AAEhD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@rydr/game-sdk",
3
+ "version": "1.7.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/bdefrenne/rydr-game-sdk.git"
7
+ },
8
+ "description": "Client SDK for building games on the RYDR indoor-cycling platform: the typed platform↔game wire protocol, a bridged hardware hook, RYDR UI components/tokens, and a local dev harness.",
9
+ "license": "UNLICENSED",
10
+ "type": "module",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
19
+ },
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "prepare": "tsc -p tsconfig.json",
28
+ "dev": "tsc -w -p tsconfig.json",
29
+ "clean": "rm -rf dist",
30
+ "typecheck": "tsc --noEmit -p tsconfig.json",
31
+ "version": "node scripts/sync-version.mjs && git add src/protocol/version.ts",
32
+ "postversion": "git push --follow-tags"
33
+ },
34
+ "devDependencies": {
35
+ "typescript": "^5.5.0"
36
+ }
37
+ }