@xmachines/play-xstate 3.0.0 → 4.0.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 +148 -57
- package/dist/capabilities.d.ts +92 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +4 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/define-player.d.ts +7 -1
- package/dist/define-player.d.ts.map +1 -1
- package/dist/define-player.js +9 -60
- package/dist/define-player.js.map +1 -1
- package/dist/errors.d.ts +29 -26
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +53 -35
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -4
- package/dist/index.js.map +1 -1
- package/dist/player-actor.d.ts +52 -117
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +72 -228
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/derive-current-route.d.ts +1 -36
- package/dist/routing/derive-current-route.d.ts.map +1 -1
- package/dist/routing/derive-current-route.js +2 -76
- package/dist/routing/derive-current-route.js.map +1 -1
- package/dist/routing/derive-initial-route.d.ts.map +1 -1
- package/dist/routing/derive-initial-route.js +11 -0
- package/dist/routing/derive-initial-route.js.map +1 -1
- package/dist/routing/derive-route.d.ts +81 -2
- package/dist/routing/derive-route.d.ts.map +1 -1
- package/dist/routing/derive-route.js +97 -3
- package/dist/routing/derive-route.js.map +1 -1
- package/dist/routing/format-play-route-transitions.d.ts +8 -2
- package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
- package/dist/routing/format-play-route-transitions.js +170 -43
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/routing/index.d.ts +1 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/types.d.ts +9 -5
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/state-meta.d.ts +52 -0
- package/dist/state-meta.d.ts.map +1 -0
- package/dist/state-meta.js +77 -0
- package/dist/state-meta.js.map +1 -0
- package/dist/types.d.ts +18 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/view/derive-current-view.d.ts +1 -1
- package/dist/view/derive-current-view.d.ts.map +1 -1
- package/dist/view/derive-current-view.js +2 -2
- package/dist/view/derive-current-view.js.map +1 -1
- package/dist/with-routing.d.ts +45 -0
- package/dist/with-routing.d.ts.map +1 -0
- package/dist/with-routing.js +78 -0
- package/dist/with-routing.js.map +1 -0
- package/dist/with-view.d.ts +42 -0
- package/dist/with-view.d.ts.map +1 -0
- package/dist/with-view.js +150 -0
- package/dist/with-view.js.map +1 -0
- package/package.json +38 -17
- package/dist/guards/compose.d.ts +0 -158
- package/dist/guards/compose.d.ts.map +0 -1
- package/dist/guards/compose.js +0 -188
- package/dist/guards/compose.js.map +0 -1
- package/dist/guards/helpers.d.ts +0 -62
- package/dist/guards/helpers.d.ts.map +0 -1
- package/dist/guards/helpers.js +0 -85
- package/dist/guards/helpers.js.map +0 -1
- package/dist/guards/index.d.ts +0 -20
- package/dist/guards/index.d.ts.map +0 -1
- package/dist/guards/index.js +0 -18
- package/dist/guards/index.js.map +0 -1
- package/dist/guards/types.d.ts +0 -22
- package/dist/guards/types.d.ts.map +0 -1
- package/dist/guards/types.js +0 -2
- package/dist/guards/types.js.map +0 -1
package/dist/player-actor.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { Actor, } from "xstate";
|
|
2
|
-
import { AbstractActor, reuseComposedState, shallowEqualExcept, } from "@xmachines/play-actor";
|
|
3
2
|
import { DISPOSE } from "@xmachines/play";
|
|
4
3
|
import { Signal } from "@xmachines/play-signals";
|
|
5
4
|
import { ActorThrewNonErrorError, InvalidEventError, InvalidMachineError } from "./errors.js";
|
|
6
|
-
import { deriveCurrentRoute, deriveInitialRoute } from "./routing/index.js";
|
|
7
|
-
import { deriveCurrentView } from "./view/derive-current-view.js";
|
|
8
5
|
/**
|
|
9
6
|
* Tells you if a value is an `Error`, by its identity or by its brand: `instanceof`
|
|
10
7
|
* misses an error from another realm, such as an iframe or `node:vm`. The function
|
|
@@ -25,13 +22,15 @@ const isRealError = (value) => {
|
|
|
25
22
|
/**
|
|
26
23
|
* Normalizes a failure of the actor for `onError`.
|
|
27
24
|
*
|
|
25
|
+
* @internal
|
|
26
|
+
*
|
|
28
27
|
* The function gives an `Error` to the handler without a change. The error of the
|
|
29
28
|
* machine therefore keeps its identity: an `instanceof` test of a consumer still
|
|
30
29
|
* works, and the path without an `onError` throws that same object again. Every
|
|
31
30
|
* other value is ours to build, and it becomes a `PlayError` with a code. That
|
|
32
31
|
* error carries the value from the throw as its `cause`.
|
|
33
32
|
*/
|
|
34
|
-
const toError = (value) => {
|
|
33
|
+
export const toError = (value) => {
|
|
35
34
|
try {
|
|
36
35
|
if (isRealError(value)) {
|
|
37
36
|
return value;
|
|
@@ -44,48 +43,6 @@ const toError = (value) => {
|
|
|
44
43
|
}
|
|
45
44
|
return new ActorThrewNonErrorError(value);
|
|
46
45
|
};
|
|
47
|
-
/**
|
|
48
|
-
* The structural equality of two derived view specs, with a limit on its depth.
|
|
49
|
-
*
|
|
50
|
-
* The function walks exactly the shape that `deriveCurrentView` builds: the spec
|
|
51
|
-
* fields, then `elements`, then the `props` object of each element. It compares
|
|
52
|
-
* each leaf with `Object.is`. It never enters the VALUE of a prop: a new reference
|
|
53
|
-
* therefore emits the view again, also when the contents are equal. This design
|
|
54
|
-
* keeps two things correct: a prop of a container (a Map, a Set, or an instance of a
|
|
55
|
-
* class, which a structural comparison cannot see), and a cyclic value, which gives
|
|
56
|
-
* a structural comparison a recursion without an end.
|
|
57
|
-
*/
|
|
58
|
-
const viewSpecsEquivalent = (a, b) => {
|
|
59
|
-
if (a === b)
|
|
60
|
-
return true;
|
|
61
|
-
if (!a || !b)
|
|
62
|
-
return false;
|
|
63
|
-
if (!shallowEqualExcept(a, b, "elements"))
|
|
64
|
-
return false;
|
|
65
|
-
const aElements = a.elements ?? {};
|
|
66
|
-
const bElements = b.elements ?? {};
|
|
67
|
-
// A derived spec spreads the same static meta.view. Therefore the elements
|
|
68
|
-
// usually have the same reference, and the walk over each element is then not
|
|
69
|
-
// necessary.
|
|
70
|
-
if (aElements === bElements)
|
|
71
|
-
return true;
|
|
72
|
-
const elementKeys = Object.keys(aElements);
|
|
73
|
-
if (elementKeys.length !== Object.keys(bElements).length)
|
|
74
|
-
return false;
|
|
75
|
-
for (const key of elementKeys) {
|
|
76
|
-
const aElement = aElements[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
77
|
-
const bElement = bElements[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
78
|
-
if (aElement === bElement)
|
|
79
|
-
continue;
|
|
80
|
-
if (!aElement || !bElement)
|
|
81
|
-
return false;
|
|
82
|
-
if (!shallowEqualExcept(aElement, bElement, "props"))
|
|
83
|
-
return false;
|
|
84
|
-
if (!shallowEqualExcept(aElement.props ?? {}, bElement.props ?? {}))
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
return true;
|
|
88
|
-
};
|
|
89
46
|
/**
|
|
90
47
|
* Tells you if a snapshot is worth a propagation to the signals: an active
|
|
91
48
|
* snapshot, or a "done" snapshot, which means that the machine reached a final state
|
|
@@ -97,8 +54,8 @@ const isObservableSnapshot = (snapshot) => snapshot.status === "active" || snaps
|
|
|
97
54
|
/**
|
|
98
55
|
* The concrete XState actor. It implements the signal protocol of the Play Architecture
|
|
99
56
|
*
|
|
100
|
-
* The class extends
|
|
101
|
-
*
|
|
57
|
+
* The class extends the `Actor` class of XState directly, and it implements
|
|
58
|
+
* {@link @xmachines/play-actor!PlayActor}. It gives you the XState v5 integration, and it keeps the
|
|
102
59
|
* compatibility with the ecosystem, such as the XState inspection and the devtools.
|
|
103
60
|
* The constructor of the base class receives the machine. Therefore a `PlayerActor`
|
|
104
61
|
* **is** the XState actor, and it is no wrapper around one: every member of the
|
|
@@ -106,8 +63,8 @@ const isObservableSnapshot = (snapshot) => snapshot.status === "active" || snaps
|
|
|
106
63
|
* reactive state on the TC39 Signals for the observation by the infrastructure.
|
|
107
64
|
*
|
|
108
65
|
* **Capabilities:** the class implements both the
|
|
109
|
-
* {@link @xmachines/play-
|
|
110
|
-
* {@link @xmachines/play-
|
|
66
|
+
* {@link @xmachines/play-router!index.Routable} interface and the
|
|
67
|
+
* {@link @xmachines/play-view!index.Viewable} interface. It therefore supports the
|
|
111
68
|
* routing and the view rendering.
|
|
112
69
|
*
|
|
113
70
|
* **Architectural context:** the class implements **Actor Authority (INV-01)**,
|
|
@@ -122,7 +79,7 @@ const isObservableSnapshot = (snapshot) => snapshot.status === "active" || snaps
|
|
|
122
79
|
* The creation of an actor, and its lifecycle
|
|
123
80
|
* ```typescript
|
|
124
81
|
* import { setup } from "xstate";
|
|
125
|
-
* import { definePlayer } from "@xmachines/play-xstate";
|
|
82
|
+
* import { definePlayer, compose, PlayerActor } from "@xmachines/play-xstate";
|
|
126
83
|
*
|
|
127
84
|
* const machine = setup({}).createMachine({
|
|
128
85
|
* initial: 'idle',
|
|
@@ -168,9 +125,9 @@ const isObservableSnapshot = (snapshot) => snapshot.status === "active" || snaps
|
|
|
168
125
|
*
|
|
169
126
|
* @see [Play RFC](../../docs/rfc/play.md)
|
|
170
127
|
* @see {@link definePlayer} for the creation through a factory
|
|
171
|
-
* @see {@link @xmachines/play-actor!
|
|
172
|
-
* @see {@link @xmachines/play-
|
|
173
|
-
* @see {@link @xmachines/play-
|
|
128
|
+
* @see {@link @xmachines/play-actor!PlayActor} for the signal protocol
|
|
129
|
+
* @see {@link @xmachines/play-router!index.Routable} for the routing capability
|
|
130
|
+
* @see {@link @xmachines/play-view!index.Viewable} for the view rendering capability
|
|
174
131
|
*
|
|
175
132
|
* @remarks
|
|
176
133
|
* **The routing:** this actor supports the `route: {}` config pattern of XState and
|
|
@@ -183,8 +140,21 @@ const isObservableSnapshot = (snapshot) => snapshot.status === "active" || snaps
|
|
|
183
140
|
* PlayRenderer is therefore correct. The class derives each view at the entry of a
|
|
184
141
|
* state and keeps it, and it computes no view on a read.
|
|
185
142
|
*/
|
|
186
|
-
export class PlayerActor extends
|
|
143
|
+
export class PlayerActor extends Actor {
|
|
187
144
|
playerOptions;
|
|
145
|
+
/**
|
|
146
|
+
* The three inputs of the constructor that a CAPABILITY needs.
|
|
147
|
+
*
|
|
148
|
+
* A mixin over a generic base cannot declare a constructor: TypeScript then demands the
|
|
149
|
+
* signature `...args: any[]` (TS2545), which this workspace does not write. A field
|
|
150
|
+
* initializer of a subclass runs after `super()` instead, and it reads these. The
|
|
151
|
+
* routing capability derives `initialRoute` from all three.
|
|
152
|
+
*/
|
|
153
|
+
playerMachine;
|
|
154
|
+
/** @see {@link playerMachine} */
|
|
155
|
+
playerInput;
|
|
156
|
+
/** @see {@link playerMachine} */
|
|
157
|
+
playerRestoredSnapshot;
|
|
188
158
|
/**
|
|
189
159
|
* The live options object of the caller, or an empty object during the construction.
|
|
190
160
|
*
|
|
@@ -204,16 +174,7 @@ export class PlayerActor extends AbstractActor {
|
|
|
204
174
|
get hooks() {
|
|
205
175
|
return this.playerOptions ?? {};
|
|
206
176
|
}
|
|
207
|
-
|
|
208
|
-
* The last snapshot of the view pipeline. XState notifies each observer on EVERY
|
|
209
|
-
* event that it processes, and an event that it ignores delivers the identical
|
|
210
|
-
* snapshot again. deriveCurrentView is pure in the snapshot. Therefore an identical
|
|
211
|
-
* reference can change no result. The first value is undefined, and never a
|
|
212
|
-
* snapshot: the snapshot of the construction has the same reference as the snapshot
|
|
213
|
-
* that start() replays, and that value therefore stops the first view.
|
|
214
|
-
*/
|
|
215
|
-
lastViewSnapshot = undefined;
|
|
216
|
-
// The requirements of the AbstractActor protocol
|
|
177
|
+
// The requirements of the PlayActor contract
|
|
217
178
|
state;
|
|
218
179
|
/**
|
|
219
180
|
* Tells you if the current state of the actor accepts the given event.
|
|
@@ -228,84 +189,25 @@ export class PlayerActor extends AbstractActor {
|
|
|
228
189
|
*/
|
|
229
190
|
can(event) {
|
|
230
191
|
// A read of the signal keeps can() reactive: a Signal.Computed over the signal
|
|
231
|
-
// computes its value again on each transition.
|
|
232
|
-
// construction window, where the code can read no snapshot, and an actor with a
|
|
233
|
-
// failed initialization, where XState parks an error snapshot. That snapshot is
|
|
234
|
-
// a truthy object, and it has no `can` method.
|
|
192
|
+
// computes its value again on each transition.
|
|
235
193
|
const snapshot = this.state?.get();
|
|
236
|
-
|
|
194
|
+
// The STATUS decides first, and the presence of the method decides second.
|
|
195
|
+
//
|
|
196
|
+
// An actor answers an event only while it is active. XState 5.32 made that test
|
|
197
|
+
// unnecessary by accident — the error snapshot of a failed initialization carried no
|
|
198
|
+
// `can` method, so a test of the method alone answered `false` for it — and 5.33
|
|
199
|
+
// gives that snapshot a working `can`, which then answered `true` for an actor that
|
|
200
|
+
// processes an event never. The status is what the question is really about, and a
|
|
201
|
+
// `done` actor answers `false` for the same reason.
|
|
202
|
+
//
|
|
203
|
+
// A STOPPED actor is the exception, and it is deliberate: the subscription below
|
|
204
|
+
// updates this signal on a stable state alone, so the signal keeps the last ACTIVE
|
|
205
|
+
// snapshot after a teardown rather than freezing on an artifact of it. `can()`
|
|
206
|
+
// therefore answers for the last live state of a stopped actor.
|
|
207
|
+
if (snapshot?.status !== "active")
|
|
208
|
+
return false;
|
|
209
|
+
return typeof snapshot.can === "function" ? snapshot.can(event) : false;
|
|
237
210
|
}
|
|
238
|
-
/**
|
|
239
|
-
* A TC39 `Signal.Computed`. It derives the current URL path from the `meta.route`
|
|
240
|
-
* template of the active machine state and from the context of the actor.
|
|
241
|
-
*
|
|
242
|
-
* It returns `null` when the current state has no `meta.route` field, and also when
|
|
243
|
-
* it cannot resolve the complete route template. A necessary `:param` that the
|
|
244
|
-
* context does not hold is caught inside the signal, and a
|
|
245
|
-
* `MissingRouteParamError` therefore never leaves `get()`: that condition is
|
|
246
|
-
* temporary during a transition, and the signal computes the value again on the next
|
|
247
|
-
* snapshot.
|
|
248
|
-
*
|
|
249
|
-
* @example
|
|
250
|
-
* ```typescript
|
|
251
|
-
* // It returns "/profile/alice" when context.params.userId === "alice",
|
|
252
|
-
* // and null while the param is still absent.
|
|
253
|
-
* const route = actor.currentRoute.get();
|
|
254
|
-
* ```
|
|
255
|
-
*/
|
|
256
|
-
currentRoute;
|
|
257
|
-
/**
|
|
258
|
-
* The route of the initial state of the machine. The constructor fixes it, and it
|
|
259
|
-
* never changes, also when the code restores the actor from a snapshot.
|
|
260
|
-
*
|
|
261
|
-
* A router bridge compares it with the browser URL, and it therefore separates a
|
|
262
|
-
* deep link (a URL that is not the initial one → the router wins) from a restore
|
|
263
|
-
* (the initial URL, and the actor at a different route from the restore → the actor
|
|
264
|
-
* wins).
|
|
265
|
-
*
|
|
266
|
-
* `deriveInitialRoute` derives the value statically from the machine definition,
|
|
267
|
-
* with the pure `initialTransition` helper of XState: the chain of the initial states
|
|
268
|
-
* and their `meta.route` templates are fixed at the moment of the machine
|
|
269
|
-
* definition, and the substitution of a `:param` uses the real initial context of
|
|
270
|
-
* the machine for the `input` of this actor. The code makes no second actor, and a
|
|
271
|
-
* snapshot of a restore changes the value never: it is always the **default**
|
|
272
|
-
* initial route of the machine.
|
|
273
|
-
*/
|
|
274
|
-
initialRoute;
|
|
275
|
-
/**
|
|
276
|
-
* The reactive signal of the current view spec. The signal derives the spec from
|
|
277
|
-
* the `meta.view` metadata of the active state.
|
|
278
|
-
*
|
|
279
|
-
* It emits a **new object reference** on each real change of the view on the
|
|
280
|
-
* screen: the view of a different state, or a change of a param or of the context
|
|
281
|
-
* that changes the resolved spec. A re-entry with `reenter: true` and new params
|
|
282
|
-
* also changes the spec. A snapshot that changes no view on the screen, such as an
|
|
283
|
-
* assign of the context alone, keeps the previous reference. A provider below the
|
|
284
|
-
* signal therefore mounts the UI again not on every event.
|
|
285
|
-
*
|
|
286
|
-
* The `PlaySpec` of the emission carries the context of the machine in its composed
|
|
287
|
-
* `state` field, under the read-only `/context` subtree. A spec therefore reads the
|
|
288
|
-
* context, and also each URL param, through the ordinary state grammar
|
|
289
|
-
* (`{ $state: "/context/params/section" }`). The context-projection module of
|
|
290
|
-
* `@xmachines/play-actor` holds the complete contract.
|
|
291
|
-
*
|
|
292
|
-
* The signal returns `null` when the current state has no `meta.view` metadata.
|
|
293
|
-
*
|
|
294
|
-
* Two states can declare two separate `meta.view` literals with an identical
|
|
295
|
-
* structure. A transition between those two states then emits two different
|
|
296
|
-
* references, and a provider mounts the UI again. Move the shared literal into one
|
|
297
|
-
* `typedSpec` constant, and the identity then removes the duplicate.
|
|
298
|
-
*
|
|
299
|
-
* @example
|
|
300
|
-
* ```typescript
|
|
301
|
-
* const view = actor.currentView.get();
|
|
302
|
-
* if (view) {
|
|
303
|
-
* console.log(view.root); // for example "root"
|
|
304
|
-
* console.log(view.elements); // the Spec elements of @xmachines/json-render-core
|
|
305
|
-
* }
|
|
306
|
-
* ```
|
|
307
|
-
*/
|
|
308
|
-
currentView = new Signal.State(null);
|
|
309
211
|
constructor(machine, options, input, restoredSnapshot) {
|
|
310
212
|
// A defensive check before super(): a machine that is not an object fails deep
|
|
311
213
|
// inside the constructor of XState, with an opaque TypeError, and not with a coded
|
|
@@ -329,30 +231,15 @@ export class PlayerActor extends AbstractActor {
|
|
|
329
231
|
snapshot: restoredSnapshot,
|
|
330
232
|
inspect: options?.inspect,
|
|
331
233
|
});
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
// pre-start snapshot of this actor IS that default initial state, and the code
|
|
336
|
-
// derives the route from it directly. A restore alone needs the pure
|
|
337
|
-
// `initialTransition` helper of XState. The inert actor scope of that helper runs
|
|
338
|
-
// the initial transition of the machine two more times, and one of them has an
|
|
339
|
-
// undefined `input`. This is a quirk of XState, and it costs too much for each
|
|
340
|
-
// other case.
|
|
341
|
-
this.initialRoute =
|
|
342
|
-
restoredSnapshot === undefined
|
|
343
|
-
? deriveCurrentRoute(this.getSnapshot())
|
|
344
|
-
: deriveInitialRoute(machine, input);
|
|
234
|
+
this.playerMachine = machine;
|
|
235
|
+
this.playerInput = input;
|
|
236
|
+
this.playerRestoredSnapshot = restoredSnapshot;
|
|
345
237
|
this.playerOptions = options || {};
|
|
346
238
|
// Initialize the state signal. Each update is synchronous, with no batching in a
|
|
347
239
|
// microtask: XState groups the transitions of one send() call into one
|
|
348
240
|
// subscription callback already, and a synchronous update shows each guard
|
|
349
241
|
// redirect to a router bridge at once.
|
|
350
242
|
this.state = new Signal.State(this.getSnapshot());
|
|
351
|
-
// Initialize the currentRoute computed signal
|
|
352
|
-
this.currentRoute = new Signal.Computed(() => {
|
|
353
|
-
const snapshot = this.state.get();
|
|
354
|
-
return deriveCurrentRoute(snapshot);
|
|
355
|
-
});
|
|
356
243
|
// Observe the transitions of this actor. The code uses `super`, and not `this`, so
|
|
357
244
|
// that the bookkeeping of the next-only subscriptions in the subscribe override
|
|
358
245
|
// stays about the subscriptions of the user code.
|
|
@@ -364,14 +251,16 @@ export class PlayerActor extends AbstractActor {
|
|
|
364
251
|
if (isObservableSnapshot(snapshot)) {
|
|
365
252
|
// Each state update is synchronous. Therefore a router bridge sees a guard redirect at once.
|
|
366
253
|
this.state.set(snapshot);
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
//
|
|
254
|
+
// Every capability derives here, and the ORDER is the composition order:
|
|
255
|
+
// `compose(PlayerActor, withRouting, withView)` makes `withView` the outermost
|
|
256
|
+
// class, so its override runs `super.onSnapshot()` first and the routing
|
|
257
|
+
// capability therefore holds its new value before the view derives from it.
|
|
258
|
+
// The whole order of one transition:
|
|
259
|
+
// 1. state receives its new value, and each Computed over it follows
|
|
260
|
+
// 2. onSnapshot runs each capability, in the composition order
|
|
372
261
|
// 3. the onStateChange hook runs
|
|
373
262
|
// 4. send() then calls onTransition
|
|
374
|
-
this.
|
|
263
|
+
this.onSnapshot(snapshot);
|
|
375
264
|
// Call the onStateChange hook
|
|
376
265
|
const onStateChange = this.hooks.onStateChange;
|
|
377
266
|
if (onStateChange) {
|
|
@@ -496,7 +385,7 @@ export class PlayerActor extends AbstractActor {
|
|
|
496
385
|
// must still run for it, with the correct snapshot from before the send.
|
|
497
386
|
const prevSnapshot = this.getSnapshot();
|
|
498
387
|
// Send the event to the XState actor.
|
|
499
|
-
//
|
|
388
|
+
// The class declares send() to narrow the
|
|
500
389
|
// event type, and TypeScript forbids a super call to an abstract member.
|
|
501
390
|
// Therefore the code reaches the implementation of XState directly. `this` IS the
|
|
502
391
|
// actor. This call is therefore exactly the call of `super.send(event)`: the relay
|
|
@@ -510,12 +399,6 @@ export class PlayerActor extends AbstractActor {
|
|
|
510
399
|
onTransition(this, prevSnapshot, nextSnapshot);
|
|
511
400
|
}
|
|
512
401
|
}
|
|
513
|
-
/**
|
|
514
|
-
* Returns the current snapshot
|
|
515
|
-
*/
|
|
516
|
-
getSnapshot() {
|
|
517
|
-
return super.getSnapshot();
|
|
518
|
-
}
|
|
519
402
|
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
520
403
|
// The subscribe() method of XState accepts a function and also an observer, and it
|
|
521
404
|
// normalizes them internally. The cast joins the two overload signatures only.
|
|
@@ -542,16 +425,6 @@ export class PlayerActor extends AbstractActor {
|
|
|
542
425
|
},
|
|
543
426
|
};
|
|
544
427
|
}
|
|
545
|
-
/**
|
|
546
|
-
* Listens for the events that this actor emits with the `emit` action.
|
|
547
|
-
*
|
|
548
|
-
* @param type - The type of the emitted event to listen for, or `"*"` for every event.
|
|
549
|
-
* @param handler - The actor calls it with each emitted event that matches.
|
|
550
|
-
* @returns The subscription, with an `unsubscribe()` method.
|
|
551
|
-
*/
|
|
552
|
-
on(type, handler) {
|
|
553
|
-
return super.on(type, handler);
|
|
554
|
-
}
|
|
555
428
|
/**
|
|
556
429
|
* Returns the persisted snapshot of this actor.
|
|
557
430
|
*
|
|
@@ -563,55 +436,26 @@ export class PlayerActor extends AbstractActor {
|
|
|
563
436
|
return forward.call(this, options);
|
|
564
437
|
}
|
|
565
438
|
/**
|
|
566
|
-
*
|
|
567
|
-
* each transition. The signal holds the view, and the code computes it not on each
|
|
568
|
-
* read.
|
|
439
|
+
* The point where a capability derives its own signals from a new snapshot.
|
|
569
440
|
*
|
|
570
|
-
*
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if (snapshot === this.lastViewSnapshot) {
|
|
574
|
-
return;
|
|
575
|
-
}
|
|
576
|
-
this.lastViewSnapshot = snapshot;
|
|
577
|
-
try {
|
|
578
|
-
const view = deriveCurrentView(snapshot);
|
|
579
|
-
// Emit only after a real change of the view on the screen: deriveCurrentView
|
|
580
|
-
// returns a fresh object on each call, and the identity of the reference therefore
|
|
581
|
-
// tells nothing. A new reference for a snapshot that changes the view not, for
|
|
582
|
-
// example a context-only assign, makes a provider below mount the UI again, and
|
|
583
|
-
// that removes the state of the view. A deep equality test is deliberately NOT
|
|
584
|
-
// here: it sees nothing inside a Map or a Set, and it therefore stops a real
|
|
585
|
-
// change, and it recurses without an end on a cyclic prop. The last spec of an
|
|
586
|
-
// emission IS the current value of the signal. Read it without a track, so that
|
|
587
|
-
// the gate registers currentView never as a dependency of a computation around
|
|
588
|
-
// it.
|
|
589
|
-
const lastEmittedView = Signal.subtle.untrack(() => this.currentView.get());
|
|
590
|
-
// Use the reference of the previous composed state again when the value of the
|
|
591
|
-
// /context projection did not change. A context-only assign that changes no
|
|
592
|
-
// projected value therefore changes the identity of the state not.
|
|
593
|
-
const nextView = reuseComposedState(lastEmittedView, view);
|
|
594
|
-
if (viewSpecsEquivalent(lastEmittedView, nextView)) {
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
this.currentView.set(nextView);
|
|
598
|
-
}
|
|
599
|
-
catch (error) {
|
|
600
|
-
const onError = this.hooks.onError;
|
|
601
|
-
if (onError) {
|
|
602
|
-
onError(this, toError(error));
|
|
603
|
-
}
|
|
604
|
-
// On an error: keep the last valid view, and clear it not
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
/**
|
|
608
|
-
* The dispose method, for the cleanup. It is the alias of {@link stop}.
|
|
441
|
+
* The base derives nothing: `PlayActor` asks for `state` and `send`, and this class
|
|
442
|
+
* gives exactly those. A capability is a mixin that overrides this method, calls
|
|
443
|
+
* `super.onSnapshot(snapshot)` FIRST, and then writes its own signal.
|
|
609
444
|
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
445
|
+
* That one rule fixes the order, and the order is load-bearing. The view of a state
|
|
446
|
+
* reads the route and the state that the same transition produced, and a router bridge
|
|
447
|
+
* must see a guard redirect synchronously. `compose(PlayerActor, withRouting, withView)`
|
|
448
|
+
* therefore derives the route before the view, because `withView` wraps the class that
|
|
449
|
+
* `withRouting` returned.
|
|
450
|
+
*
|
|
451
|
+
* The method runs after `state` holds the new snapshot and before the `onStateChange`
|
|
452
|
+
* hook of the options.
|
|
453
|
+
*
|
|
454
|
+
* @param snapshot - The stable snapshot of this transition.
|
|
612
455
|
*/
|
|
613
|
-
|
|
614
|
-
this.
|
|
456
|
+
onSnapshot(snapshot) {
|
|
457
|
+
// The base class holds no capability. A mixin overrides this method.
|
|
458
|
+
void snapshot;
|
|
615
459
|
}
|
|
616
460
|
/**
|
|
617
461
|
* Stops the actor when the scope of a `using` declaration ends.
|
package/dist/player-actor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"player-actor.js","sourceRoot":"","sources":["../src/player-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,
|
|
1
|
+
{"version":3,"file":"player-actor.js","sourceRoot":"","sources":["../src/player-actor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,40 +1,5 @@
|
|
|
1
1
|
import type { AnyMachineSnapshot } from "xstate";
|
|
2
|
-
|
|
3
|
-
* Collects the `meta` object of the active state nodes of a SINGLE branch, from the
|
|
4
|
-
* root to a leaf. The key of each entry is the state id, and the order is the
|
|
5
|
-
* ancestors first. {@link deriveRoute} folds this shape.
|
|
6
|
-
*
|
|
7
|
-
* `snapshot.getMeta()` returns a FLAT record of the meta object of every active
|
|
8
|
-
* state. For a machine that is not parallel, that record is one chain of ancestors
|
|
9
|
-
* already. For a PARALLEL machine, it mixes the entries of every active region. A
|
|
10
|
-
* blind fold therefore joins a relative route of one region to an absolute route of
|
|
11
|
-
* a sibling region, and the URL belongs to the tree of neither region. The flat
|
|
12
|
-
* record also cannot go back into a hierarchy: when a state declares an explicit
|
|
13
|
-
* `id`, for example a child with `id: "dashboard-overview"` under `id: "dashboard"`,
|
|
14
|
-
* the meta keys are those ids, and they carry no information about the ancestry.
|
|
15
|
-
*
|
|
16
|
-
* Therefore this function walks `snapshot.value`, which holds the real hierarchy of
|
|
17
|
-
* the active states by the state key, against the node tree of the machine. It
|
|
18
|
-
* follows the FIRST active child at each level. This gives one deterministic branch,
|
|
19
|
-
* which matches the historical behavior of "the first that it finds" for a parallel
|
|
20
|
-
* machine. It also works with an explicit id, because each node carries its own `id`
|
|
21
|
-
* and its own `meta`.
|
|
22
|
-
*
|
|
23
|
-
* The function returns `null` when the snapshot exposes no machine and no value to
|
|
24
|
-
* walk. This is a defensive measure, because a real XState snapshot always exposes
|
|
25
|
-
* them. The caller then uses `getMeta()`, as before.
|
|
26
|
-
*/
|
|
27
|
-
export declare const firstActiveBranchMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
|
|
28
|
-
/**
|
|
29
|
-
* Resolves the meta record that the route derivation and the view derivation fold:
|
|
30
|
-
* the single active branch that {@link firstActiveBranchMeta} walks, which is
|
|
31
|
-
* correct for a parallel machine and for an explicit id, or the flat `getMeta()`
|
|
32
|
-
* record when the snapshot has no machine tree to walk. `deriveCurrentRoute` and
|
|
33
|
-
* `deriveCurrentView` share this function. Therefore the two sides cannot move apart
|
|
34
|
-
* on the selection of the branch, and they cannot move apart on their tolerance of a
|
|
35
|
-
* degenerate snapshot.
|
|
36
|
-
*/
|
|
37
|
-
export declare const activeStateMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
|
|
2
|
+
export { activeStateMeta, firstActiveBranchMeta } from "../state-meta.js";
|
|
38
3
|
/**
|
|
39
4
|
* Derives the current URL of the actor from the state metadata and the context.
|
|
40
5
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-current-route.d.ts","sourceRoot":"","sources":["../../src/routing/derive-current-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"derive-current-route.d.ts","sourceRoot":"","sources":["../../src/routing/derive-current-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAQjD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAU,kBAAkB,KAAG,MAAM,GAAG,IA8B1E,CAAC"}
|
|
@@ -1,82 +1,8 @@
|
|
|
1
1
|
import { MissingRouteParamError } from "../errors.js";
|
|
2
2
|
import { deriveRoute } from "./derive-route.js";
|
|
3
3
|
import { buildRouteUrl } from "./build-url.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* root to a leaf. The key of each entry is the state id, and the order is the
|
|
7
|
-
* ancestors first. {@link deriveRoute} folds this shape.
|
|
8
|
-
*
|
|
9
|
-
* `snapshot.getMeta()` returns a FLAT record of the meta object of every active
|
|
10
|
-
* state. For a machine that is not parallel, that record is one chain of ancestors
|
|
11
|
-
* already. For a PARALLEL machine, it mixes the entries of every active region. A
|
|
12
|
-
* blind fold therefore joins a relative route of one region to an absolute route of
|
|
13
|
-
* a sibling region, and the URL belongs to the tree of neither region. The flat
|
|
14
|
-
* record also cannot go back into a hierarchy: when a state declares an explicit
|
|
15
|
-
* `id`, for example a child with `id: "dashboard-overview"` under `id: "dashboard"`,
|
|
16
|
-
* the meta keys are those ids, and they carry no information about the ancestry.
|
|
17
|
-
*
|
|
18
|
-
* Therefore this function walks `snapshot.value`, which holds the real hierarchy of
|
|
19
|
-
* the active states by the state key, against the node tree of the machine. It
|
|
20
|
-
* follows the FIRST active child at each level. This gives one deterministic branch,
|
|
21
|
-
* which matches the historical behavior of "the first that it finds" for a parallel
|
|
22
|
-
* machine. It also works with an explicit id, because each node carries its own `id`
|
|
23
|
-
* and its own `meta`.
|
|
24
|
-
*
|
|
25
|
-
* The function returns `null` when the snapshot exposes no machine and no value to
|
|
26
|
-
* walk. This is a defensive measure, because a real XState snapshot always exposes
|
|
27
|
-
* them. The caller then uses `getMeta()`, as before.
|
|
28
|
-
*/
|
|
29
|
-
export const firstActiveBranchMeta = (snapshot) => {
|
|
30
|
-
const root = snapshot.machine?.root;
|
|
31
|
-
if (!root)
|
|
32
|
-
return null;
|
|
33
|
-
const ordered = {};
|
|
34
|
-
let node = root;
|
|
35
|
-
let value = snapshot.value;
|
|
36
|
-
while (node) {
|
|
37
|
-
if (node.meta && typeof node.meta === "object") {
|
|
38
|
-
ordered[node.id] = node.meta; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
39
|
-
}
|
|
40
|
-
// Find the key of the active child at this level. A string value is the name of an
|
|
41
|
-
// atomic active leaf. An object value is a compound node, with one key, or a
|
|
42
|
-
// parallel node, with many keys: take the first key, for one deterministic
|
|
43
|
-
// branch.
|
|
44
|
-
let key;
|
|
45
|
-
if (typeof value === "string") {
|
|
46
|
-
key = value;
|
|
47
|
-
}
|
|
48
|
-
else if (value && typeof value === "object") {
|
|
49
|
-
key = Object.keys(value)[0];
|
|
50
|
-
}
|
|
51
|
-
if (key === undefined)
|
|
52
|
-
break;
|
|
53
|
-
const child = node.states?.[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
54
|
-
if (!child)
|
|
55
|
-
break;
|
|
56
|
-
value =
|
|
57
|
-
typeof value === "object" && value !== null
|
|
58
|
-
? value[key] // nosemgrep: gitlab.eslint.detect-object-injection
|
|
59
|
-
: {};
|
|
60
|
-
node = child;
|
|
61
|
-
}
|
|
62
|
-
return ordered;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Resolves the meta record that the route derivation and the view derivation fold:
|
|
66
|
-
* the single active branch that {@link firstActiveBranchMeta} walks, which is
|
|
67
|
-
* correct for a parallel machine and for an explicit id, or the flat `getMeta()`
|
|
68
|
-
* record when the snapshot has no machine tree to walk. `deriveCurrentRoute` and
|
|
69
|
-
* `deriveCurrentView` share this function. Therefore the two sides cannot move apart
|
|
70
|
-
* on the selection of the branch, and they cannot move apart on their tolerance of a
|
|
71
|
-
* degenerate snapshot.
|
|
72
|
-
*/
|
|
73
|
-
export const activeStateMeta = (snapshot) => {
|
|
74
|
-
if (!snapshot || typeof snapshot.getMeta !== "function") {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
const meta = firstActiveBranchMeta(snapshot) ?? snapshot.getMeta();
|
|
78
|
-
return meta && typeof meta === "object" ? meta : null;
|
|
79
|
-
};
|
|
4
|
+
import { activeStateMeta } from "../state-meta.js";
|
|
5
|
+
export { activeStateMeta, firstActiveBranchMeta } from "../state-meta.js";
|
|
80
6
|
/**
|
|
81
7
|
* Derives the current URL of the actor from the state metadata and the context.
|
|
82
8
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-current-route.js","sourceRoot":"","sources":["../../src/routing/derive-current-route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"derive-current-route.js","sourceRoot":"","sources":["../../src/routing/derive-current-route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,QAA4B,EAAiB,EAAE;IACjF,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,EAAE,CAAC;QACX,OAAO,IAAI,CAAC;IACb,CAAC;IAED,MAAM,aAAa,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC,aAAa,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,aAAa,CAAC,aAAa,EAAE,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAiB,CAAC,CAAC;IAC/E,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,gFAAgF;QAChF,oFAAoF;QACpF,gFAAgF;QAChF,iFAAiF;QACjF,yBAAyB;QACzB,0FAA0F;QAC1F,uFAAuF;QACvF,iFAAiF;QACjF,0EAA0E;QAC1E,oCAAoC;QACpC,IAAI,KAAK,YAAY,sBAAsB,EAAE,CAAC;YAC7C,OAAO,IAAI,CAAC;QACb,CAAC;QACD,6DAA6D;QAC7D,MAAM,KAAK,CAAC;IACb,CAAC;AACF,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-initial-route.d.ts","sourceRoot":"","sources":["../../src/routing/derive-initial-route.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAI1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,eAAe,EAAE,QAAQ,OAAO,KAAG,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"derive-initial-route.d.ts","sourceRoot":"","sources":["../../src/routing/derive-initial-route.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,KAAK,eAAe,EAAE,MAAM,QAAQ,CAAC;AAI1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,kBAAkB,GAAI,SAAS,eAAe,EAAE,QAAQ,OAAO,KAAG,MAAM,GAAG,IAwBvF,CAAC"}
|
|
@@ -52,6 +52,17 @@ export const deriveInitialRoute = (machine, input) => {
|
|
|
52
52
|
// that snapshot also has no route metadata. Report "no initial route to derive".
|
|
53
53
|
return null;
|
|
54
54
|
}
|
|
55
|
+
// The SAME failure, reported the other way. XState 5.32 threw out of
|
|
56
|
+
// `initialTransition` for a context factory that throws, and 5.33 returns an
|
|
57
|
+
// error-status snapshot instead, with the reason on `snapshot.error`. The catch above
|
|
58
|
+
// therefore stopped firing, and a machine whose context never built derived the route
|
|
59
|
+
// of its initial state — `/login` for a factory that threw — which a bridge then took
|
|
60
|
+
// as the place of the actor.
|
|
61
|
+
//
|
|
62
|
+
// Both shapes mean the same thing, so both answer the same way. The status is the
|
|
63
|
+
// question, and it holds whichever way a later release reports the failure.
|
|
64
|
+
if (initialSnapshot.status === "error")
|
|
65
|
+
return null;
|
|
55
66
|
return deriveCurrentRoute(initialSnapshot);
|
|
56
67
|
};
|
|
57
68
|
//# sourceMappingURL=derive-initial-route.js.map
|