@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 +61 -54
- package/dist/abstract-actor.d.ts +97 -89
- package/dist/abstract-actor.d.ts.map +1 -1
- package/dist/abstract-actor.js +34 -33
- package/dist/abstract-actor.js.map +1 -1
- package/dist/context-projection.d.ts +74 -67
- package/dist/context-projection.d.ts.map +1 -1
- package/dist/context-projection.js +90 -82
- package/dist/context-projection.js.map +1 -1
- package/dist/index.d.ts +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -9
- package/dist/index.js.map +1 -1
- package/dist/provider-guards.d.ts +37 -33
- package/dist/provider-guards.d.ts.map +1 -1
- package/dist/provider-guards.js +34 -30
- package/dist/provider-guards.js.map +1 -1
- package/dist/view-store-lifecycle.d.ts +46 -41
- package/dist/view-store-lifecycle.d.ts.map +1 -1
- package/dist/view-store-lifecycle.js +28 -25
- package/dist/view-store-lifecycle.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Abstract Actor base class for XMachines Play Architecture.
|
|
4
4
|
|
|
5
|
-
[](https://opensource.org/licenses/MIT) [.
|
|
5
|
+
[](https://opensource.org/licenses/MIT) [](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
|
|
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`
|
|
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
|
|
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
|
-
|
|
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` |
|
|
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
|
-
|
|
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
|
-
|
|
44
|
+
The abstract base class extends the XState `Actor<TLogic>` class.
|
|
47
45
|
|
|
48
|
-
A subclass **is** the actor
|
|
49
|
-
instance holds the running machine
|
|
50
|
-
prototype
|
|
51
|
-
TypeScript forbids `super`
|
|
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
|
-
|
|
92
|
-
`meta` field
|
|
93
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
through the ordinary `{ $state: "/context/…" }` grammar
|
|
118
|
-
`repeat.statePath
|
|
119
|
-
|
|
120
|
-
`/context` is read-only by design
|
|
121
|
-
|
|
122
|
-
send
|
|
123
|
-
`spec.state
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
`/context/username`
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
context is
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
|
154
|
-
> prop-enrichment pass
|
|
155
|
-
>
|
|
156
|
-
> let
|
|
157
|
-
> projection filter
|
|
158
|
-
>
|
|
159
|
-
>
|
|
160
|
-
>
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
package/dist/abstract-actor.d.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AbstractActor base class
|
|
2
|
+
* The AbstractActor base class of the Play Architecture
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
8
|
-
* - state:
|
|
9
|
-
* - send:
|
|
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
|
-
*
|
|
12
|
-
* - Routable:
|
|
13
|
-
* - Viewable:
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
|
31
|
+
* The XMachines extension of the `Spec` type of `@xmachines/json-render-core`.
|
|
31
32
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* ordinary `{ $state: "/context/…" }` grammar
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
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
|
-
*
|
|
50
|
-
* definition site
|
|
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
|
|
53
|
-
*
|
|
54
|
-
* mechanism that
|
|
55
|
-
*
|
|
56
|
-
*
|
|
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
|
-
*
|
|
59
|
-
* spec
|
|
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
|
|
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
|
-
*
|
|
84
|
+
* The actor capability that exposes a renderable view state.
|
|
83
85
|
*
|
|
84
|
-
* `Viewable` marks
|
|
85
|
-
*
|
|
86
|
-
* current view
|
|
87
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
101
|
+
* The framework-agnostic base of the `ViewContextValue` type in each framework.
|
|
100
102
|
*
|
|
101
|
-
*
|
|
102
|
-
* `registry`
|
|
103
|
-
* type
|
|
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
|
|
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
|
-
/**
|
|
113
|
+
/** The action handlers, resolved against the live StateStore. */
|
|
111
114
|
handlers: Record<string, ActionHandler>;
|
|
112
|
-
/**
|
|
115
|
+
/** The component registry, from registryResult.registry. */
|
|
113
116
|
registry: TRegistry;
|
|
114
|
-
/**
|
|
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
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* `DefineRegistryResult` type
|
|
121
|
-
* `@xmachines/json-render-core
|
|
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
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
149
|
+
/** The actor instance with the currentView signal. It requires the Viewable capability. */
|
|
143
150
|
actor: AbstractActor<AnyActorLogic> & Viewable;
|
|
144
|
-
/**
|
|
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
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
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
|
-
*
|
|
154
|
-
*
|
|
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
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* **A subclass IS the actor.**
|
|
166
|
-
* `super(logic, options)`, then observe `this`.
|
|
167
|
-
*
|
|
168
|
-
* actor,
|
|
169
|
-
* internal `_send` that receives
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* @typeParam
|
|
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
|
-
*
|
|
185
|
+
* The reactive snapshot of the current actor state.
|
|
179
186
|
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
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
|
-
*
|
|
192
|
+
* Sends an event to the Actor.
|
|
186
193
|
*
|
|
187
|
-
*
|
|
194
|
+
* The constraint is TEvent, which gives the type safety of a concrete
|
|
195
|
+
* implementation.
|
|
188
196
|
*
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* `
|
|
194
|
-
*
|
|
195
|
-
*
|
|
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
|
|
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"}
|
package/dist/abstract-actor.js
CHANGED
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* AbstractActor base class
|
|
2
|
+
* The AbstractActor base class of the Play Architecture
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
-
*
|
|
8
|
-
* - state:
|
|
9
|
-
* - send:
|
|
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
|
-
*
|
|
12
|
-
* - Routable:
|
|
13
|
-
* - Viewable:
|
|
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
|
-
*
|
|
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
|
-
*
|
|
22
|
-
* definition site
|
|
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
|
|
25
|
-
*
|
|
26
|
-
* mechanism that
|
|
27
|
-
*
|
|
28
|
-
*
|
|
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
|
-
*
|
|
31
|
-
* spec
|
|
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
|
|
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
|
-
*
|
|
58
|
+
* The abstract base class of an actor of the Play Architecture.
|
|
57
59
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
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.**
|
|
63
|
-
* `super(logic, options)`, then observe `this`.
|
|
64
|
-
*
|
|
65
|
-
* actor,
|
|
66
|
-
* internal `_send` that receives
|
|
67
|
-
*
|
|
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
|
|
71
|
-
* @typeParam TEvent -
|
|
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
|
|
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"}
|