@xmachines/play-actor 2.0.0 → 2.1.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.
@@ -1,54 +1,58 @@
1
1
  /**
2
- * Shared provider guards for framework ActorProvider implementations.
2
+ * The shared provider guards of the ActorProvider implementation of each framework.
3
3
  *
4
- * Every framework integration (React, Vue, Solid, Svelte, DOM) performs the same
5
- * two rituals when bridging an actor's view to a json-render tree:
4
+ * Every framework integration (React, Vue, Solid, Svelte, and DOM) does the same
5
+ * two steps when it connects the view of an actor to a json-render tree:
6
6
  *
7
- * 1. Sanitize `spec.state` before seeding a fresh `@xstate/store` atom
7
+ * 1. It cleans `spec.state` before it seeds a new `@xstate/store` atom
8
8
  * ({@link toAtomState}).
9
- * 2. Inject a component-level `onRenderError` handler into the component
10
- * registry without mutating the caller's registry
9
+ * 2. It puts an `onRenderError` handler of the component level into the component
10
+ * registry, and it does not change the registry of the caller
11
11
  * ({@link attachRenderErrorHandler}).
12
12
  *
13
- * Centralising them here keeps the guard semantics identical across frameworks.
13
+ * Both functions are here. Therefore the semantics of the guards are identical in
14
+ * every framework.
14
15
  *
15
16
  * @packageDocumentation
16
17
  */
17
18
  import type { RenderErrorHandler } from "@xmachines/json-render-core";
18
19
  /**
19
- * Safely coerce a spec's `state` field to a plain object for `createAtom`.
20
- *
21
- * `spec.state` is typed as `unknown` in `PlaySpec`. At runtime it can be
22
- * `null`, `undefined`, a primitive, or a plain object depending on what the
23
- * machine author put in the view spec. `createAtom` requires a plain object as
24
- * its initial value anything else produces a broken store at runtime.
25
- *
26
- * Only plain objects (prototype is `Object.prototype` or `null`) are accepted
27
- * and returned as-is. Everything else `null`, `undefined`, primitives,
28
- * arrays, class instances, and built-in objects (Date, Map, Set, etc.) — falls
29
- * back to a fresh `{}`, preventing silent broken-store bugs at runtime.
30
- *
31
- * @param state - The raw `spec.state` value from a `PlaySpec`.
32
- * @returns `state` itself when it is a plain object, otherwise a new empty object.
20
+ * Converts the `state` field of a spec into a plain object for `createAtom`, in a safe way.
21
+ *
22
+ * `spec.state` has the type `unknown` in `PlaySpec`. At run time it is `null`,
23
+ * `undefined`, a primitive, or a plain object, and this depends on the value that
24
+ * the author of the machine put in the view spec. `createAtom` requires a plain
25
+ * object as its first value, because every other value makes a broken store at run
26
+ * time.
27
+ *
28
+ * The function accepts a plain object only, which means that its prototype is
29
+ * `Object.prototype` or `null`, and it returns that object without a change. Every
30
+ * other value becomes a new `{}`: `null`, `undefined`, a primitive, an array, an
31
+ * instance of a class, and a built-in object such as a Date, a Map, or a Set. A
32
+ * broken store therefore never appears at run time.
33
+ *
34
+ * @param state - The raw `spec.state` value of a `PlaySpec`.
35
+ * @returns `state` itself when it is a plain object. In every other case, a new empty object.
33
36
  */
34
37
  export declare function toAtomState(state: unknown): Record<string, unknown>;
35
38
  /**
36
- * Clone a component registry and inject an `onRenderError` handler.
39
+ * Copies a component registry, and puts an `onRenderError` handler into the copy.
37
40
  *
38
- * The handler is defined as a non-enumerable, configurable own property on the
39
- * clone (per D-19 one injection convention for all framework renderers), so
40
- * it overrides any handler set at `defineRegistry` level without showing up
41
- * when the registry's component entries are enumerated.
41
+ * The function defines the handler as an own property of the copy. That property is
42
+ * not enumerable, and it is configurable (D-19 gives one convention of the
43
+ * injection for every framework renderer). The handler therefore replaces each
44
+ * handler of the `defineRegistry` level, and it does not appear in an enumeration of
45
+ * the component entries of the registry.
42
46
  *
43
- * The caller's registry is never mutated a shallow clone is returned. Callers
44
- * that need per-instance handlers (e.g. an `onRenderError` prop on
45
- * `ActorProvider`) can therefore share one `defineRegistry` result across
46
- * providers safely.
47
+ * The function never changes the registry of the caller: it returns a shallow copy.
48
+ * Therefore a caller that needs a handler for each instance, such as an
49
+ * `onRenderError` prop of `ActorProvider`, can share one result of `defineRegistry`
50
+ * between the providers in a safe way.
47
51
  *
48
- * @typeParam TRegistry - The framework-specific component registry type.
52
+ * @typeParam TRegistry - The component registry type of the framework.
49
53
  * @param registry - The component registry from `defineRegistry().registry`.
50
- * @param handler - Called with `(error, componentName)` when a catalog component throws during render.
51
- * @returns A shallow clone of `registry` with `onRenderError` attached.
54
+ * @param handler - The renderer calls it with `(error, componentName)` when a catalog component throws during a render.
55
+ * @returns A shallow copy of `registry`, with `onRenderError` on it.
52
56
  */
53
57
  export declare function attachRenderErrorHandler<TRegistry extends object>(registry: TRegistry, handler: RenderErrorHandler): TRegistry;
54
58
  //# sourceMappingURL=provider-guards.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider-guards.d.ts","sourceRoot":"","sources":["../src/provider-guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQnE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,SAAS,MAAM,EAChE,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAE,kBAAkB,GACzB,SAAS,CAQX"}
1
+ {"version":3,"file":"provider-guards.d.ts","sourceRoot":"","sources":["../src/provider-guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQnE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,SAAS,MAAM,EAChE,QAAQ,EAAE,SAAS,EACnB,OAAO,EAAE,kBAAkB,GACzB,SAAS,CAQX"}
@@ -1,34 +1,37 @@
1
1
  /**
2
- * Shared provider guards for framework ActorProvider implementations.
2
+ * The shared provider guards of the ActorProvider implementation of each framework.
3
3
  *
4
- * Every framework integration (React, Vue, Solid, Svelte, DOM) performs the same
5
- * two rituals when bridging an actor's view to a json-render tree:
4
+ * Every framework integration (React, Vue, Solid, Svelte, and DOM) does the same
5
+ * two steps when it connects the view of an actor to a json-render tree:
6
6
  *
7
- * 1. Sanitize `spec.state` before seeding a fresh `@xstate/store` atom
7
+ * 1. It cleans `spec.state` before it seeds a new `@xstate/store` atom
8
8
  * ({@link toAtomState}).
9
- * 2. Inject a component-level `onRenderError` handler into the component
10
- * registry without mutating the caller's registry
9
+ * 2. It puts an `onRenderError` handler of the component level into the component
10
+ * registry, and it does not change the registry of the caller
11
11
  * ({@link attachRenderErrorHandler}).
12
12
  *
13
- * Centralising them here keeps the guard semantics identical across frameworks.
13
+ * Both functions are here. Therefore the semantics of the guards are identical in
14
+ * every framework.
14
15
  *
15
16
  * @packageDocumentation
16
17
  */
17
18
  /**
18
- * Safely coerce a spec's `state` field to a plain object for `createAtom`.
19
+ * Converts the `state` field of a spec into a plain object for `createAtom`, in a safe way.
19
20
  *
20
- * `spec.state` is typed as `unknown` in `PlaySpec`. At runtime it can be
21
- * `null`, `undefined`, a primitive, or a plain object depending on what the
22
- * machine author put in the view spec. `createAtom` requires a plain object as
23
- * its initial value anything else produces a broken store at runtime.
21
+ * `spec.state` has the type `unknown` in `PlaySpec`. At run time it is `null`,
22
+ * `undefined`, a primitive, or a plain object, and this depends on the value that
23
+ * the author of the machine put in the view spec. `createAtom` requires a plain
24
+ * object as its first value, because every other value makes a broken store at run
25
+ * time.
24
26
  *
25
- * Only plain objects (prototype is `Object.prototype` or `null`) are accepted
26
- * and returned as-is. Everything else `null`, `undefined`, primitives,
27
- * arrays, class instances, and built-in objects (Date, Map, Set, etc.) falls
28
- * back to a fresh `{}`, preventing silent broken-store bugs at runtime.
27
+ * The function accepts a plain object only, which means that its prototype is
28
+ * `Object.prototype` or `null`, and it returns that object without a change. Every
29
+ * other value becomes a new `{}`: `null`, `undefined`, a primitive, an array, an
30
+ * instance of a class, and a built-in object such as a Date, a Map, or a Set. A
31
+ * broken store therefore never appears at run time.
29
32
  *
30
- * @param state - The raw `spec.state` value from a `PlaySpec`.
31
- * @returns `state` itself when it is a plain object, otherwise a new empty object.
33
+ * @param state - The raw `spec.state` value of a `PlaySpec`.
34
+ * @returns `state` itself when it is a plain object. In every other case, a new empty object.
32
35
  */
33
36
  export function toAtomState(state) {
34
37
  if (state !== null && typeof state === "object" && !Array.isArray(state)) {
@@ -40,22 +43,23 @@ export function toAtomState(state) {
40
43
  return {};
41
44
  }
42
45
  /**
43
- * Clone a component registry and inject an `onRenderError` handler.
46
+ * Copies a component registry, and puts an `onRenderError` handler into the copy.
44
47
  *
45
- * The handler is defined as a non-enumerable, configurable own property on the
46
- * clone (per D-19 one injection convention for all framework renderers), so
47
- * it overrides any handler set at `defineRegistry` level without showing up
48
- * when the registry's component entries are enumerated.
48
+ * The function defines the handler as an own property of the copy. That property is
49
+ * not enumerable, and it is configurable (D-19 gives one convention of the
50
+ * injection for every framework renderer). The handler therefore replaces each
51
+ * handler of the `defineRegistry` level, and it does not appear in an enumeration of
52
+ * the component entries of the registry.
49
53
  *
50
- * The caller's registry is never mutated a shallow clone is returned. Callers
51
- * that need per-instance handlers (e.g. an `onRenderError` prop on
52
- * `ActorProvider`) can therefore share one `defineRegistry` result across
53
- * providers safely.
54
+ * The function never changes the registry of the caller: it returns a shallow copy.
55
+ * Therefore a caller that needs a handler for each instance, such as an
56
+ * `onRenderError` prop of `ActorProvider`, can share one result of `defineRegistry`
57
+ * between the providers in a safe way.
54
58
  *
55
- * @typeParam TRegistry - The framework-specific component registry type.
59
+ * @typeParam TRegistry - The component registry type of the framework.
56
60
  * @param registry - The component registry from `defineRegistry().registry`.
57
- * @param handler - Called with `(error, componentName)` when a catalog component throws during render.
58
- * @returns A shallow clone of `registry` with `onRenderError` attached.
61
+ * @param handler - The renderer calls it with `(error, componentName)` when a catalog component throws during a render.
62
+ * @returns A shallow copy of `registry`, with `onRenderError` on it.
59
63
  */
60
64
  export function attachRenderErrorHandler(registry, handler) {
61
65
  const clone = { ...registry };
@@ -1 +1 @@
1
- {"version":3,"file":"provider-guards.js","sourceRoot":"","sources":["../src/provider-guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAY,CAAC;QACtD,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAClD,OAAO,KAAgC,CAAC;QACzC,CAAC;IACF,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,wBAAwB,CACvC,QAAmB,EACnB,OAA2B;IAE3B,MAAM,KAAK,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC9B,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,eAAe,EAAE;QAC7C,KAAK,EAAE,OAAO;QACd,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,IAAI;KAClB,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"provider-guards.js","sourceRoot":"","sources":["../src/provider-guards.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1E,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAY,CAAC;QACtD,IAAI,KAAK,KAAK,MAAM,CAAC,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAClD,OAAO,KAAgC,CAAC;QACzC,CAAC;IACF,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,wBAAwB,CACvC,QAAmB,EACnB,OAA2B;IAE3B,MAAM,KAAK,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC9B,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,eAAe,EAAE;QAC7C,KAAK,EAAE,OAAO;QACd,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,IAAI;KAClB,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACd,CAAC"}
@@ -1,77 +1,82 @@
1
1
  /**
2
- * View-store lifecycle — the framework-agnostic reseed-vs-refresh decision
3
- * every provider wires into its own reactivity.
2
+ * The lifecycle of the view store — the framework-agnostic decision between a new
3
+ * seed and a refresh. Each provider connects it to its own reactivity.
4
4
  *
5
- * The policy in one place (previously hand-copied per renderer, where the
6
- * copies drifted into real bugs):
5
+ * The policy is in one place now. Each renderer held a copy of it before, and those
6
+ * copies moved apart into real faults:
7
7
  *
8
- * - `viewKey` changed (or first resolve, or actor swapped) RESEED: a fresh
9
- * store from the view's composed state.
10
- * - `viewKey` unchanged → REFRESH: only the /context projection moved, so the
11
- * `/context` subtree is replaced in place and ephemeral root-level state
12
- * (drafts, toggles) survives.
13
- * - No `viewKey` (a hand-built Viewable that does not stamp one) reseed per
14
- * EMISSION, the safe pre-viewKey behavior.
15
- * - Actor swap → the kept-alive store dies with its actor (lifetime rule).
16
- * - Controlled mode (caller-supplied store) → the caller owns seeding and
17
- * lifecycle, but /context is machinery-owned in both modes and is refreshed
18
- * here unless the caller defers it ({@link ResolveViewStoreOptions}),
19
- * which React's render path needs (store subscribers must not be notified
20
- * mid-render; its effects refresh instead).
8
+ * - The `viewKey` changed, or this is the first resolve, or the tree provides a
9
+ * different actor → NEW SEED: a new store, from the composed state of the view.
10
+ * - The `viewKey` did not change → REFRESH: only the /context projection moved.
11
+ * Therefore the code replaces the `/context` subtree in place, and the ephemeral
12
+ * state at the root level, such as a draft or a toggle, stays.
13
+ * - No `viewKey`, from a Viewable that a person built and that stamps no keya new
14
+ * seed for each EMISSION, which is the safe behavior from the time before the
15
+ * viewKey.
16
+ * - A different actor → the store that stays alive dies with its actor. This is the
17
+ * rule of the lifetime.
18
+ * - The controlled mode, where the caller gives the store → the caller owns the seed
19
+ * and the lifecycle. The machinery owns /context in both modes, and this file
20
+ * refreshes it. The caller can move that refresh to a later moment
21
+ * ({@link ResolveViewStoreOptions}), and the render path of React needs this,
22
+ * because a store must notify no subscriber during a render. The effects of React
23
+ * then do the refresh.
21
24
  *
22
- * What stays in each provider is only reactivity wiring: WHEN to resolve, and
23
- * how the result reaches children.
25
+ * Each provider therefore holds the wiring of its reactivity only: the moment of
26
+ * the resolve, and the path of the result to the children.
24
27
  *
25
28
  * @packageDocumentation
26
29
  */
27
30
  import type { StateStore } from "@xmachines/json-render-core";
28
31
  import type { PlaySpec } from "./abstract-actor.js";
29
- /** What a resolve produced — see {@link ViewStoreLifecycle.resolve}. */
32
+ /** The result of a resolve — see {@link ViewStoreLifecycle.resolve}. */
30
33
  export interface ViewStoreResolution {
31
- /** The UNGUARDED store — the machinery's own refresh reference. */
34
+ /** The store WITHOUT the guard — the reference of the machinery for its own refresh. */
32
35
  store: StateStore;
33
36
  /**
34
- * The store to hand children ($bindState, setState, chained set): writes
35
- * under /context throw. One wrapper per underlying store the identity is
36
- * cached so `useSyncExternalStore`-style consumers stay stable.
37
+ * The store to give to the children ($bindState, setState, and a chained set): a
38
+ * write under /context throws. There is one wrapper for each store below it, and
39
+ * the code caches the identity. Therefore a consumer in the style of
40
+ * `useSyncExternalStore` stays stable.
37
41
  */
38
42
  guardedStore: StateStore;
39
43
  /**
40
- * True when this resolve created a fresh store (first resolve, viewKey
41
- * change, per-emission fallback, actor swap). Providers that remount a
42
- * subtree per store (Vue's storeKey) key on it.
44
+ * It is true when this resolve made a new store: at the first resolve, on a change
45
+ * of the viewKey, in the fallback for each emission, and on a change of the actor. A
46
+ * provider that mounts a subtree again for each store, such as the storeKey of Vue,
47
+ * uses this field as its key.
43
48
  */
44
49
  reseeded: boolean;
45
50
  }
46
51
  export interface ResolveViewStoreOptions {
47
52
  /**
48
- * Controlled mode only: refresh the external store's /context during this
49
- * resolve (default true). Pass false where notifying store subscribers is
50
- * not allowed at the call site (React's render path) and refresh from an
51
- * effect instead.
53
+ * The controlled mode only: refresh the /context subtree of the external store
54
+ * during this resolve. The default is true. Give false where the call site permits
55
+ * no notification of the store subscribers, which is the render path of React, and
56
+ * refresh from an effect instead.
52
57
  */
53
58
  refreshExternalStore?: boolean;
54
59
  }
55
60
  export interface ViewStoreLifecycle {
56
61
  /**
57
- * Bring the store in line with an emission and return it (with its guard).
62
+ * Brings the store in line with an emission, and returns it with its guard.
58
63
  *
59
- * @param actor - The actor the emission came from a swap drops the kept store.
60
- * @param view - The derived view (non-null; a null emission is a GAP, not a
61
- * new view callers simply do not resolve on null, keeping the store).
62
- * @param externalStore - Controlled mode: the caller-owned store.
64
+ * @param actor - The actor of the emission. A different actor drops the store that the code kept.
65
+ * @param view - The derived view. It is not null: a null emission is a GAP, and not
66
+ * a new view. A caller resolves nothing on a null value, and it keeps the store.
67
+ * @param externalStore - The controlled mode: the store of the caller.
63
68
  * @param options - See {@link ResolveViewStoreOptions}.
64
69
  */
65
70
  resolve(actor: unknown, view: PlaySpec, externalStore?: StateStore | undefined, options?: ResolveViewStoreOptions): ViewStoreResolution;
66
- /** Drop everything (unmount/disconnect) the next resolve reseeds. */
71
+ /** Drops everything, on an unmount or a disconnect. The next resolve makes a new seed. */
67
72
  reset(): void;
68
73
  }
69
74
  /**
70
- * Create a lifecycle coordinator.
75
+ * Creates a coordinator of the lifecycle.
71
76
  *
72
- * @param createStore - Framework-supplied store factory; receives the
73
- * proto-safe seed (`toAtomState(view.state)` the composed state already
74
- * carries /context).
77
+ * @param createStore - The store factory of the framework. It receives the seed
78
+ * that is safe for the prototype (`toAtomState(view.state)`), and the composed
79
+ * state carries /context already.
75
80
  */
76
81
  export declare function createViewStoreLifecycle(createStore: (seed: Record<string, unknown>) => StateStore): ViewStoreLifecycle;
77
82
  //# sourceMappingURL=view-store-lifecycle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"view-store-lifecycle.d.ts","sourceRoot":"","sources":["../src/view-store-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IACnC,mEAAmE;IACnE,KAAK,EAAE,UAAU,CAAC;IAClB;;;;OAIG;IACH,YAAY,EAAE,UAAU,CAAC;IACzB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACvC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IAClC;;;;;;;;OAQG;IACH,OAAO,CACN,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,QAAQ,EACd,aAAa,CAAC,EAAE,UAAU,GAAG,SAAS,EACtC,OAAO,CAAC,EAAE,uBAAuB,GAC/B,mBAAmB,CAAC;IACvB,uEAAuE;IACvE,KAAK,IAAI,IAAI,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACvC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,UAAU,GACxD,kBAAkB,CA4DpB"}
1
+ {"version":3,"file":"view-store-lifecycle.d.ts","sourceRoot":"","sources":["../src/view-store-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IACnC,wFAAwF;IACxF,KAAK,EAAE,UAAU,CAAC;IAClB;;;;;OAKG;IACH,YAAY,EAAE,UAAU,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACvC;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IAClC;;;;;;;;OAQG;IACH,OAAO,CACN,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,QAAQ,EACd,aAAa,CAAC,EAAE,UAAU,GAAG,SAAS,EACtC,OAAO,CAAC,EAAE,uBAAuB,GAC/B,mBAAmB,CAAC;IACvB,0FAA0F;IAC1F,KAAK,IAAI,IAAI,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACvC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,UAAU,GACxD,kBAAkB,CA4DpB"}
@@ -1,44 +1,47 @@
1
1
  /**
2
- * View-store lifecycle — the framework-agnostic reseed-vs-refresh decision
3
- * every provider wires into its own reactivity.
2
+ * The lifecycle of the view store — the framework-agnostic decision between a new
3
+ * seed and a refresh. Each provider connects it to its own reactivity.
4
4
  *
5
- * The policy in one place (previously hand-copied per renderer, where the
6
- * copies drifted into real bugs):
5
+ * The policy is in one place now. Each renderer held a copy of it before, and those
6
+ * copies moved apart into real faults:
7
7
  *
8
- * - `viewKey` changed (or first resolve, or actor swapped) RESEED: a fresh
9
- * store from the view's composed state.
10
- * - `viewKey` unchanged → REFRESH: only the /context projection moved, so the
11
- * `/context` subtree is replaced in place and ephemeral root-level state
12
- * (drafts, toggles) survives.
13
- * - No `viewKey` (a hand-built Viewable that does not stamp one) reseed per
14
- * EMISSION, the safe pre-viewKey behavior.
15
- * - Actor swap → the kept-alive store dies with its actor (lifetime rule).
16
- * - Controlled mode (caller-supplied store) → the caller owns seeding and
17
- * lifecycle, but /context is machinery-owned in both modes and is refreshed
18
- * here unless the caller defers it ({@link ResolveViewStoreOptions}),
19
- * which React's render path needs (store subscribers must not be notified
20
- * mid-render; its effects refresh instead).
8
+ * - The `viewKey` changed, or this is the first resolve, or the tree provides a
9
+ * different actor → NEW SEED: a new store, from the composed state of the view.
10
+ * - The `viewKey` did not change → REFRESH: only the /context projection moved.
11
+ * Therefore the code replaces the `/context` subtree in place, and the ephemeral
12
+ * state at the root level, such as a draft or a toggle, stays.
13
+ * - No `viewKey`, from a Viewable that a person built and that stamps no keya new
14
+ * seed for each EMISSION, which is the safe behavior from the time before the
15
+ * viewKey.
16
+ * - A different actor → the store that stays alive dies with its actor. This is the
17
+ * rule of the lifetime.
18
+ * - The controlled mode, where the caller gives the store → the caller owns the seed
19
+ * and the lifecycle. The machinery owns /context in both modes, and this file
20
+ * refreshes it. The caller can move that refresh to a later moment
21
+ * ({@link ResolveViewStoreOptions}), and the render path of React needs this,
22
+ * because a store must notify no subscriber during a render. The effects of React
23
+ * then do the refresh.
21
24
  *
22
- * What stays in each provider is only reactivity wiring: WHEN to resolve, and
23
- * how the result reaches children.
25
+ * Each provider therefore holds the wiring of its reactivity only: the moment of
26
+ * the resolve, and the path of the result to the children.
24
27
  *
25
28
  * @packageDocumentation
26
29
  */
27
30
  import { guardContextWrites, refreshContextSubtree } from "./context-projection.js";
28
31
  import { toAtomState } from "./provider-guards.js";
29
32
  /**
30
- * Create a lifecycle coordinator.
33
+ * Creates a coordinator of the lifecycle.
31
34
  *
32
- * @param createStore - Framework-supplied store factory; receives the
33
- * proto-safe seed (`toAtomState(view.state)` the composed state already
34
- * carries /context).
35
+ * @param createStore - The store factory of the framework. It receives the seed
36
+ * that is safe for the prototype (`toAtomState(view.state)`), and the composed
37
+ * state carries /context already.
35
38
  */
36
39
  export function createViewStoreLifecycle(createStore) {
37
40
  let internalStore = null;
38
41
  let lastViewKey = undefined;
39
42
  let lastView = null;
40
43
  let lastActor = null;
41
- // Guard identity cache one wrapper per underlying store.
44
+ // The identity cache of the guard: one wrapper for each store below it.
42
45
  let guardedSource = null;
43
46
  let guardedStore = null;
44
47
  const reset = () => {
@@ -52,7 +55,7 @@ export function createViewStoreLifecycle(createStore) {
52
55
  return {
53
56
  reset,
54
57
  resolve(actor, view, externalStore, options) {
55
- // Lifetime rule: a kept-alive store must not outlive its actor.
58
+ // The rule of the lifetime: a store that stays alive must not outlive its actor.
56
59
  if (lastActor !== actor) {
57
60
  const firstResolve = lastActor === null && internalStore === null;
58
61
  if (!firstResolve)
@@ -1 +1 @@
1
- {"version":3,"file":"view-store-lifecycle.js","sourceRoot":"","sources":["../src/view-store-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAKH,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAkDnD;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACvC,WAA0D;IAE1D,IAAI,aAAa,GAAsB,IAAI,CAAC;IAC5C,IAAI,WAAW,GAAuB,SAAS,CAAC;IAChD,IAAI,QAAQ,GAAoB,IAAI,CAAC;IACrC,IAAI,SAAS,GAAY,IAAI,CAAC;IAC9B,2DAA2D;IAC3D,IAAI,aAAa,GAAsB,IAAI,CAAC;IAC5C,IAAI,YAAY,GAAsB,IAAI,CAAC;IAE3C,MAAM,KAAK,GAAG,GAAS,EAAE;QACxB,aAAa,GAAG,IAAI,CAAC;QACrB,WAAW,GAAG,SAAS,CAAC;QACxB,QAAQ,GAAG,IAAI,CAAC;QAChB,SAAS,GAAG,IAAI,CAAC;QACjB,aAAa,GAAG,IAAI,CAAC;QACrB,YAAY,GAAG,IAAI,CAAC;IACrB,CAAC,CAAC;IAEF,OAAO;QACN,KAAK;QACL,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO;YAC1C,gEAAgE;YAChE,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;gBACzB,MAAM,YAAY,GAAG,SAAS,KAAK,IAAI,IAAI,aAAa,KAAK,IAAI,CAAC;gBAClE,IAAI,CAAC,YAAY;oBAAE,KAAK,EAAE,CAAC;gBAC3B,SAAS,GAAG,KAAK,CAAC;YACnB,CAAC;YAED,IAAI,QAAoB,CAAC;YACzB,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,aAAa,EAAE,CAAC;gBACnB,QAAQ,GAAG,aAAa,CAAC;gBACzB,IAAI,OAAO,EAAE,oBAAoB,KAAK,KAAK,EAAE,CAAC;oBAC7C,qBAAqB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACvC,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;gBAC7B,IAAI,SAAS,GAAsB,aAAa,CAAC;gBACjD,IACC,SAAS,KAAK,IAAI;oBAClB,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,EACpE,CAAC;oBACF,SAAS,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;oBACjD,aAAa,GAAG,SAAS,CAAC;oBAC1B,WAAW,GAAG,OAAO,CAAC;oBACtB,QAAQ,GAAG,IAAI,CAAC;gBACjB,CAAC;qBAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;oBAClC,qBAAqB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;gBACxC,CAAC;gBACD,QAAQ,GAAG,IAAI,CAAC;gBAChB,QAAQ,GAAG,SAAS,CAAC;YACtB,CAAC;YAED,IAAI,aAAa,KAAK,QAAQ,EAAE,CAAC;gBAChC,aAAa,GAAG,QAAQ,CAAC;gBACzB,YAAY,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,YAA0B,EAAE,QAAQ,EAAE,CAAC;QAChF,CAAC;KACD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"view-store-lifecycle.js","sourceRoot":"","sources":["../src/view-store-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAoDnD;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CACvC,WAA0D;IAE1D,IAAI,aAAa,GAAsB,IAAI,CAAC;IAC5C,IAAI,WAAW,GAAuB,SAAS,CAAC;IAChD,IAAI,QAAQ,GAAoB,IAAI,CAAC;IACrC,IAAI,SAAS,GAAY,IAAI,CAAC;IAC9B,wEAAwE;IACxE,IAAI,aAAa,GAAsB,IAAI,CAAC;IAC5C,IAAI,YAAY,GAAsB,IAAI,CAAC;IAE3C,MAAM,KAAK,GAAG,GAAS,EAAE;QACxB,aAAa,GAAG,IAAI,CAAC;QACrB,WAAW,GAAG,SAAS,CAAC;QACxB,QAAQ,GAAG,IAAI,CAAC;QAChB,SAAS,GAAG,IAAI,CAAC;QACjB,aAAa,GAAG,IAAI,CAAC;QACrB,YAAY,GAAG,IAAI,CAAC;IACrB,CAAC,CAAC;IAEF,OAAO;QACN,KAAK;QACL,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO;YAC1C,iFAAiF;YACjF,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;gBACzB,MAAM,YAAY,GAAG,SAAS,KAAK,IAAI,IAAI,aAAa,KAAK,IAAI,CAAC;gBAClE,IAAI,CAAC,YAAY;oBAAE,KAAK,EAAE,CAAC;gBAC3B,SAAS,GAAG,KAAK,CAAC;YACnB,CAAC;YAED,IAAI,QAAoB,CAAC;YACzB,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,IAAI,aAAa,EAAE,CAAC;gBACnB,QAAQ,GAAG,aAAa,CAAC;gBACzB,IAAI,OAAO,EAAE,oBAAoB,KAAK,KAAK,EAAE,CAAC;oBAC7C,qBAAqB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBACvC,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;gBAC7B,IAAI,SAAS,GAAsB,aAAa,CAAC;gBACjD,IACC,SAAS,KAAK,IAAI;oBAClB,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,EACpE,CAAC;oBACF,SAAS,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;oBACjD,aAAa,GAAG,SAAS,CAAC;oBAC1B,WAAW,GAAG,OAAO,CAAC;oBACtB,QAAQ,GAAG,IAAI,CAAC;gBACjB,CAAC;qBAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;oBAClC,qBAAqB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;gBACxC,CAAC;gBACD,QAAQ,GAAG,IAAI,CAAC;gBAChB,QAAQ,GAAG,SAAS,CAAC;YACtB,CAAC;YAED,IAAI,aAAa,KAAK,QAAQ,EAAE,CAAC;gBAChC,aAAa,GAAG,QAAQ,CAAC;gBACzB,YAAY,GAAG,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YAC7C,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,YAA0B,EAAE,QAAQ,EAAE,CAAC;QAChF,CAAC;KACD,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmachines/play-actor",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "private": false,
5
5
  "description": "Abstract Actor base class for XMachines Play Architecture",
6
6
  "keywords": [
@@ -40,6 +40,7 @@
40
40
  "build": "vite build && tsc --build",
41
41
  "clean": "rm -rf dist *.tsbuildinfo coverage node_modules/.svelte2tsx-* node_modules/.vite*",
42
42
  "test": "vitest",
43
+ "test:coverage": "vitest run --coverage",
43
44
  "lint": "oxlint .",
44
45
  "lint:fix": "oxlint --fix .",
45
46
  "format": "oxfmt .",
@@ -57,8 +58,8 @@
57
58
  },
58
59
  "peerDependencies": {
59
60
  "@xmachines/json-render-core": "^0.20.0-xm.2",
60
- "@xmachines/play": "2.0.0",
61
- "@xmachines/play-signals": "2.0.0",
61
+ "@xmachines/play": "2.1.0",
62
+ "@xmachines/play-signals": "2.1.0",
62
63
  "xstate": "^5.31.0"
63
64
  },
64
65
  "engines": {