narraleaf-react 0.18.0 → 0.19.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.
@@ -64,7 +64,13 @@ export type StackModelRawData = {
64
64
  /**
65
65
  * One frame of a read-only {@link StackModel.snapshot} — an action currently on the execution
66
66
  * stack. A frame that is a concurrent group ({@link Control.all}/{@link Control.any}) also lists
67
- * its branches (each a top-to-bottom frame list).
67
+ * its branches, each a whole {@link StackSnapshot}.
68
+ *
69
+ * `branches` used to be `StackFrameSnapshot[][]` — only each branch's `frames`. That silently threw
70
+ * away everything a nested stack knows about ITSELF: a `Control.repeat` runs as a nested StackModel,
71
+ * so its `loop` counter lived on a snapshot whose frames were kept and whose `loop` and `tag` were
72
+ * dropped on the way out. The counter was therefore unreachable from `getStackSnapshot()` no matter
73
+ * how a caller asked, which is exactly what a debug view most wants to show.
68
74
  *
69
75
  * **Experimental / read-only.** For tooling (Studio's call-stack view). The exact shape is not a
70
76
  * stable contract and may change; do not serialize it or drive game logic from it.
@@ -73,7 +79,7 @@ export type StackFrameSnapshot = {
73
79
  actionId: string | null;
74
80
  actionType: string | null;
75
81
  branchWaitType?: StackModelWaiting["type"];
76
- branches?: StackFrameSnapshot[][];
82
+ branches?: StackSnapshot[];
77
83
  };
78
84
  /**
79
85
  * Read-only view of a StackModel's execution stack. `frames` are ordered top-first (the frame
@@ -3,8 +3,9 @@ import { GameState } from "../../player/gameState";
3
3
  import { Storable, Namespace } from "../elements/persistent/storable";
4
4
  import { LiveGame } from "../game/liveGame";
5
5
  import { Preference } from "../game/preference";
6
+ import type { StorableChange, StorableRestore } from "../elements/persistent/storable";
6
7
  import type { SavedGame } from "../gameTypes";
7
8
  import type { StackSnapshot, StackFrameSnapshot } from "../action/stackModel";
8
9
  import { KeyMap } from "../game/keyMap";
9
10
  export { LiveGame, GameState, Game, Storable, Namespace, Preference, KeyMap, };
10
- export type { SavedGame, StackSnapshot, StackFrameSnapshot, };
11
+ export type { SavedGame, StackSnapshot, StackFrameSnapshot, StorableChange, StorableRestore, };
@@ -1,4 +1,31 @@
1
- import { NameSpaceContent } from "../../elements/persistent/type";
1
+ import { NameSpaceContent, StorableType } from "../../elements/persistent/type";
2
+ import { EventDispatcher, EventToken } from "../../../../util/data";
3
+ /**
4
+ * One stored value changing. Reported by {@link Storable.onChange} after the new value is
5
+ * already readable through `getNamespace(namespace).get(key)`.
6
+ */
7
+ export type StorableChange<T extends StorableType = any> = {
8
+ /**
9
+ * The key the namespace is registered under in the {@link Storable} — the same string
10
+ * {@link Storable.getNamespace} takes, and the one a save file carries. For a namespace
11
+ * declared with `new Persistent("player", ...)` this is `"persistent:player"`.
12
+ */
13
+ namespace: string;
14
+ key: string;
15
+ /** The value that was there. `undefined` if the key had never been written. */
16
+ previous: T | undefined;
17
+ /** The value that is there now. `undefined` if the key was dropped (see {@link Namespace.reset}). */
18
+ next: T | undefined;
19
+ };
20
+ /**
21
+ * A bulk value application — a save being loaded, or a namespace being rewound to a
22
+ * snapshot. Reported by {@link Storable.onRestore} *instead of* per-key changes; see the
23
+ * note on {@link Namespace.deserialize}.
24
+ */
25
+ export type StorableRestore = {
26
+ /** The namespace keys whose contents were replaced. */
27
+ namespaces: string[];
28
+ };
2
29
  export declare class Namespace<T extends NameSpaceContent<keyof T>> {
3
30
  static isSerializable(value: any): boolean;
4
31
  name: string;
@@ -11,10 +38,25 @@ export declare class Namespace<T extends NameSpaceContent<keyof T>> {
11
38
  keys(): (keyof T)[];
12
39
  values(): T[keyof T][];
13
40
  entries(): [keyof T, T[keyof T]][];
41
+ /**
42
+ * Restore the author's defaults.
43
+ *
44
+ * Reports one change per key that actually moved. A key written after construction is
45
+ * not in the defaults, so it is dropped and reported as changing to `undefined`.
46
+ */
14
47
  reset(): this;
15
48
  }
16
49
  export declare class Storable {
50
+ static EventTypes: {
51
+ readonly "event:storable.change": "event:storable.change";
52
+ readonly "event:storable.restore": "event:storable.restore";
53
+ };
17
54
  static createNamespace<T extends NameSpaceContent<keyof T>>(name: string, initContent: T, key?: string): Namespace<T>;
55
+ /**
56
+ * Changes to any value in any registered namespace. Prefer {@link Storable.onChange},
57
+ * which filters by namespace and key.
58
+ */
59
+ readonly events: EventDispatcher<StorableEvents>;
18
60
  addNamespace<T extends NameSpaceContent<keyof T>>(namespace: Namespace<T>): this | undefined;
19
61
  getNamespace<T extends NameSpaceContent<keyof T> = any>(key: string): Namespace<T>;
20
62
  setNamespace<T extends NameSpaceContent<keyof T> = any>(key: string, namespace: Namespace<T>): this;
@@ -26,4 +68,45 @@ export declare class Storable {
26
68
  keys(): string[];
27
69
  values(): Namespace<any>[];
28
70
  entries(): [string, Namespace<any>][];
71
+ /**
72
+ * Listen for a stored value changing.
73
+ *
74
+ * The listener runs after the new value is readable, and only when the value actually
75
+ * moved — writing a value equal to the one already there reports nothing, so a line that
76
+ * re-asserts a flag every time it runs does not wake anything up. Equality is structural,
77
+ * so rebuilding an object with the same contents is also a no-op.
78
+ *
79
+ * Loading a save does not report changes; see {@link Storable.onRestore}.
80
+ *
81
+ * Subscriptions outlive the namespaces they watch: `newGame()` and loading a save both
82
+ * rebuild every namespace from scratch, and a listener registered here survives that.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * // every change, anywhere
87
+ * liveGame.getStorable().onChange(({namespace, key, previous, next}) => {...});
88
+ *
89
+ * // one namespace
90
+ * liveGame.getStorable().onChange("persistent:player", ({key, next}) => {...});
91
+ *
92
+ * // one key
93
+ * liveGame.getStorable().onChange("persistent:player", "gold", ({next}) => {
94
+ * if (next === 100) {...}
95
+ * });
96
+ * ```
97
+ * @returns a token whose `cancel()` removes the listener
98
+ */
99
+ onChange(listener: (change: StorableChange) => void): EventToken;
100
+ onChange(namespace: string, listener: (change: StorableChange) => void): EventToken;
101
+ onChange(namespace: string, key: string, listener: (change: StorableChange) => void): EventToken;
102
+ /**
103
+ * Listen for the store being replaced wholesale — loading a save, or rewinding a
104
+ * namespace to a snapshot. Fires once per bulk application, naming the namespaces
105
+ * involved, instead of the changes it implies.
106
+ *
107
+ * Re-read whatever you derive from the store when this fires.
108
+ *
109
+ * @returns a token whose `cancel()` removes the listener
110
+ */
111
+ onRestore(listener: (restore: StorableRestore) => void): EventToken;
29
112
  }