@datamoc/mw_games 0.4.2 → 0.4.3

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 (80) hide show
  1. package/README.md +1 -1
  2. package/dist/actors/ItemStatusEffect.d.ts +1 -1
  3. package/dist/actors/ItemStatusEffect.d.ts.map +1 -1
  4. package/dist/actors/ItemStatusEffect.js +2 -11
  5. package/dist/actors/ItemStatusEffect.js.map +1 -1
  6. package/dist/actors/StatusEffect.d.ts +11 -0
  7. package/dist/actors/StatusEffect.d.ts.map +1 -1
  8. package/dist/actors/StatusEffect.js +21 -8
  9. package/dist/actors/StatusEffect.js.map +1 -1
  10. package/dist/core/HttpTransport.d.ts +1 -1
  11. package/dist/core/HttpTransport.js +1 -1
  12. package/dist/core/News.d.ts +6 -13
  13. package/dist/core/News.d.ts.map +1 -1
  14. package/dist/core/News.js +10 -23
  15. package/dist/core/News.js.map +1 -1
  16. package/dist/core/RunHistory.d.ts +1 -2
  17. package/dist/core/RunHistory.d.ts.map +1 -1
  18. package/dist/core/RunHistory.js +5 -6
  19. package/dist/core/RunHistory.js.map +1 -1
  20. package/dist/core/Stats.d.ts +1 -2
  21. package/dist/core/Stats.d.ts.map +1 -1
  22. package/dist/core/Stats.js +5 -6
  23. package/dist/core/Stats.js.map +1 -1
  24. package/dist/core/StoredValue.d.ts +21 -0
  25. package/dist/core/StoredValue.d.ts.map +1 -0
  26. package/dist/core/StoredValue.js +28 -0
  27. package/dist/core/StoredValue.js.map +1 -0
  28. package/dist/mw_games.global.js +90 -90
  29. package/dist/roguelike/Level.d.ts +10 -0
  30. package/dist/roguelike/Level.d.ts.map +1 -1
  31. package/dist/roguelike/Level.js +57 -17
  32. package/dist/roguelike/Level.js.map +1 -1
  33. package/dist/roguelike/Pathfinder.js +19 -19
  34. package/dist/roguelike/Pathfinder.js.map +1 -1
  35. package/dist/roguelike/Placement.d.ts +1 -1
  36. package/dist/roguelike/Placement.d.ts.map +1 -1
  37. package/dist/roguelike/Placement.js +5 -5
  38. package/dist/roguelike/Placement.js.map +1 -1
  39. package/dist/rpg/FreeMover.d.ts +1 -1
  40. package/dist/rpg/FreeMover.d.ts.map +1 -1
  41. package/dist/rpg/FreeMover.js +3 -6
  42. package/dist/rpg/FreeMover.js.map +1 -1
  43. package/dist/rpg/GridMover.d.ts +1 -1
  44. package/dist/rpg/GridMover.d.ts.map +1 -1
  45. package/dist/rpg/GridMover.js +3 -6
  46. package/dist/rpg/GridMover.js.map +1 -1
  47. package/dist/rpg/MovableSprite.d.ts +6 -0
  48. package/dist/rpg/MovableSprite.d.ts.map +1 -1
  49. package/dist/rpg/MovableSprite.js +9 -1
  50. package/dist/rpg/MovableSprite.js.map +1 -1
  51. package/dist/two-d/ui/BitmapLabel.d.ts +3 -9
  52. package/dist/two-d/ui/BitmapLabel.d.ts.map +1 -1
  53. package/dist/two-d/ui/BitmapLabel.js +3 -2
  54. package/dist/two-d/ui/BitmapLabel.js.map +1 -1
  55. package/dist/two-d/ui/IconGrid.d.ts +2 -3
  56. package/dist/two-d/ui/IconGrid.d.ts.map +1 -1
  57. package/dist/two-d/ui/IconGrid.js +34 -50
  58. package/dist/two-d/ui/IconGrid.js.map +1 -1
  59. package/dist/two-d/ui/Label.d.ts +2 -8
  60. package/dist/two-d/ui/Label.d.ts.map +1 -1
  61. package/dist/two-d/ui/Label.js +4 -3
  62. package/dist/two-d/ui/Label.js.map +1 -1
  63. package/dist/two-d/ui/ListView.d.ts +3 -4
  64. package/dist/two-d/ui/ListView.d.ts.map +1 -1
  65. package/dist/two-d/ui/ListView.js +25 -43
  66. package/dist/two-d/ui/ListView.js.map +1 -1
  67. package/dist/two-d/ui/SelectionModel.d.ts +50 -0
  68. package/dist/two-d/ui/SelectionModel.d.ts.map +1 -0
  69. package/dist/two-d/ui/SelectionModel.js +73 -0
  70. package/dist/two-d/ui/SelectionModel.js.map +1 -0
  71. package/dist/two-d/ui/themedText.d.ts +20 -0
  72. package/dist/two-d/ui/themedText.d.ts.map +1 -0
  73. package/dist/two-d/ui/themedText.js +9 -0
  74. package/dist/two-d/ui/themedText.js.map +1 -0
  75. package/dist/version.d.ts +1 -1
  76. package/dist/version.js +1 -1
  77. package/package.json +4 -1
  78. package/tools/compile-resources.mjs +1 -1
  79. package/tools/compress-dist.d.mts +16 -0
  80. package/tools/compress-dist.mjs +116 -0
package/README.md CHANGED
@@ -11,7 +11,7 @@ of their own; improvements to `mwg`'s own files are shared back.
11
11
  **[Live examples and API docs](https://datamoc.github.io/mwg/)**: every example below,
12
12
  playable in the browser with no download, plus the generated API reference.
13
13
 
14
- > **Status: early release (v0.4.1).** Every module in the shared floor below, plus optional
14
+ > **Status: early release (v0.4.3).** Every module in the shared floor below, plus optional
15
15
  > 3D, mobile (Capacitor) and desktop (WebView2) packaging, is built and tested - see
16
16
  > [ROADMAP.md](ROADMAP.md) for the full, numbered history.
17
17
  >
@@ -1,4 +1,4 @@
1
- import type { EffectClock } from './StatusEffect.ts';
1
+ import { type EffectClock } from './StatusEffect.ts';
2
2
  export interface ItemStatusEffectOptions<T> {
3
3
  /** fields applied to the item for the duration, restored to their prior value on expiry */
4
4
  fields: Partial<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"ItemStatusEffect.d.ts","sourceRoot":"","sources":["../../src/actors/ItemStatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACzC,2FAA2F;IAC3F,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IAEjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,sGAAsG;AACtG,MAAM,WAAW,sBAAsB;IACtC,MAAM,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACrD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,sBAAsB,CAuBxB"}
1
+ {"version":3,"file":"ItemStatusEffect.d.ts","sourceRoot":"","sources":["../../src/actors/ItemStatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAc,MAAM,mBAAmB,CAAC;AAEjE,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACzC,2FAA2F;IAC3F,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IAEnB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IAEjB,qFAAqF;IACrF,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,sGAAsG;AACtG,MAAM,WAAW,sBAAsB;IACtC,MAAM,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,MAAM,EACrD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,sBAAsB,CAYxB"}
@@ -1,3 +1,4 @@
1
+ import { leaseClock } from './StatusEffect.js';
1
2
  /**
2
3
  * A temporary status on an item itself - a weapon coated in poison for a fixed number of
3
4
  * turns, a shield reinforced until it wears off, a ring blessed only "for this floor" - the
@@ -33,16 +34,6 @@ export function applyItemStatusEffect(item, clock, options) {
33
34
  for (const [key, value] of previous)
34
35
  item[key] = value;
35
36
  };
36
- const id = clock.add({
37
- duration: options.duration,
38
- tick: (turn) => options.tick?.(turn),
39
- onExpire: restore,
40
- });
41
- return {
42
- cancel: () => {
43
- clock.remove(id);
44
- restore();
45
- },
46
- };
37
+ return leaseClock(clock, { duration: options.duration, tick: options.tick, onExpire: restore });
47
38
  }
48
39
  //# sourceMappingURL=ItemStatusEffect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ItemStatusEffect.js","sourceRoot":"","sources":["../../src/actors/ItemStatusEffect.ts"],"names":[],"mappings":"AAkBA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,qBAAqB,CACpC,IAAO,EACP,KAAkB,EAClB,OAAmC;IAEnC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAgB,EAAE,CAAC;QAC9D,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAe,CAAC;IAC/C,CAAC;IAED,MAAM,OAAO,GAAG,GAAS,EAAE;QAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACxD,CAAC,CAAC;IAEF,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;QACpC,QAAQ,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,OAAO;QACN,MAAM,EAAE,GAAG,EAAE;YACZ,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACjB,OAAO,EAAE,CAAC;QACX,CAAC;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"ItemStatusEffect.js","sourceRoot":"","sources":["../../src/actors/ItemStatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAkBjE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,qBAAqB,CACpC,IAAO,EACP,KAAkB,EAClB,OAAmC;IAEnC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAuB,CAAC;IAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAgB,EAAE,CAAC;QAC9D,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAe,CAAC;IAC/C,CAAC;IAED,MAAM,OAAO,GAAG,GAAS,EAAE;QAC1B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACxD,CAAC,CAAC;IAEF,OAAO,UAAU,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;AACjG,CAAC"}
@@ -24,6 +24,17 @@ export interface StatusEffectOptions {
24
24
  export interface StatusEffectHandle {
25
25
  cancel(): void;
26
26
  }
27
+ /**
28
+ * The half both `applyStatusEffect` and `applyItemStatusEffect` share: register `onExpire`
29
+ * with `clock` for `duration` turns, and hand back a `cancel()` that unregisters early and
30
+ * still runs `onExpire` once. Lives here rather than in a third file because this module
31
+ * already owns `EffectClock`, the only type it needs.
32
+ */
33
+ export declare function leaseClock(clock: EffectClock, options: {
34
+ duration: number;
35
+ tick?: (turn: number) => void;
36
+ onExpire: () => void;
37
+ }): StatusEffectHandle;
27
38
  /**
28
39
  * A temporary buff or debuff: applies `modifiers` to `stats` and registers their expiry with
29
40
  * `clock`, so a game never has to remember to remove what it added. The seam `TurnClock` and
@@ -1 +1 @@
1
- {"version":3,"file":"StatusEffect.d.ts","sourceRoot":"","sources":["../../src/actors/StatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,GAAG,MAAM,CAAC;IAChG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IACnC,8FAA8F;IAC9F,SAAS,EAAE,SAAS,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;IAE/C,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IAEjB,oFAAoF;IACpF,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,4FAA4F;AAC5F,MAAM,WAAW,kBAAkB;IAClC,MAAM,IAAI,IAAI,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,mBAAmB,GAC1B,kBAAkB,CAgBpB"}
1
+ {"version":3,"file":"StatusEffect.d.ts","sourceRoot":"","sources":["../../src/actors/StatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1D;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;KAAE,GAAG,MAAM,CAAC;IAChG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IACnC,8FAA8F;IAC9F,SAAS,EAAE,SAAS,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;IAE/C,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IAEjB,oFAAoF;IACpF,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,4FAA4F;AAC5F,MAAM,WAAW,kBAAkB;IAClC,MAAM,IAAI,IAAI,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CACzB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,GAChF,kBAAkB,CAapB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,iBAAiB,CAChC,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,mBAAmB,GAC1B,kBAAkB,CASpB"}
@@ -1,4 +1,23 @@
1
1
  import { StatBlock } from './StatBlock.js';
2
+ /**
3
+ * The half both `applyStatusEffect` and `applyItemStatusEffect` share: register `onExpire`
4
+ * with `clock` for `duration` turns, and hand back a `cancel()` that unregisters early and
5
+ * still runs `onExpire` once. Lives here rather than in a third file because this module
6
+ * already owns `EffectClock`, the only type it needs.
7
+ */
8
+ export function leaseClock(clock, options) {
9
+ const id = clock.add({
10
+ duration: options.duration,
11
+ tick: (turn) => options.tick?.(turn),
12
+ onExpire: options.onExpire,
13
+ });
14
+ return {
15
+ cancel: () => {
16
+ clock.remove(id);
17
+ options.onExpire();
18
+ },
19
+ };
20
+ }
2
21
  /**
3
22
  * A temporary buff or debuff: applies `modifiers` to `stats` and registers their expiry with
4
23
  * `clock`, so a game never has to remember to remove what it added. The seam `TurnClock` and
@@ -31,16 +50,10 @@ export function applyStatusEffect(stats, clock, options) {
31
50
  const source = Symbol('statusEffect');
32
51
  for (const modifier of options.modifiers)
33
52
  stats.addModifier({ ...modifier, source });
34
- const id = clock.add({
53
+ return leaseClock(clock, {
35
54
  duration: options.duration,
36
- tick: (turn) => options.tick?.(turn),
55
+ tick: options.tick,
37
56
  onExpire: () => stats.removeModifiersFrom(source),
38
57
  });
39
- return {
40
- cancel: () => {
41
- clock.remove(id);
42
- stats.removeModifiersFrom(source);
43
- },
44
- };
45
58
  }
46
59
  //# sourceMappingURL=StatusEffect.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StatusEffect.js","sourceRoot":"","sources":["../../src/actors/StatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAiB,MAAM,gBAAgB,CAAC;AA4B1D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,iBAAiB,CAChC,KAAgB,EAChB,KAAkB,EAClB,OAA4B;IAE5B,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACtC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS;QAAE,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAErF,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;QACpC,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC;KACjD,CAAC,CAAC;IAEH,OAAO;QACN,MAAM,EAAE,GAAG,EAAE;YACZ,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACjB,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"StatusEffect.js","sourceRoot":"","sources":["../../src/actors/StatusEffect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAiB,MAAM,gBAAgB,CAAC;AA4B1D;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CACzB,KAAkB,EAClB,OAAkF;IAElF,MAAM,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC;QACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC;QACpC,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC1B,CAAC,CAAC;IAEH,OAAO;QACN,MAAM,EAAE,GAAG,EAAE;YACZ,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACjB,OAAO,CAAC,QAAQ,EAAE,CAAC;QACpB,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,iBAAiB,CAChC,KAAgB,EAChB,KAAkB,EAClB,OAA4B;IAE5B,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;IACtC,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS;QAAE,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAErF,OAAO,UAAU,CAAC,KAAK,EAAE;QACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC;KACjD,CAAC,CAAC;AACJ,CAAC"}
@@ -5,7 +5,7 @@ export interface HttpTransportOptions {
5
5
  }
6
6
  /**
7
7
  * The constructor validation and timeout-wrapped fetch shared by every injectable HTTPS
8
- * transport here (`FeedbackClient`, `SaveSyncClient`, `TelemetryClient`) - each one is a
8
+ * transport here (`FeedbackClient`, `NewsClient`, `SaveSyncClient`, `TelemetryClient`) - each one is a
9
9
  * plain request/response against a game's own endpoint, differing only in what they send and
10
10
  * expect back, not in how the endpoint/timeout/fetch options are validated or how a request
11
11
  * is aborted after `timeoutMs`. `label` names the concrete client in its own error messages
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The constructor validation and timeout-wrapped fetch shared by every injectable HTTPS
3
- * transport here (`FeedbackClient`, `SaveSyncClient`, `TelemetryClient`) - each one is a
3
+ * transport here (`FeedbackClient`, `NewsClient`, `SaveSyncClient`, `TelemetryClient`) - each one is a
4
4
  * plain request/response against a game's own endpoint, differing only in what they send and
5
5
  * expect back, not in how the endpoint/timeout/fetch options are validated or how a request
6
6
  * is aborted after `timeoutMs`. `label` names the concrete client in its own error messages
@@ -1,8 +1,9 @@
1
1
  import { type SaveStorage } from './Save.ts';
2
+ import { HttpTransport, type HttpTransportOptions } from './HttpTransport.ts';
2
3
  /**
3
4
  * Fetches a game's own news/announcements feed - the inbound counterpart to
4
- * `FeedbackClient`, following the same injectable-transport shape (a game's own HTTPS
5
- * endpoint, no backend shipped or assumed) rather than a second pattern.
5
+ * `FeedbackClient`, built on the shared `HttpTransport` like every other client here
6
+ * (a game's own HTTPS endpoint, no backend shipped or assumed).
6
7
  *
7
8
  * @example
8
9
  * ```ts
@@ -22,15 +23,8 @@ export interface NewsItem {
22
23
  body: string;
23
24
  publishedAt?: number;
24
25
  }
25
- export interface NewsOptions {
26
- endpoint: string;
27
- timeoutMs?: number;
28
- fetch?: typeof globalThis.fetch;
29
- }
30
- export declare class NewsClient {
31
- private readonly endpoint;
32
- private readonly timeoutMs;
33
- private readonly fetchFn;
26
+ export type NewsOptions = HttpTransportOptions;
27
+ export declare class NewsClient extends HttpTransport {
34
28
  constructor(options: NewsOptions);
35
29
  /**
36
30
  * Fetches and validates the feed; a malformed item throws rather than reaching a game as
@@ -46,8 +40,7 @@ export interface NewsSeenOptions {
46
40
  }
47
41
  /** which news items a player has already dismissed, so a returning player is not shown the same announcement forever */
48
42
  export declare class NewsSeenTracker {
49
- private readonly storage;
50
- private readonly key;
43
+ private readonly store;
51
44
  constructor(options: NewsSeenOptions);
52
45
  private readSeen;
53
46
  isSeen(id: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"News.d.ts","sourceRoot":"","sources":["../../src/core/News.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7D;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CAChC;AAED,qBAAa,UAAU;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,YAAY,OAAO,EAAE,WAAW,EAO/B;IAED;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAYtC;CACD;AAgBD,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wHAAwH;AACxH,qBAAa,eAAe;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B,YAAY,OAAO,EAAE,eAAe,EAGnC;IAED,OAAO,CAAC,QAAQ;IAKhB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAIzB;IAED,uEAAuE;IACvE,MAAM,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAG7C;CACD"}
1
+ {"version":3,"file":"News.d.ts","sourceRoot":"","sources":["../../src/core/News.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE9E;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,QAAQ;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAE/C,qBAAa,UAAW,SAAQ,aAAa;IAC5C,YAAY,OAAO,EAAE,WAAW,EAE/B;IAED;;;;;OAKG;IACG,UAAU,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAQtC;CACD;AAgBD,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wHAAwH;AACxH,qBAAa,eAAe;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAE9C,YAAY,OAAO,EAAE,eAAe,EAKnC;IAED,OAAO,CAAC,QAAQ;IAIhB,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE1B;IAED,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAIzB;IAED,uEAAuE;IACvE,MAAM,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAG7C;CACD"}
package/dist/core/News.js CHANGED
@@ -1,16 +1,10 @@
1
1
  import { defaultStorage } from './Save.js';
2
2
  import { sanitizeInboundText } from './Sanitize.js';
3
- export class NewsClient {
3
+ import { StoredValue } from './StoredValue.js';
4
+ import { HttpTransport } from './HttpTransport.js';
5
+ export class NewsClient extends HttpTransport {
4
6
  constructor(options) {
5
- if (!options.endpoint)
6
- throw new Error('news endpoint is required');
7
- this.endpoint = options.endpoint;
8
- this.timeoutMs = options.timeoutMs ?? 10000;
9
- if (!(this.timeoutMs > 0))
10
- throw new Error('news timeout must be positive');
11
- this.fetchFn = options.fetch ?? globalThis.fetch;
12
- if (!this.fetchFn)
13
- throw new Error('fetch is unavailable; provide NewsOptions.fetch');
7
+ super(options, 'news');
14
8
  }
15
9
  /**
16
10
  * Fetches and validates the feed; a malformed item throws rather than reaching a game as
@@ -19,20 +13,15 @@ export class NewsClient {
19
13
  * `normalizeItem`'s own per-field shape check below.
20
14
  */
21
15
  async fetchItems() {
22
- const controller = new AbortController();
23
- const timer = setTimeout(() => controller.abort(), this.timeoutMs);
24
- try {
25
- const response = await this.fetchFn(this.endpoint, { signal: controller.signal });
16
+ return this.withTimeout(async (signal) => {
17
+ const response = await this.fetchFn(this.endpoint, { signal });
26
18
  if (!response.ok)
27
19
  throw new Error(`news request failed with HTTP ${response.status}`);
28
20
  const data = JSON.parse(sanitizeInboundText(await response.text()));
29
21
  if (!Array.isArray(data))
30
22
  throw new Error('news response was not an array');
31
23
  return data.map((raw, index) => normalizeItem(raw, index));
32
- }
33
- finally {
34
- clearTimeout(timer);
35
- }
24
+ });
36
25
  }
37
26
  }
38
27
  function normalizeItem(raw, index) {
@@ -55,12 +44,10 @@ function normalizeItem(raw, index) {
55
44
  /** which news items a player has already dismissed, so a returning player is not shown the same announcement forever */
56
45
  export class NewsSeenTracker {
57
46
  constructor(options) {
58
- this.storage = options.storage ?? defaultStorage();
59
- this.key = `mwg-news-seen:${options.namespace}`;
47
+ this.store = new StoredValue(options.storage ?? defaultStorage(), `mwg-news-seen:${options.namespace}`);
60
48
  }
61
49
  readSeen() {
62
- const raw = this.storage.read(this.key);
63
- return new Set(raw ? JSON.parse(raw) : []);
50
+ return new Set(this.store.read([]));
64
51
  }
65
52
  isSeen(id) {
66
53
  return this.readSeen().has(id);
@@ -68,7 +55,7 @@ export class NewsSeenTracker {
68
55
  markSeen(id) {
69
56
  const seen = this.readSeen();
70
57
  seen.add(id);
71
- this.storage.write(this.key, JSON.stringify([...seen]));
58
+ this.store.write([...seen]);
72
59
  }
73
60
  /** `items` filtered down to whichever have not been marked seen yet */
74
61
  unseen(items) {
@@ -1 +1 @@
1
- {"version":3,"file":"News.js","sourceRoot":"","sources":["../../src/core/News.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"News.js","sourceRoot":"","sources":["../../src/core/News.ts"],"names":[],"mappings":"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"}
@@ -34,9 +34,8 @@ export interface RunHistoryOptions {
34
34
  limit?: number;
35
35
  }
36
36
  export declare class RunHistory<T> {
37
- private readonly storage;
37
+ private readonly store;
38
38
  private readonly limit?;
39
- private readonly key;
40
39
  constructor(options: RunHistoryOptions);
41
40
  private readAll;
42
41
  /** appends a completed run's summary, oldest first; drops the oldest entry once `limit` is exceeded */
@@ -1 +1 @@
1
- {"version":3,"file":"RunHistory.d.ts","sourceRoot":"","sources":["../../src/core/RunHistory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IACjC,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,UAAU,CAAC,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B,YAAY,OAAO,EAAE,iBAAiB,EAIrC;IAED,OAAO,CAAC,OAAO;IAKf,uGAAuG;IACvG,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAOrC;IAED,uCAAuC;IACvC,GAAG,IAAI,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAEnC;IAED;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,EAAE,KAAK,GAAE,KAAK,GAAG,MAAe,GAAG,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAIhG;IAED,+BAA+B;IAC/B,KAAK,IAAI,IAAI,CAEZ;CACD"}
1
+ {"version":3,"file":"RunHistory.d.ts","sourceRoot":"","sources":["../../src/core/RunHistory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,CAAC;CACX;AAED,MAAM,WAAW,iBAAiB;IACjC,kFAAkF;IAClF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,UAAU,CAAC,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAEhC,YAAY,OAAO,EAAE,iBAAiB,EAMrC;IAED,OAAO,CAAC,OAAO;IAIf,uGAAuG;IACvG,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAOrC;IAED,uCAAuC;IACvC,GAAG,IAAI,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAEnC;IAED;;;;OAIG;IACH,MAAM,CAAC,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,EAAE,KAAK,GAAE,KAAK,GAAG,MAAe,GAAG,SAAS,eAAe,CAAC,CAAC,CAAC,EAAE,CAIhG;IAED,+BAA+B;IAC/B,KAAK,IAAI,IAAI,CAEZ;CACD"}
@@ -1,13 +1,12 @@
1
1
  import { defaultStorage } from './Save.js';
2
+ import { StoredValue } from './StoredValue.js';
2
3
  export class RunHistory {
3
4
  constructor(options) {
4
- this.storage = options.storage ?? defaultStorage();
5
+ this.store = new StoredValue(options.storage ?? defaultStorage(), `mwg-runs:${options.namespace}`);
5
6
  this.limit = options.limit;
6
- this.key = `mwg-runs:${options.namespace}`;
7
7
  }
8
8
  readAll() {
9
- const raw = this.storage.read(this.key);
10
- return raw ? JSON.parse(raw) : [];
9
+ return this.store.read([]);
11
10
  }
12
11
  /** appends a completed run's summary, oldest first; drops the oldest entry once `limit` is exceeded */
13
12
  record(summary) {
@@ -16,7 +15,7 @@ export class RunHistory {
16
15
  entries.push(entry);
17
16
  if (this.limit !== undefined && entries.length > this.limit)
18
17
  entries.splice(0, entries.length - this.limit);
19
- this.storage.write(this.key, JSON.stringify(entries));
18
+ this.store.write(entries);
20
19
  return entry;
21
20
  }
22
21
  /** every recorded run, oldest first */
@@ -35,7 +34,7 @@ export class RunHistory {
35
34
  }
36
35
  /** drops every recorded run */
37
36
  clear() {
38
- this.storage.remove(this.key);
37
+ this.store.remove();
39
38
  }
40
39
  }
41
40
  //# sourceMappingURL=RunHistory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RunHistory.js","sourceRoot":"","sources":["../../src/core/RunHistory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAoB,MAAM,WAAW,CAAC;AAsC7D,MAAM,OAAO,UAAU;IAKtB,YAAY,OAA0B;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;QACnD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,GAAG,GAAG,YAAY,OAAO,CAAC,SAAS,EAAE,CAAC;IAC5C,CAAC;IAEO,OAAO;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAA0B,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7D,CAAC;IAED,uGAAuG;IACvG,MAAM,CAAC,OAAU;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAuB,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC;QAC1G,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5G,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QACtD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,uCAAuC;IACvC,GAAG;QACF,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,EAA0B,EAAE,KAAK,GAAmB,MAAM;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,+BAA+B;IAC/B,KAAK;QACJ,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;CACD"}
1
+ {"version":3,"file":"RunHistory.js","sourceRoot":"","sources":["../../src/core/RunHistory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAoB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAsC/C,MAAM,OAAO,UAAU;IAItB,YAAY,OAA0B;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAC3B,OAAO,CAAC,OAAO,IAAI,cAAc,EAAE,EACnC,YAAY,OAAO,CAAC,SAAS,EAAE,CAC/B,CAAC;QACF,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC5B,CAAC;IAEO,OAAO;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,uGAAuG;IACvG,MAAM,CAAC,OAAU;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAuB,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC;QAC1G,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK;YAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5G,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC;IACd,CAAC;IAED,uCAAuC;IACvC,GAAG;QACF,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,EAA0B,EAAE,KAAK,GAAmB,MAAM;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,+BAA+B;IAC/B,KAAK;QACJ,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACrB,CAAC;CACD"}
@@ -32,8 +32,7 @@ export interface PlayerStatsOptions<T, S = T> {
32
32
  * ```
33
33
  */
34
34
  export declare class PlayerStats<T, S = T> {
35
- private readonly storage;
36
- private readonly key;
35
+ private readonly store;
37
36
  private readonly initial;
38
37
  private readonly combine;
39
38
  constructor(options: PlayerStatsOptions<T, S>);
@@ -1 +1 @@
1
- {"version":3,"file":"Stats.d.ts","sourceRoot":"","sources":["../../src/core/Stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7D,MAAM,WAAW,kBAAkB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;IAC3C,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,uDAAuD;IACvD,OAAO,EAAE,CAAC,CAAC;IACX,yDAAyD;IACzD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAI;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IAEtD,YAAY,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,EAK5C;IAED,6EAA6E;IAC7E,GAAG,IAAI,CAAC,CAGP;IAED,sFAAsF;IACtF,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAIpB;IAED,6EAA6E;IAC7E,KAAK,IAAI,IAAI,CAEZ;CACD"}
1
+ {"version":3,"file":"Stats.d.ts","sourceRoot":"","sources":["../../src/core/Stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7D,MAAM,WAAW,kBAAkB,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;IAC3C,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,uDAAuD;IACvD,OAAO,EAAE,CAAC,CAAC;IACX,yDAAyD;IACzD,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAI;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8B;IAEtD,YAAY,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,EAI5C;IAED,6EAA6E;IAC7E,GAAG,IAAI,CAAC,CAEP;IAED,sFAAsF;IACtF,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAIpB;IAED,6EAA6E;IAC7E,KAAK,IAAI,IAAI,CAEZ;CACD"}
@@ -1,4 +1,5 @@
1
1
  import { defaultStorage } from './Save.js';
2
+ import { StoredValue } from './StoredValue.js';
2
3
  /**
3
4
  * A lifetime running total, folded in one run at a time - distinct from `RunHistory`, which
4
5
  * keeps individual runs and may drop the oldest ones once its own `limit` is reached.
@@ -24,25 +25,23 @@ import { defaultStorage } from './Save.js';
24
25
  */
25
26
  export class PlayerStats {
26
27
  constructor(options) {
27
- this.storage = options.storage ?? defaultStorage();
28
- this.key = `mwg-stats:${options.namespace}`;
28
+ this.store = new StoredValue(options.storage ?? defaultStorage(), `mwg-stats:${options.namespace}`);
29
29
  this.initial = options.initial;
30
30
  this.combine = options.combine;
31
31
  }
32
32
  /** the current lifetime total, `initial` if nothing has been recorded yet */
33
33
  get() {
34
- const raw = this.storage.read(this.key);
35
- return raw ? JSON.parse(raw) : this.initial;
34
+ return this.store.read(this.initial);
36
35
  }
37
36
  /** folds `summary` into the running total and persists it, returning the new total */
38
37
  record(summary) {
39
38
  const next = this.combine(this.get(), summary);
40
- this.storage.write(this.key, JSON.stringify(next));
39
+ this.store.write(next);
41
40
  return next;
42
41
  }
43
42
  /** back to `initial`, as a new save file or a "reset stats" option should */
44
43
  reset() {
45
- this.storage.remove(this.key);
44
+ this.store.remove();
46
45
  }
47
46
  }
48
47
  //# sourceMappingURL=Stats.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Stats.js","sourceRoot":"","sources":["../../src/core/Stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAoB,MAAM,WAAW,CAAC;AAY7D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,WAAW;IAMvB,YAAY,OAAiC;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;QACnD,IAAI,CAAC,GAAG,GAAG,aAAa,OAAO,CAAC,SAAS,EAAE,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,6EAA6E;IAC7E,GAAG;QACF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;IACpD,CAAC;IAED,sFAAsF;IACtF,MAAM,CAAC,OAAU;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,6EAA6E;IAC7E,KAAK;QACJ,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;CACD"}
1
+ {"version":3,"file":"Stats.js","sourceRoot":"","sources":["../../src/core/Stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAoB,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAY/C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,OAAO,WAAW;IAKvB,YAAY,OAAiC;QAC5C,IAAI,CAAC,KAAK,GAAG,IAAI,WAAW,CAAI,OAAO,CAAC,OAAO,IAAI,cAAc,EAAE,EAAE,aAAa,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;QACvG,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,CAAC;IAED,6EAA6E;IAC7E,GAAG;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAED,sFAAsF;IACtF,MAAM,CAAC,OAAU;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,6EAA6E;IAC7E,KAAK;QACJ,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACrB,CAAC;CACD"}
@@ -0,0 +1,21 @@
1
+ import type { SaveStorage } from './Save.ts';
2
+ /**
3
+ * One JSON value under one storage key: the read-with-fallback / write / remove trio that
4
+ * `PlayerStats`, `RunHistory` and `NewsSeenTracker` each hand-rolled, with slightly
5
+ * different falsy-vs-null edges per copy. The one here treats any missing or empty read as
6
+ * absent (the `raw ? ... : fallback` rule two of the three already followed); corrupt JSON
7
+ * still throws, the same as before, since silently inventing a value would hide a real bug.
8
+ *
9
+ * Internal: multi-key shapes (`Collection`'s prefix scan, `SaveSystem`'s slots) do not fit
10
+ * it and keep their own code.
11
+ */
12
+ export declare class StoredValue<T> {
13
+ private readonly storage;
14
+ private readonly key;
15
+ constructor(storage: SaveStorage, key: string);
16
+ /** the stored value, or `fallback` when nothing has been written yet */
17
+ read(fallback: T): T;
18
+ write(value: T): void;
19
+ remove(): void;
20
+ }
21
+ //# sourceMappingURL=StoredValue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StoredValue.d.ts","sourceRoot":"","sources":["../../src/core/StoredValue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAE7C;;;;;;;;;GASG;AACH,qBAAa,WAAW,CAAC,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B,YAAY,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAG5C;IAED,wEAAwE;IACxE,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAGnB;IAED,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAEpB;IAED,MAAM,IAAI,IAAI,CAEb;CACD"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * One JSON value under one storage key: the read-with-fallback / write / remove trio that
3
+ * `PlayerStats`, `RunHistory` and `NewsSeenTracker` each hand-rolled, with slightly
4
+ * different falsy-vs-null edges per copy. The one here treats any missing or empty read as
5
+ * absent (the `raw ? ... : fallback` rule two of the three already followed); corrupt JSON
6
+ * still throws, the same as before, since silently inventing a value would hide a real bug.
7
+ *
8
+ * Internal: multi-key shapes (`Collection`'s prefix scan, `SaveSystem`'s slots) do not fit
9
+ * it and keep their own code.
10
+ */
11
+ export class StoredValue {
12
+ constructor(storage, key) {
13
+ this.storage = storage;
14
+ this.key = key;
15
+ }
16
+ /** the stored value, or `fallback` when nothing has been written yet */
17
+ read(fallback) {
18
+ const raw = this.storage.read(this.key);
19
+ return raw ? JSON.parse(raw) : fallback;
20
+ }
21
+ write(value) {
22
+ this.storage.write(this.key, JSON.stringify(value));
23
+ }
24
+ remove() {
25
+ this.storage.remove(this.key);
26
+ }
27
+ }
28
+ //# sourceMappingURL=StoredValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StoredValue.js","sourceRoot":"","sources":["../../src/core/StoredValue.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,OAAO,WAAW;IAIvB,YAAY,OAAoB,EAAE,GAAW;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IAChB,CAAC;IAED,wEAAwE;IACxE,IAAI,CAAC,QAAW;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,OAAO,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;IAChD,CAAC;IAED,KAAK,CAAC,KAAQ;QACb,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,MAAM;QACL,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;CACD"}