@hadoku/prefs-client 1.1.3 → 1.1.4

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/README.md CHANGED
@@ -97,6 +97,28 @@ const client = createPrefsClient({
97
97
  });
98
98
  ```
99
99
 
100
+ ## Platform rows (`@wolffm/prefs-client/platform`)
101
+
102
+ Rows that belong to no single app. Import the definition rather than retyping the appId,
103
+ scope and schema, so the second app to need a setting finds the first one's row instead of
104
+ inventing its own.
105
+
106
+ | Row | Fields | Scope | Owner |
107
+ | --------------------- | ------------------------ | ------ | ---------------------------------------------------------- |
108
+ | `games` (`GAMES_ROW`) | `muted`, `volume` (0..1) | device | every hadoku game: master sound, above a game's own levels |
109
+ | `portfolio` | `theme` | device | `@wolffm/themes`; do not write it from an app |
110
+
111
+ ```ts
112
+ import { createPrefsClient } from '@wolffm/prefs-client';
113
+ import { GAMES_ROW, GAMES_DEFAULTS } from '@wolffm/prefs-client/platform';
114
+
115
+ const games = createPrefsClient({ ...GAMES_ROW, defaults: GAMES_DEFAULTS });
116
+ await games.save({ muted: true }, { scope: GAMES_ROW.scope });
117
+ ```
118
+
119
+ The profile picture is not a row here: it is `./avatar` below, whose fallback is the
120
+ watchparty character.
121
+
100
122
  ## Avatars (`@wolffm/prefs-client/avatar`)
101
123
 
102
124
  One resolved avatar per hadoku user, chosen by the user at `hadoku.me/account`.
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Platform rows — prefs rows that belong to no single app, so every app that
5
+ * reads or writes one imports its definition from here rather than retyping
6
+ * the appId, the scope and the schema.
7
+ *
8
+ * A row here is only a NAME and a SHAPE: prefs-api accepts any `[a-z0-9-]+`
9
+ * appId and stores the blob as given, so nothing server-side changes when one
10
+ * is added. What this file stops is the second app inventing its own row for
11
+ * the same setting (bomberman's `bomberman.volume` in localStorage beside
12
+ * cardtable's `games` row, 2026-10-30).
13
+ *
14
+ * Not here, and why:
15
+ * - Theme (`portfolio`, device scope) is owned by `@wolffm/themes`, which
16
+ * renders the picker for every app.
17
+ * - The profile picture is `./avatar`: one resolved avatar per user, whose
18
+ * fallback is the watchparty character read from the `watchparty` row.
19
+ *
20
+ * Usage:
21
+ * createPrefsClient({ ...GAMES_ROW, defaults: GAMES_DEFAULTS })
22
+ * prefs.save({ volume: 0.4 }, { scope: GAMES_ROW.scope })
23
+ */
24
+
25
+ /**
26
+ * Master sound for every hadoku game. Device scope: the right volume belongs
27
+ * to the speakers, not the account. A game's own levels (music, effects) stay
28
+ * in its own row; these two sit above them.
29
+ */
30
+ declare const GAMES_ROW: {
31
+ readonly appId: "games";
32
+ readonly scope: "device";
33
+ readonly schema: z.ZodObject<{
34
+ muted: z.ZodOptional<z.ZodBoolean>;
35
+ volume: z.ZodOptional<z.ZodNumber>;
36
+ }, z.core.$strip>;
37
+ };
38
+ type GamesPrefs = z.infer<typeof GAMES_ROW.schema>;
39
+ declare const GAMES_DEFAULTS: Required<GamesPrefs>;
40
+
41
+ export { GAMES_DEFAULTS, GAMES_ROW, type GamesPrefs };
@@ -0,0 +1,17 @@
1
+ // src/platform.ts
2
+ import { z } from "zod";
3
+ var GAMES_ROW = {
4
+ appId: "games",
5
+ scope: "device",
6
+ schema: z.object({
7
+ /** Silences the game entirely; `volume` is kept for when it is unmuted. */
8
+ muted: z.boolean().optional(),
9
+ /** Master volume, 0 (silent) to 1 (full). */
10
+ volume: z.number().min(0).max(1).optional()
11
+ })
12
+ };
13
+ var GAMES_DEFAULTS = { muted: false, volume: 1 };
14
+ export {
15
+ GAMES_DEFAULTS,
16
+ GAMES_ROW
17
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hadoku/prefs-client",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "Client SDK for the hadoku unified preferences store. Wraps /prefs/api/v1/* with localStorage caching, debounced writes, Zod-validated reads, and a usePrefs() React hook, plus match history, ratings and leaderboards for every game (./games), and the one resolved avatar per user (./avatar).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,6 +18,10 @@
18
18
  "types": "./dist/games.d.ts",
19
19
  "default": "./dist/games.js"
20
20
  },
21
+ "./platform": {
22
+ "types": "./dist/platform.d.ts",
23
+ "default": "./dist/platform.js"
24
+ },
21
25
  "./avatar": {
22
26
  "types": "./dist/avatar.d.ts",
23
27
  "default": "./dist/avatar.js"