@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.
package/README.md CHANGED
@@ -2,9 +2,7 @@
2
2
 
3
3
  Abstract Actor base class for XMachines Play Architecture.
4
4
 
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-2.0.0-blue)](https://www.npmjs.com/package/@xmachines/play-actor)
6
-
7
- Part of the [xmachines-js monorepo](../../README.md).
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-2.1.0-blue)](https://www.npmjs.com/package/@xmachines/play-actor)
8
6
 
9
7
  ## Installation
10
8
 
@@ -12,7 +10,7 @@ Part of the [xmachines-js monorepo](../../README.md).
12
10
  pnpm add @xmachines/play-actor
13
11
  ```
14
12
 
15
- **Peer dependencies** install alongside the package:
13
+ **Peer dependencies.** Install them with the package:
16
14
 
17
15
  ```bash
18
16
  pnpm add xstate @xmachines/play @xmachines/play-signals @xmachines/json-render-core
@@ -20,35 +18,35 @@ pnpm add xstate @xmachines/play @xmachines/play-signals @xmachines/json-render-c
20
18
 
21
19
  ## Overview
22
20
 
23
- `@xmachines/play-actor` provides `AbstractActor`, a minimal base class that extends the XState `Actor` class while enforcing the Play Architecture's **signal protocol** (RFC section 5.3). It exposes reactive TC39 Signals for infrastructure-layer communication while preserving full XState ecosystem compatibility (devtools, inspection).
21
+ `@xmachines/play-actor` gives you `AbstractActor`, a minimal base class. The class extends the XState `Actor` class, and it enforces the **signal protocol** of the Play Architecture (RFC section 5.3). It exposes reactive TC39 Signals for the infrastructure layer. It also keeps the complete compatibility with the XState ecosystem, which includes the devtools and the inspection.
24
22
 
25
- The core protocol is deliberately minimal:
23
+ The core protocol is small on purpose:
26
24
 
27
25
  | Property | Type | Description |
28
26
  | -------- | ------------------------- | ---------------------------------------- |
29
27
  | `state` | `Signal.State<unknown>` | Reactive snapshot of current actor state |
30
28
  | `send` | `(event: TEvent) => void` | Event dispatch method |
31
29
 
32
- Optional capabilities are declared as separate interfaces — a concrete actor opts in only to what it needs:
30
+ Separate interfaces declare the optional capabilities. A concrete actor implements only the interfaces that it needs:
33
31
 
34
32
  | Interface | Property | Description |
35
33
  | ---------- | ----------------------------------------------- | ------------------------------------- |
36
34
  | `Routable` | `currentRoute: Signal.Computed<string \| null>` | Current route path derived from state |
37
- | `Routable` | `initialRoute: string \| null` | Route the actor starts on |
35
+ | `Routable` | `initialRoute: string \| null` | The route where the actor starts |
38
36
  | `Viewable` | `currentView: Signal.State<PlaySpec \| null>` | Current JSON-render view spec |
39
37
 
40
- Concrete implementations are created by adapters such as [`@xmachines/play-xstate`](../play-xstate/README.md).
38
+ An adapter, such as [`@xmachines/play-xstate`](../play-xstate/README.md), makes the concrete implementations.
41
39
 
42
40
  ## API Summary
43
41
 
44
42
  ### `AbstractActor<TLogic, TEvent>`
45
43
 
46
- Abstract base class extending XState `Actor<TLogic>`.
44
+ The abstract base class extends the XState `Actor<TLogic>` class.
47
45
 
48
- A subclass **is** the actor: hand the logic and its options to `super()` so one
49
- instance holds the running machine, and reach XState's own `send` through the
50
- prototype `send` is declared abstract here only to narrow the event type, and
51
- TypeScript forbids `super` calls to an abstract member.
46
+ A subclass **is** the actor. Give the logic and its options to `super()`, so that one
47
+ instance holds the running machine. Reach the `send` method of XState through the
48
+ prototype. This class declares `send` as abstract for one reason only: to narrow the
49
+ event type. TypeScript forbids a `super` call to an abstract member.
52
50
 
53
51
  ```ts
54
52
  import { AbstractActor } from "@xmachines/play-actor";
@@ -75,6 +73,7 @@ class MyActor extends AbstractActor<AnyActorLogic> {
75
73
  With a typed event union:
76
74
 
77
75
  ```ts
76
+ // imports as in the previous example
78
77
  type AuthEvent = { type: "auth.login"; username: string } | { type: "auth.logout" };
79
78
 
80
79
  class AuthActor extends AbstractActor<AnyActorLogic, AuthEvent> {
@@ -88,9 +87,10 @@ class AuthActor extends AbstractActor<AnyActorLogic, AuthEvent> {
88
87
 
89
88
  ### `typedSpec(spec)`
90
89
 
91
- Identity helper that types a view-spec literal as `PlaySpec` at the definition site. XState's
92
- `meta` field is `Record<string, unknown>`, so this is where the spec shape gets compile-time
93
- validation and IDE autocomplete without any runtime cost.
90
+ This identity helper gives a view-spec literal the type `PlaySpec` at the definition site. The
91
+ XState `meta` field has the type `Record<string, unknown>`. Therefore this helper is the place
92
+ where the spec shape receives the compile-time check and the IDE autocomplete. The helper has no
93
+ cost at run time.
94
94
 
95
95
  ```ts
96
96
  import { typedSpec } from "@xmachines/play-actor";
@@ -112,28 +112,33 @@ meta: {
112
112
 
113
113
  ### `PlaySpec`
114
114
 
115
- Extends `@xmachines/json-render-core`'s `Spec`. The machine's whole context is projected into
116
- every derived view's state store under the read-only **`/context` subtree**, so specs read it
117
- through the ordinary `{ $state: "/context/…" }` grammar in props, `visible` conditions, and
118
- `repeat.statePath` alike.
119
-
120
- `/context` is read-only by design never writable. Machine context changes only through events;
121
- a `$bindState` or `setState` write under `/context` throws with an error naming the event to
122
- send instead. This is the model: bindable ephemeral state lives at the store root (seeded from
123
- `spec.state`), domain state lives in the machine and changes via meaningful, inspectable events.
124
-
125
- Provenance is legible in the path: `/context/params/username` is visibly URL-derived, while
126
- `/context/username` is machine-owned — one can never shadow the other.
127
-
128
- Two consequences of the everything-is-projected model are worth knowing. First, **exposure**:
129
- the whole context is client-visible in the view store (debug panels, inspectors, validators) —
130
- context is a client-side value either way, so keep secrets out of it. Second, **emission
131
- granularity**: the emit gate compares context per top-level field, so an event that changes any
132
- field re-emits the view with the same `viewKey`. Providers refresh `/context` in the live store
133
- rather than reseeding it — no remount, ephemeral view state and focus survive — but a
134
- re-emission is still a render pass in the framework layer. Keep high-frequency ephemeral data
135
- (per-keystroke drafts, timers) in the view store (`spec.state` + `$bindState`) or a child actor
136
- rather than in machine context; domain state belongs in context, keystrokes do not.
115
+ This type extends the `Spec` type of `@xmachines/json-render-core`. Each derived view receives
116
+ the complete machine context in its state store, under the read-only **`/context` subtree**. A
117
+ spec therefore reads the context through the ordinary `{ $state: "/context/…" }` grammar: in a
118
+ prop, in a `visible` condition, and in `repeat.statePath`.
119
+
120
+ `/context` is read-only by design. Nothing can write to it. The machine context changes through
121
+ an event only. A `$bindState` write or a `setState` write under `/context` throws an error, and
122
+ the error names the event to send. This is the model: the bindable ephemeral state is at the
123
+ root of the store, from `spec.state`; the domain state is in the machine, and it changes through
124
+ events that are meaningful and easy to inspect.
125
+
126
+ The path shows the origin of each value. `/context/params/username` comes from the URL.
127
+ `/context/username` belongs to the machine. One value can never hide the other.
128
+
129
+ The model projects everything, and this has two consequences. The first consequence is
130
+ **exposure**. The complete context is visible to the client in the view store, which includes a
131
+ debug panel, an inspector, and a validator. The context is a client-side value in each case, so
132
+ keep a secret out of it.
133
+
134
+ The second consequence is **emission granularity**. The emit gate compares the context field by
135
+ field, at the top level only. Therefore an event that changes any field emits the view again
136
+ with the same `viewKey`. A provider refreshes `/context` in the live store, and it does not seed
137
+ the store again. The component does not remount, and the ephemeral view state and the focus
138
+ stay. However, a new emission is still a render pass in the framework layer. Keep
139
+ high-frequency ephemeral data, such as a draft for each keystroke or a timer, in the view store
140
+ (`spec.state` with `$bindState`) or in a child actor. The domain state belongs in the context. A
141
+ keystroke does not.
137
142
 
138
143
  ```ts
139
144
  import type { PlaySpec } from "@xmachines/play-actor";
@@ -150,31 +155,33 @@ const spec: PlaySpec = {
150
155
  };
151
156
  ```
152
157
 
153
- > Historical note: earlier versions had a `contextProps` field. It first drove an implicit
154
- > prop-enrichment pass that merged allowlisted context fields and URL params into every
155
- > element's props (removed it injected values into components that never asked for them and
156
- > let user-manipulable URL data silently shadow machine-owned state), and was then briefly a
157
- > projection filter (removed filtering what a view may read added machinery without a real
158
- > problem to solve). Validate the **derived** view (`actor.currentView.get()`), not the raw
159
- > `meta.view`: the derived spec's `state` carries the projection, so tools like `validateSpec`
160
- > see a self-consistent spec.
158
+ > Historical note: an earlier version had a `contextProps` field. At first the field drove an
159
+ > implicit prop-enrichment pass. That pass merged the allowlisted context fields and the URL
160
+ > params into the props of every element. We removed it, because it put values into components
161
+ > that never asked for them, and it let URL data from the user hide machine-owned state. The
162
+ > field was then a projection filter for a short time. We removed that filter too, because a
163
+ > limit on what a view can read added machinery without a real problem to solve. Always
164
+ > validate the **derived** view (`actor.currentView.get()`), not the raw `meta.view`. The
165
+ > `state` of the derived spec carries the projection, so a tool such as `validateSpec` sees a
166
+ > spec that is consistent with itself.
161
167
 
162
168
  ### `Routable`
163
169
 
164
170
  Interface for actors that support routing.
165
171
 
166
172
  ```ts
167
- import type { Routable } from "@xmachines/play-actor";
173
+ import { AbstractActor, type Routable } from "@xmachines/play-actor";
168
174
  import { Signal } from "@xmachines/play-signals";
175
+ import type { AnyActorLogic, EventObject } from "xstate";
169
176
 
170
177
  // Implement in a concrete actor (note: RoutableActor interface is exported from @xmachines/play-router):
171
178
  class MyRoutableActor extends AbstractActor<AnyActorLogic> implements Routable {
172
- state = new Signal.State({});
173
- currentRoute = new Signal.Computed(() => this.state.get().path ?? null);
179
+ state = new Signal.State<{ path?: string }>({});
180
+ currentRoute = new Signal.Computed<string | null>(() => this.state.get().path ?? null);
174
181
  initialRoute = "/";
175
- send = (event) => {
182
+ override send(event: EventObject): void {
176
183
  /* dispatch */
177
- };
184
+ }
178
185
  }
179
186
  ```
180
187
 
@@ -194,7 +201,7 @@ const viewable: Viewable = { currentView: signal };
194
201
 
195
202
  ### `BaseActorProviderProps<TRegistry>`
196
203
 
197
- Framework-agnostic base props shared by every `ActorProvider` implementation (React, Vue, Solid, Svelte). Framework renderer packages extend this interface.
204
+ The framework-agnostic base props. Every `ActorProvider` implementation shares them: React, Vue, Solid, and Svelte. Each framework renderer package extends this interface.
198
205
 
199
206
  ```ts
200
207
  import type { BaseActorProviderProps } from "@xmachines/play-actor";
@@ -208,7 +215,7 @@ interface ActorProviderProps extends BaseActorProviderProps<DefineRegistryResult
208
215
 
209
216
  ### `BaseViewContextValue<TRegistry>`
210
217
 
211
- Framework-agnostic base for every framework's `ViewContextValue`. Holds `spec`, `handlers`, `registry`, and `store` fields that are identical across React, Vue, Solid, and Svelte.
218
+ The framework-agnostic base of the `ViewContextValue` type in each framework. It holds the `spec`, `handlers`, `registry`, and `store` fields. These fields are identical in React, Vue, Solid, and Svelte.
212
219
 
213
220
  ## Testing
214
221
 
@@ -1,18 +1,19 @@
1
1
  /**
2
- * AbstractActor base class for Play Architecture
2
+ * The AbstractActor base class of the Play Architecture
3
3
  *
4
- * Extends XState Actor to maintain ecosystem compatibility (inspection, devtools)
5
- * while enforcing signal protocol for Actor Infrastructure communication.
4
+ * It extends the XState Actor class, which keeps the compatibility with the
5
+ * ecosystem, such as the inspection and the devtools. It also enforces the signal
6
+ * protocol of the communication between the Actor and the infrastructure.
6
7
  *
7
- * Per RFC section 5.3, the Actor exposes a minimal protocol:
8
- * - state: Current machine state snapshot
9
- * - send: Event dispatch method
8
+ * RFC section 5.3 gives the minimal protocol of the Actor:
9
+ * - state: the snapshot of the current machine state
10
+ * - send: the method that sends an event
10
11
  *
11
- * Optional capabilities are provided via interfaces:
12
- * - Routable: For actors that support routing
13
- * - Viewable: For actors that support view rendering
12
+ * Two interfaces give the optional capabilities:
13
+ * - Routable: for an actor with a routing support
14
+ * - Viewable: for an actor with a view rendering
14
15
  *
15
- * Concrete implementations are created by adapters (e.g., @xmachines/play-xstate).
16
+ * An adapter, such as @xmachines/play-xstate, makes the concrete implementations.
16
17
  *
17
18
  * @packageDocumentation
18
19
  */
@@ -20,46 +21,47 @@ import { Actor, type AnyActorLogic, type EventObject } from "xstate";
20
21
  import type { Signal } from "@xmachines/play-signals";
21
22
  import type { Spec, StateStore, RenderErrorHandler, ActionHandler } from "@xmachines/json-render-core";
22
23
  /**
23
- * Optional capability: Routing support
24
+ * An optional capability: the routing support
24
25
  */
25
26
  export interface Routable {
26
27
  readonly currentRoute: Signal.Computed<string | null>;
27
28
  readonly initialRoute: string | null;
28
29
  }
29
30
  /**
30
- * XMachines extension of `@xmachines/json-render-core` `Spec`.
31
+ * The XMachines extension of the `Spec` type of `@xmachines/json-render-core`.
31
32
  *
32
- * The machine's context is projected into every derived view's state store
33
- * under the read-only `/context` subtree, so specs read it through the
34
- * ordinary `{ $state: "/context/…" }` grammar in props, `visible`
35
- * conditions, and `repeat.statePath` alike. The whole context is always
36
- * projected; a spec simply reads the paths it needs.
33
+ * Each derived view receives the machine context in its state store, under the
34
+ * read-only `/context` subtree. A spec therefore reads the context through the
35
+ * ordinary `{ $state: "/context/…" }` grammar: in a prop, in a `visible` condition,
36
+ * and in `repeat.statePath`. The store always holds the complete context, and a
37
+ * spec reads only the paths that it needs.
37
38
  */
38
39
  export interface PlaySpec extends Spec {
39
40
  /**
40
- * Identity of the view this derived spec came from set by
41
- * `deriveCurrentView` from the meta entry the derivation actually selected.
42
- * Providers key their store lifecycle on it: a changed `viewKey` reseeds the
43
- * store; an unchanged one refreshes `/context` in place, preserving
44
- * ephemeral view state. Never author this field in `meta.view`.
41
+ * The identity of the view of this derived spec. `deriveCurrentView` sets it from
42
+ * the meta entry that the derivation selected. A provider uses it as the key of its
43
+ * store lifecycle: a new `viewKey` seeds the store again, and the same `viewKey`
44
+ * refreshes `/context` in place, which keeps the ephemeral view state. Never write
45
+ * this field in `meta.view`.
45
46
  */
46
47
  readonly viewKey?: string;
47
48
  }
48
49
  /**
49
- * Identity helper that types a view spec literal as `PlaySpec` at the
50
- * definition site, giving compile-time validation and IDE autocomplete.
50
+ * The identity helper gives a view spec literal the type `PlaySpec` at the
51
+ * definition site. The compiler therefore checks the spec, and the IDE completes it.
51
52
  *
52
- * XState's `meta` field is typed as `Record<string, unknown>`, so TypeScript
53
- * cannot infer the spec shape from context. `typedSpec(...)` is the opt-in
54
- * mechanism that activates checking where the spec is written. `viewKey` is
55
- * excluded from the parameter — derivation stamps it and would silently
56
- * overwrite an authored value, so authoring one is rejected at compile time.
53
+ * The XState `meta` field has the type `Record<string, unknown>`. TypeScript
54
+ * therefore infers no spec shape from the context. `typedSpec(...)` is the
55
+ * mechanism that starts the check where you write the spec. The parameter holds no
56
+ * `viewKey`: the derivation stamps that field, and it overwrites a value from an
57
+ * author without a notice. Therefore the compiler refuses a `viewKey` here.
57
58
  *
58
- * Excess-property checking only applies to an inline object literal; for a
59
- * spec built in a variable or through spreads, use `satisfies PlaySpec` at
59
+ * The check of an excess property works on an inline object literal only. For a
60
+ * spec in a variable, or for a spec from a spread, write `satisfies PlaySpec` at
60
61
  * the literal instead.
61
62
  *
62
- * At runtime this is a no-op the spec object is returned unchanged.
63
+ * At run time this function does nothing: it returns the spec object without a
64
+ * change.
63
65
  *
64
66
  * @example
65
67
  * ```ts
@@ -79,50 +81,55 @@ export interface PlaySpec extends Spec {
79
81
  */
80
82
  export declare function typedSpec(spec: Omit<PlaySpec, "viewKey">): PlaySpec;
81
83
  /**
82
- * Actor capability for exposing renderable view state.
84
+ * The actor capability that exposes a renderable view state.
83
85
  *
84
- * `Viewable` marks actors that publish a `currentView` signal.
85
- * Renderers such as `PlayRenderer` consume this contract to resolve the
86
- * current view description into concrete UI without embedding view logic inside the
87
- * framework adapter.
86
+ * `Viewable` marks an actor that publishes a `currentView` signal.
87
+ * A renderer, such as `PlayRenderer`, reads this contract. It converts the
88
+ * description of the current view into a concrete UI, and the framework adapter
89
+ * therefore holds no view logic.
88
90
  */
89
91
  export interface Viewable {
90
92
  /**
91
- * Current view signal. Contains the json-render PlaySpec for the current machine
92
- * state, or null when no view is active.
93
+ * The signal of the current view. It holds the json-render PlaySpec of the current
94
+ * machine state, or null when no view is active.
93
95
  *
94
- * Infrastructure renders view Logic-Driven UI invariant.
96
+ * The infrastructure renders the view. This is the Logic-Driven UI invariant.
95
97
  */
96
98
  readonly currentView: Signal.State<PlaySpec | null>;
97
99
  }
98
100
  /**
99
- * Framework-agnostic base for every framework's `ViewContextValue`.
101
+ * The framework-agnostic base of the `ViewContextValue` type in each framework.
100
102
  *
101
- * Holds the three fields that are identical across React, Vue, Solid, and Svelte.
102
- * `registry` is framework-specific (each framework has its own `ComponentRegistry`
103
- * type) so it is typed via `TRegistry` the same generic used in `BaseActorProviderProps`.
103
+ * It holds the three fields that are identical in React, Vue, Solid, and Svelte.
104
+ * The `registry` field belongs to one framework, because each framework has its own
105
+ * `ComponentRegistry` type. Therefore `TRegistry` gives its type, and this is the
106
+ * same generic parameter as in `BaseActorProviderProps`.
104
107
  *
105
- * @typeParam TRegistry - The framework's component registry type (e.g. `ComponentRegistry` from `@xmachines/json-render-react`).
108
+ * @typeParam TRegistry - The registry type of the component of the framework, for example `ComponentRegistry` from `@xmachines/json-render-react`.
106
109
  */
107
110
  export interface BaseViewContextValue<TRegistry extends object> {
108
111
  /** The current PlaySpec to render. */
109
112
  spec: PlaySpec;
110
- /** Action handlers resolved against the live StateStore. */
113
+ /** The action handlers, resolved against the live StateStore. */
111
114
  handlers: Record<string, ActionHandler>;
112
- /** Component registry from registryResult.registry. */
115
+ /** The component registry, from registryResult.registry. */
113
116
  registry: TRegistry;
114
- /** The active StateStore — pass to JSONUIProvider/JsonUIProvider as `store` to share state across providers. */
117
+ /**
118
+ * The active StateStore. Give it to JSONUIProvider or JsonUIProvider as `store`, and the providers then share the state.
119
+ */
115
120
  store: StateStore;
116
121
  }
117
122
  /**
118
- * Framework-agnostic base props shared by every `ActorProvider` implementation
119
- * (React, Vue, Solid, Svelte). `TRegistry` captures the framework-specific
120
- * `DefineRegistryResult` type; `RenderErrorHandler` is sourced from
121
- * `@xmachines/json-render-core` so no second generic is needed.
123
+ * The framework-agnostic base props. Every `ActorProvider` implementation shares
124
+ * them: React, Vue, Solid, and Svelte. `TRegistry` holds the
125
+ * `DefineRegistryResult` type of the framework. `RenderErrorHandler` comes from
126
+ * `@xmachines/json-render-core`, and a second generic parameter is therefore not
127
+ * necessary.
122
128
  *
123
- * Framework packages extend this with their `fallback`, `onError`, and `children` fields.
129
+ * Each framework package extends this interface with its `fallback` field, its
130
+ * `onError` field, and its `children` field.
124
131
  *
125
- * @typeParam TRegistry - The framework's `DefineRegistryResult` type.
132
+ * @typeParam TRegistry - The `DefineRegistryResult` type of the framework.
126
133
  *
127
134
  * @example
128
135
  * ```ts
@@ -139,60 +146,61 @@ export interface BaseActorProviderProps<TRegistry extends {
139
146
  registry: object;
140
147
  handlers: (...args: never[]) => unknown;
141
148
  }> {
142
- /** Actor instance with currentView signal (requires Viewable capability). */
149
+ /** The actor instance with the currentView signal. It requires the Viewable capability. */
143
150
  actor: AbstractActor<AnyActorLogic> & Viewable;
144
- /** Full result from defineRegistry() contains the component registry and action handlers factory. */
151
+ /** The complete result of defineRegistry(). It holds the component registry and the factory of the action handlers. */
145
152
  registryResult: TRegistry;
146
153
  /**
147
- * Optional external StateStore (controlled mode).
148
- * When provided, spec.state is ignored and this store is the single source of truth.
149
- * When omitted, a fresh @xstate/store atom is created per view transition from spec.state.
154
+ * The optional external StateStore, which is the controlled mode.
155
+ * With this option, the provider ignores spec.state, and this store is the single
156
+ * source of truth. Without it, the provider makes a new @xstate/store atom for each
157
+ * view transition, with the values of spec.state.
150
158
  */
151
159
  store?: StateStore;
152
160
  /**
153
- * Called when an individual catalog component throws during render.
154
- * Takes precedence over any onRenderError set via defineRegistry.
161
+ * The provider calls it when one catalog component throws during a render.
162
+ * This handler replaces every onRenderError of defineRegistry.
155
163
  */
156
164
  onRenderError?: RenderErrorHandler;
157
165
  }
158
166
  /**
159
- * Abstract base class for Play Architecture actors.
160
- *
161
- * Provides signal-driven state observation that integrates with XState ecosystem
162
- * tooling (devtools, inspection) while exposing reactive signals for
163
- * Infrastructure layer communication.
164
- *
165
- * **A subclass IS the actor.** Forward the logic *and* its options to
166
- * `super(logic, options)`, then observe `this`. Holding a separately
167
- * constructed actor alongside leaves this instance running as an empty second
168
- * actor, and every inherited member `system`, `sessionId`, `clock`, the
169
- * internal `_send` that receives `sendTo()` traffic, and anything a future
170
- * XState version adds answers from that empty one until it is individually
171
- * forwarded.
172
- *
173
- * @typeParam TLogic - XState actor logic type
174
- * @typeParam TEvent - Event type constraint (defaults to EventObject)
167
+ * The abstract base class of an actor of the Play Architecture.
168
+ *
169
+ * It observes the state through the signals, and it works with the tools of the
170
+ * XState ecosystem, such as the devtools and the inspection. It also exposes the
171
+ * reactive signals of the communication with the infrastructure layer.
172
+ *
173
+ * **A subclass IS the actor.** Give the logic *and* its options to
174
+ * `super(logic, options)`, then observe `this`. A separate actor beside this
175
+ * instance leaves this instance as an empty second actor. Every inherited member
176
+ * then answers from that empty actor, until you forward each one: `system`,
177
+ * `sessionId`, `clock`, the internal `_send` that receives the traffic of
178
+ * `sendTo()`, and each member that a later XState version adds.
179
+ *
180
+ * @typeParam TLogic - The type of the XState actor logic
181
+ * @typeParam TEvent - The constraint of the event type. The default is EventObject
175
182
  */
176
183
  export declare abstract class AbstractActor<TLogic extends AnyActorLogic, TEvent extends EventObject = EventObject> extends Actor<TLogic> {
177
184
  /**
178
- * Reactive snapshot of current actor state.
185
+ * The reactive snapshot of the current actor state.
179
186
  *
180
- * Infrastructure observes this signal to react to state changes without
181
- * directly coupling to the actor's internal state machine implementation.
187
+ * The infrastructure observes this signal, and it reacts to each state change. It
188
+ * therefore holds no coupling to the internal state machine of the actor.
182
189
  */
183
190
  abstract state: Signal.State<unknown>;
184
191
  /**
185
- * Send event to Actor.
192
+ * Sends an event to the Actor.
186
193
  *
187
- * Constrained to TEvent for type safety in concrete implementations.
194
+ * The constraint is TEvent, which gives the type safety of a concrete
195
+ * implementation.
188
196
  *
189
- * Note for implementations that wrap `send` (validating the event, or
190
- * notifying hooks around it): this declaration is abstract purely to narrow
191
- * the event type, and TypeScript forbids `super` calls to an abstract
192
- * member. Reach XState's own implementation with
193
- * `Actor.prototype.send.call(this, event)` instead. Making this concrete
194
- * would allow `super.send()` but would force every existing subclass to add
195
- * an `override` modifier — a breaking change for adapters outside this repo.
197
+ * A note for an implementation that wraps `send`, to check the event or to notify a
198
+ * hook around it: this declaration is abstract for one reason only, to narrow the
199
+ * event type, and TypeScript forbids a `super` call to an abstract member. Reach
200
+ * the implementation of XState with `Actor.prototype.send.call(this, event)`
201
+ * instead. A concrete declaration permits `super.send()`, but it also forces an
202
+ * `override` modifier in every subclass that exists now, and that is a breaking
203
+ * change for an adapter outside this repository.
196
204
  */
197
205
  abstract send(event: TEvent): void;
198
206
  }
@@ -1 +1 @@
1
- {"version":3,"file":"abstract-actor.d.ts","sourceRoot":"","sources":["../src/abstract-actor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EACX,IAAI,EACJ,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,MAAM,6BAA6B,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAS,SAAQ,IAAI;IACrC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,QAAQ,CAEnE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB,CAAC,SAAS,SAAS,MAAM;IAC7D,sCAAsC;IACtC,IAAI,EAAE,QAAQ,CAAC;IACf,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC,uDAAuD;IACvD,QAAQ,EAAE,SAAS,CAAC;IACpB,gHAAgH;IAChH,KAAK,EAAE,UAAU,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,sBAAsB,CACtC,SAAS,SAAS;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAA;CAAE;IAE/E,6EAA6E;IAC7E,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;IAC/C,uGAAuG;IACvG,cAAc,EAAE,SAAS,CAAC;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,8BAAsB,aAAa,CAClC,MAAM,SAAS,aAAa,EAC5B,MAAM,SAAS,WAAW,GAAG,WAAW,CACvC,SAAQ,KAAK,CAAC,MAAM,CAAC;IACtB;;;;;OAKG;IACH,SAAgB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE7C;;;;;;;;;;;;OAYG;aACsB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAClD"}
1
+ {"version":3,"file":"abstract-actor.d.ts","sourceRoot":"","sources":["../src/abstract-actor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EACX,IAAI,EACJ,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,MAAM,6BAA6B,CAAC;AAErC;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAS,SAAQ,IAAI;IACrC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,QAAQ,CAEnE;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB,CAAC,SAAS,SAAS,MAAM;IAC7D,sCAAsC;IACtC,IAAI,EAAE,QAAQ,CAAC;IACf,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC,4DAA4D;IAC5D,QAAQ,EAAE,SAAS,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,UAAU,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,sBAAsB,CACtC,SAAS,SAAS;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,OAAO,CAAA;CAAE;IAE/E,2FAA2F;IAC3F,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC;IAC/C,uHAAuH;IACvH,cAAc,EAAE,SAAS,CAAC;IAC1B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,8BAAsB,aAAa,CAClC,MAAM,SAAS,aAAa,EAC5B,MAAM,SAAS,WAAW,GAAG,WAAW,CACvC,SAAQ,KAAK,CAAC,MAAM,CAAC;IACtB;;;;;OAKG;IACH,SAAgB,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAE7C;;;;;;;;;;;;;OAaG;aACsB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAClD"}
@@ -1,37 +1,39 @@
1
1
  /**
2
- * AbstractActor base class for Play Architecture
2
+ * The AbstractActor base class of the Play Architecture
3
3
  *
4
- * Extends XState Actor to maintain ecosystem compatibility (inspection, devtools)
5
- * while enforcing signal protocol for Actor Infrastructure communication.
4
+ * It extends the XState Actor class, which keeps the compatibility with the
5
+ * ecosystem, such as the inspection and the devtools. It also enforces the signal
6
+ * protocol of the communication between the Actor and the infrastructure.
6
7
  *
7
- * Per RFC section 5.3, the Actor exposes a minimal protocol:
8
- * - state: Current machine state snapshot
9
- * - send: Event dispatch method
8
+ * RFC section 5.3 gives the minimal protocol of the Actor:
9
+ * - state: the snapshot of the current machine state
10
+ * - send: the method that sends an event
10
11
  *
11
- * Optional capabilities are provided via interfaces:
12
- * - Routable: For actors that support routing
13
- * - Viewable: For actors that support view rendering
12
+ * Two interfaces give the optional capabilities:
13
+ * - Routable: for an actor with a routing support
14
+ * - Viewable: for an actor with a view rendering
14
15
  *
15
- * Concrete implementations are created by adapters (e.g., @xmachines/play-xstate).
16
+ * An adapter, such as @xmachines/play-xstate, makes the concrete implementations.
16
17
  *
17
18
  * @packageDocumentation
18
19
  */
19
20
  import { Actor } from "xstate";
20
21
  /**
21
- * Identity helper that types a view spec literal as `PlaySpec` at the
22
- * definition site, giving compile-time validation and IDE autocomplete.
22
+ * The identity helper gives a view spec literal the type `PlaySpec` at the
23
+ * definition site. The compiler therefore checks the spec, and the IDE completes it.
23
24
  *
24
- * XState's `meta` field is typed as `Record<string, unknown>`, so TypeScript
25
- * cannot infer the spec shape from context. `typedSpec(...)` is the opt-in
26
- * mechanism that activates checking where the spec is written. `viewKey` is
27
- * excluded from the parameter — derivation stamps it and would silently
28
- * overwrite an authored value, so authoring one is rejected at compile time.
25
+ * The XState `meta` field has the type `Record<string, unknown>`. TypeScript
26
+ * therefore infers no spec shape from the context. `typedSpec(...)` is the
27
+ * mechanism that starts the check where you write the spec. The parameter holds no
28
+ * `viewKey`: the derivation stamps that field, and it overwrites a value from an
29
+ * author without a notice. Therefore the compiler refuses a `viewKey` here.
29
30
  *
30
- * Excess-property checking only applies to an inline object literal; for a
31
- * spec built in a variable or through spreads, use `satisfies PlaySpec` at
31
+ * The check of an excess property works on an inline object literal only. For a
32
+ * spec in a variable, or for a spec from a spread, write `satisfies PlaySpec` at
32
33
  * the literal instead.
33
34
  *
34
- * At runtime this is a no-op the spec object is returned unchanged.
35
+ * At run time this function does nothing: it returns the spec object without a
36
+ * change.
35
37
  *
36
38
  * @example
37
39
  * ```ts
@@ -53,22 +55,21 @@ export function typedSpec(spec) {
53
55
  return spec;
54
56
  }
55
57
  /**
56
- * Abstract base class for Play Architecture actors.
58
+ * The abstract base class of an actor of the Play Architecture.
57
59
  *
58
- * Provides signal-driven state observation that integrates with XState ecosystem
59
- * tooling (devtools, inspection) while exposing reactive signals for
60
- * Infrastructure layer communication.
60
+ * It observes the state through the signals, and it works with the tools of the
61
+ * XState ecosystem, such as the devtools and the inspection. It also exposes the
62
+ * reactive signals of the communication with the infrastructure layer.
61
63
  *
62
- * **A subclass IS the actor.** Forward the logic *and* its options to
63
- * `super(logic, options)`, then observe `this`. Holding a separately
64
- * constructed actor alongside leaves this instance running as an empty second
65
- * actor, and every inherited member `system`, `sessionId`, `clock`, the
66
- * internal `_send` that receives `sendTo()` traffic, and anything a future
67
- * XState version adds answers from that empty one until it is individually
68
- * forwarded.
64
+ * **A subclass IS the actor.** Give the logic *and* its options to
65
+ * `super(logic, options)`, then observe `this`. A separate actor beside this
66
+ * instance leaves this instance as an empty second actor. Every inherited member
67
+ * then answers from that empty actor, until you forward each one: `system`,
68
+ * `sessionId`, `clock`, the internal `_send` that receives the traffic of
69
+ * `sendTo()`, and each member that a later XState version adds.
69
70
  *
70
- * @typeParam TLogic - XState actor logic type
71
- * @typeParam TEvent - Event type constraint (defaults to EventObject)
71
+ * @typeParam TLogic - The type of the XState actor logic
72
+ * @typeParam TEvent - The constraint of the event type. The default is EventObject
72
73
  */
73
74
  export class AbstractActor extends Actor {
74
75
  }
@@ -1 +1 @@
1
- {"version":3,"file":"abstract-actor.js","sourceRoot":"","sources":["../src/abstract-actor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,KAAK,EAAwC,MAAM,QAAQ,CAAC;AAqCrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,SAAS,CAAC,IAA+B;IACxD,OAAO,IAAI,CAAC;AACb,CAAC;AAiFD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAgB,aAGpB,SAAQ,KAAa;CAuBtB"}
1
+ {"version":3,"file":"abstract-actor.js","sourceRoot":"","sources":["../src/abstract-actor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,KAAK,EAAwC,MAAM,QAAQ,CAAC;AAqCrE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,UAAU,SAAS,CAAC,IAA+B;IACxD,OAAO,IAAI,CAAC;AACb,CAAC;AAuFD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAgB,aAGpB,SAAQ,KAAa;CAwBtB"}