@xmachines/play-xstate 2.0.0-alpha.1 → 2.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 +90 -91
- package/dist/define-player.d.ts +3 -3
- package/dist/define-player.js +3 -3
- package/dist/errors.d.ts +46 -70
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +69 -77
- package/dist/errors.js.map +1 -1
- package/dist/guards/compose.d.ts +49 -59
- package/dist/guards/compose.d.ts.map +1 -1
- package/dist/guards/compose.js +68 -95
- package/dist/guards/compose.js.map +1 -1
- package/dist/guards/helpers.d.ts +6 -2
- package/dist/guards/helpers.d.ts.map +1 -1
- package/dist/guards/helpers.js +6 -2
- package/dist/guards/helpers.js.map +1 -1
- package/dist/guards/index.d.ts +7 -0
- package/dist/guards/index.d.ts.map +1 -1
- package/dist/guards/index.js +7 -0
- package/dist/guards/index.js.map +1 -1
- package/dist/guards/types.d.ts +4 -5
- package/dist/guards/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/player-actor.d.ts +112 -44
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +311 -327
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/build-url.d.ts +2 -7
- package/dist/routing/build-url.d.ts.map +1 -1
- package/dist/routing/build-url.js +21 -25
- package/dist/routing/build-url.js.map +1 -1
- package/dist/routing/derive-current-route.d.ts +32 -0
- package/dist/routing/derive-current-route.d.ts.map +1 -1
- package/dist/routing/derive-current-route.js +20 -19
- package/dist/routing/derive-current-route.js.map +1 -1
- package/dist/routing/derive-initial-route.d.ts +1 -4
- package/dist/routing/derive-initial-route.d.ts.map +1 -1
- package/dist/routing/derive-initial-route.js +1 -4
- package/dist/routing/derive-initial-route.js.map +1 -1
- package/dist/routing/format-play-route-transitions.d.ts +11 -54
- package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
- package/dist/routing/format-play-route-transitions.js +65 -125
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/routing/index.d.ts +1 -5
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +1 -3
- package/dist/routing/index.js.map +1 -1
- package/dist/types.d.ts +87 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/view/derive-current-view.d.ts +49 -0
- package/dist/view/derive-current-view.d.ts.map +1 -0
- package/dist/view/derive-current-view.js +115 -0
- package/dist/view/derive-current-view.js.map +1 -0
- package/package.json +22 -22
- package/dist/define-player.typecheck.d.ts +0 -2
- package/dist/define-player.typecheck.d.ts.map +0 -1
- package/dist/define-player.typecheck.js +0 -48
- package/dist/define-player.typecheck.js.map +0 -1
- package/dist/guards/compose.typecheck.d.ts +0 -2
- package/dist/guards/compose.typecheck.d.ts.map +0 -1
- package/dist/guards/compose.typecheck.js +0 -22
- package/dist/guards/compose.typecheck.js.map +0 -1
- package/dist/player-actor.typecheck.d.ts +0 -2
- package/dist/player-actor.typecheck.d.ts.map +0 -1
- package/dist/player-actor.typecheck.js +0 -30
- package/dist/player-actor.typecheck.js.map +0 -1
- package/dist/routing/create-routed-machine.d.ts +0 -71
- package/dist/routing/create-routed-machine.d.ts.map +0 -1
- package/dist/routing/create-routed-machine.js +0 -71
- package/dist/routing/create-routed-machine.js.map +0 -1
- package/dist/routing/play-route-event.typecheck.d.ts +0 -2
- package/dist/routing/play-route-event.typecheck.d.ts.map +0 -1
- package/dist/routing/play-route-event.typecheck.js +0 -43
- package/dist/routing/play-route-event.typecheck.js.map +0 -1
- package/dist/routing/schemas.d.ts +0 -99
- package/dist/routing/schemas.d.ts.map +0 -1
- package/dist/routing/schemas.js +0 -30
- package/dist/routing/schemas.js.map +0 -1
- package/dist/schemas.d.ts +0 -28
- package/dist/schemas.d.ts.map +0 -1
- package/dist/schemas.js +0 -29
- package/dist/schemas.js.map +0 -1
|
@@ -1,18 +1,26 @@
|
|
|
1
|
+
import { assign } from "xstate";
|
|
2
|
+
import { shallowEqualExcept } from "@xmachines/play-actor";
|
|
1
3
|
import { MissingStateIdError } from "../errors.js";
|
|
2
4
|
import { normalizeRoute } from "./derive-route.js";
|
|
3
5
|
/**
|
|
4
|
-
*
|
|
6
|
+
* Reuse the previous params/query container when the incoming one is
|
|
7
|
+
* shallow-equal.
|
|
5
8
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
9
|
+
* Route params/query arrive as a FRESH object on every `play.route` event —
|
|
10
|
+
* bridges rebuild them per URL parse, and `|| {}` allocates even for the
|
|
11
|
+
* empty case — while the view emit gate compares context per field with
|
|
12
|
+
* `Object.is`. Without reuse, a value-identical re-navigation (popstate to
|
|
13
|
+
* the current URL, a redundant programmatic send) would re-emit the view
|
|
14
|
+
* for nothing.
|
|
15
|
+
*/
|
|
16
|
+
const keepEqualContainer = (prev, next) => (prev !== undefined && shallowEqualExcept(prev, next) ? prev : next);
|
|
17
|
+
/**
|
|
18
|
+
* Formats play.route transitions from declarative route configs
|
|
8
19
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - one root-level `play.route` forwarder performs the navigation for those
|
|
14
|
-
* targets as ONE atomic transition: target + re-entry + a shallow
|
|
15
|
-
* `params`/`query` context patch.
|
|
20
|
+
* Crawls machine states looking for states with meta.route and generates
|
|
21
|
+
* transitions that handle `play.route` events by matching event.to to state IDs.
|
|
22
|
+
*
|
|
23
|
+
* Inspired by XState's internal formatRouteTransitions (stateUtils.ts line 391).
|
|
16
24
|
*
|
|
17
25
|
* @example
|
|
18
26
|
* ```typescript
|
|
@@ -27,58 +35,21 @@ import { normalizeRoute } from "./derive-route.js";
|
|
|
27
35
|
* const machine = createMachine(formatPlayRouteTransitions(machineConfig));
|
|
28
36
|
* ```
|
|
29
37
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* dynamic targets, opaque to static analysis.)
|
|
35
|
-
*
|
|
36
|
-
* The `play.route` public API and its v5 semantics are preserved:
|
|
37
|
-
* - `send({ type: "play.route", to: "#home", params, query })` navigates and
|
|
38
|
-
* patches `context.params`/`context.query` in the SAME transition — exit
|
|
39
|
-
* actions of the departing state observe the OLD params, entry actions of
|
|
40
|
-
* the target observe the NEW ones, `always` transitions never see a
|
|
41
|
-
* half-navigated intermediate state, and entry/exit actions receive the
|
|
42
|
-
* original `play.route` event;
|
|
43
|
-
* - user-defined `play.route` transitions (e.g. a hand-written 404 fallback)
|
|
44
|
-
* are preserved AFTER the forwarder: for unknown targets the forwarder
|
|
45
|
-
* returns `undefined`, so evaluation falls through to them;
|
|
46
|
-
* - `params`/`query` are only patched when the forwarder navigates — unknown
|
|
47
|
-
* and blocked targets leave context untouched.
|
|
48
|
-
*
|
|
49
|
-
* When a state declares its OWN `route` config (which wins over the injected
|
|
50
|
-
* default), the forwarder re-raises the event as `xstate.route` instead of
|
|
51
|
-
* navigating, so the user's resolver decides — including blocking. The
|
|
52
|
-
* forwarder does NOT patch `params`/`query` for such targets (a blocking
|
|
53
|
-
* resolver would otherwise leave context describing a route that was never
|
|
54
|
-
* entered); the user's function-form resolver owns any context patch, and
|
|
55
|
-
* that navigation microstep runs under the `xstate.route` event.
|
|
56
|
-
*
|
|
57
|
-
* Native `xstate.route` events also work directly (Stately ecosystem tooling),
|
|
58
|
-
* but bypass the forwarder — no `params`/`query` context patch is applied, so
|
|
59
|
-
* stale values from earlier `play.route` events linger in context (and a
|
|
60
|
-
* router bridge deriving the URL from context would interpolate those stale
|
|
61
|
-
* params).
|
|
38
|
+
* This automatically generates play.route handlers at the root level that:
|
|
39
|
+
* - Match event.to against state IDs (e.g., event.to === "#home")
|
|
40
|
+
* - Target the appropriate state
|
|
41
|
+
* - Assign params and query from the event to context
|
|
62
42
|
*
|
|
63
43
|
* @param machineConfig - XState machine config (before createMachine). Must extend `RouteMachineConfig`.
|
|
64
|
-
* @returns The machine config with
|
|
44
|
+
* @returns The same machine config with auto-generated `play.route` handlers merged in, preserving the original type `T`.
|
|
65
45
|
*/
|
|
66
46
|
export function formatPlayRouteTransitions(machineConfig) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const routeTargets = new Map();
|
|
74
|
-
/**
|
|
75
|
-
* Rebuild the states tree, injecting a native `route` config into routed
|
|
76
|
-
* nodes. The input config is never mutated — every node is shallow-copied.
|
|
77
|
-
*/
|
|
78
|
-
const injectRoutes = (states, parentPath = "") => {
|
|
79
|
-
const next = {};
|
|
80
|
-
for (const [key, stateConfig] of Object.entries(states)) {
|
|
81
|
-
const node = { ...stateConfig };
|
|
47
|
+
const routeTransitions = [];
|
|
48
|
+
const collectRoutes = (states, parentPath = "") => {
|
|
49
|
+
Object.entries(states).forEach(([key, stateConfig]) => {
|
|
50
|
+
const node = stateConfig;
|
|
51
|
+
// Build the full key-based path from the root for the transition target
|
|
52
|
+
// (XState targets use the state key hierarchy, not explicit IDs)
|
|
82
53
|
const statePath = parentPath ? `${parentPath}.${key}` : key;
|
|
83
54
|
// Validates the metadata (malformed object routes throw
|
|
84
55
|
// InvalidRouteMetadataError) and normalizes to the path string. Both
|
|
@@ -90,79 +61,48 @@ export function formatPlayRouteTransitions(machineConfig) {
|
|
|
90
61
|
if (routePath && !node.id) {
|
|
91
62
|
throw new MissingStateIdError(key, routePath);
|
|
92
63
|
}
|
|
93
|
-
if (node.states) {
|
|
94
|
-
node.states = injectRoutes(node.states, statePath);
|
|
95
|
-
}
|
|
96
64
|
if (routePath && node.id) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
// xstate.route so the user's resolver decides (and owns any
|
|
108
|
-
// context patch).
|
|
109
|
-
routeTargets.set(`#${node.id}`, null);
|
|
110
|
-
}
|
|
65
|
+
const transition = {
|
|
66
|
+
target: `.${statePath}`,
|
|
67
|
+
guard: ({ event }) => event.to === `#${node.id}`,
|
|
68
|
+
reenter: true,
|
|
69
|
+
actions: assign({
|
|
70
|
+
params: ({ context, event }) => keepEqualContainer(context.params, event.params || {}),
|
|
71
|
+
query: ({ context, event }) => keepEqualContainer(context.query, event.query || {}),
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
routeTransitions.push(transition);
|
|
111
75
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
76
|
+
if (node.states) {
|
|
77
|
+
collectRoutes(node.states, statePath);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
115
80
|
};
|
|
116
81
|
const machineStates = machineConfig.states;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return machineConfig;
|
|
82
|
+
if (machineStates) {
|
|
83
|
+
collectRoutes(machineStates);
|
|
120
84
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
85
|
+
if (routeTransitions.length > 0) {
|
|
86
|
+
const existingOn = machineConfig.on || {};
|
|
87
|
+
// Preserve user-defined play.route transitions (e.g. a hand-written 404
|
|
88
|
+
// fallback) by appending them AFTER the generated ones: XState evaluates
|
|
89
|
+
// candidate transitions in order, so generated guards win when they match
|
|
90
|
+
// and the user's transitions act as fallbacks otherwise.
|
|
91
|
+
const userRouteTransitions = existingOn["play.route"];
|
|
92
|
+
const normalizedUserTransitions = userRouteTransitions === undefined
|
|
93
|
+
? []
|
|
94
|
+
: Array.isArray(userRouteTransitions)
|
|
95
|
+
? userRouteTransitions
|
|
96
|
+
: [userRouteTransitions];
|
|
97
|
+
const updatedOn = {
|
|
98
|
+
...existingOn,
|
|
99
|
+
"play.route": [...routeTransitions, ...normalizedUserTransitions],
|
|
100
|
+
};
|
|
138
101
|
return {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// Shallow context patch — v6's replacement for assign().
|
|
142
|
-
context: {
|
|
143
|
-
params: event.params || {},
|
|
144
|
-
query: event.query || {},
|
|
145
|
-
},
|
|
102
|
+
...machineConfig,
|
|
103
|
+
on: updatedOn,
|
|
146
104
|
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// fallback) by appending them AFTER the forwarder: XState evaluates
|
|
150
|
-
// candidate transitions in order, so the forwarder wins for known targets
|
|
151
|
-
// and the user's transitions act as fallbacks otherwise.
|
|
152
|
-
const existingOn = machineConfig.on || {};
|
|
153
|
-
const userRouteTransitions = existingOn["play.route"];
|
|
154
|
-
const normalizedUserTransitions = userRouteTransitions === undefined
|
|
155
|
-
? []
|
|
156
|
-
: Array.isArray(userRouteTransitions)
|
|
157
|
-
? userRouteTransitions
|
|
158
|
-
: [userRouteTransitions];
|
|
159
|
-
return {
|
|
160
|
-
...machineConfig,
|
|
161
|
-
states: injectedStates,
|
|
162
|
-
on: {
|
|
163
|
-
...existingOn,
|
|
164
|
-
"play.route": [forwarder, ...normalizedUserTransitions],
|
|
165
|
-
},
|
|
166
|
-
};
|
|
105
|
+
}
|
|
106
|
+
return machineConfig;
|
|
167
107
|
}
|
|
168
108
|
//# sourceMappingURL=format-play-route-transitions.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-play-route-transitions.js","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format-play-route-transitions.js","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"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"}
|
package/dist/routing/index.d.ts
CHANGED
|
@@ -7,14 +7,10 @@
|
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
9
|
export { deriveRoute, isAbsoluteRoute } from "./derive-route.js";
|
|
10
|
-
export { deriveCurrentRoute } from "./derive-current-route.js";
|
|
10
|
+
export { activeStateMeta, deriveCurrentRoute, firstActiveBranchMeta, } from "./derive-current-route.js";
|
|
11
11
|
export { deriveInitialRoute } from "./derive-initial-route.js";
|
|
12
12
|
export { buildRouteUrl } from "./build-url.js";
|
|
13
13
|
export { formatPlayRouteTransitions } from "./format-play-route-transitions.js";
|
|
14
|
-
export { playMetaSchema, playRouteEventSchema } from "./schemas.js";
|
|
15
|
-
export type { PlayRoutePayload, WithOptional } from "./schemas.js";
|
|
16
|
-
export type { SetupLike } from "./create-routed-machine.js";
|
|
17
|
-
export { createRoutedMachine } from "./create-routed-machine.js";
|
|
18
14
|
export type { RouteMachineConfig, RouteStateNode } from "./format-play-route-transitions.js";
|
|
19
15
|
export type { RouteContext, RouteObject, RouteMetadata } from "./types.js";
|
|
20
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/routing/index.js
CHANGED
|
@@ -7,10 +7,8 @@
|
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
9
|
export { deriveRoute, isAbsoluteRoute } from "./derive-route.js";
|
|
10
|
-
export { deriveCurrentRoute } from "./derive-current-route.js";
|
|
10
|
+
export { activeStateMeta, deriveCurrentRoute, firstActiveBranchMeta, } from "./derive-current-route.js";
|
|
11
11
|
export { deriveInitialRoute } from "./derive-initial-route.js";
|
|
12
12
|
export { buildRouteUrl } from "./build-url.js";
|
|
13
13
|
export { formatPlayRouteTransitions } from "./format-play-route-transitions.js";
|
|
14
|
-
export { playMetaSchema, playRouteEventSchema } from "./schemas.js";
|
|
15
|
-
export { createRoutedMachine } from "./create-routed-machine.js";
|
|
16
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routing/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACjE,OAAO,EACN,eAAe,EACf,kBAAkB,EAClB,qBAAqB,GACrB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,30 +1,93 @@
|
|
|
1
|
-
import type { AnyStateMachine, InputFrom, SnapshotFrom } from "xstate";
|
|
1
|
+
import type { ActorOptions, AnyStateMachine, InputFrom, SnapshotFrom } from "xstate";
|
|
2
2
|
import type { PlayerActor as PlayerActorClass } from "./player-actor.js";
|
|
3
3
|
/**
|
|
4
4
|
* Configuration for definePlayer()
|
|
5
5
|
*/
|
|
6
6
|
export interface PlayerConfig<TMachine extends AnyStateMachine> {
|
|
7
|
-
/** XState
|
|
7
|
+
/** XState v5 state machine */
|
|
8
8
|
machine: TMachine;
|
|
9
9
|
/** Lifecycle hooks and configuration */
|
|
10
10
|
options?: PlayerOptions<TMachine>;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Player lifecycle hooks
|
|
14
|
-
*
|
|
15
|
-
* Per CONTEXT.md: Rich set of hooks for observability
|
|
13
|
+
* Player lifecycle hooks — the observability surface around the actor.
|
|
16
14
|
*/
|
|
17
15
|
export interface PlayerOptions<TMachine extends AnyStateMachine> {
|
|
18
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Called on each real start: every transition from not-running to running,
|
|
18
|
+
* including a start after a stop. A repeated `start()` while the actor is
|
|
19
|
+
* already running does not re-fire it.
|
|
20
|
+
*/
|
|
19
21
|
onStart?: (actor: PlayerActorClass<TMachine>) => void;
|
|
20
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Called on each real stop: only when a running actor was actually torn
|
|
24
|
+
* down. Repeated `stop()`/`dispose()` calls, and stopping an actor that
|
|
25
|
+
* never started, do not fire it.
|
|
26
|
+
*/
|
|
21
27
|
onStop?: (actor: PlayerActorClass<TMachine>) => void;
|
|
22
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Called after every event `send()` processes — including events the
|
|
30
|
+
* machine ignores, where `prevState` and `nextState` are the same
|
|
31
|
+
* snapshot. Compare the two when only real transitions matter.
|
|
32
|
+
*/
|
|
23
33
|
onTransition?: (actor: PlayerActorClass<TMachine>, prevState: SnapshotFrom<TMachine>, nextState: SnapshotFrom<TMachine>) => void;
|
|
24
34
|
/** Called when state signal changes */
|
|
25
35
|
onStateChange?: (actor: PlayerActorClass<TMachine>, state: SnapshotFrom<TMachine>) => void;
|
|
26
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Called on actor errors: a snapshot restore that fails at `start()`, a
|
|
38
|
+
* throwing action or guard, and view-derivation failures.
|
|
39
|
+
*
|
|
40
|
+
* Read when an error is delivered, not at construction: the options bag is
|
|
41
|
+
* shared by reference, so a handler attached to it later still receives
|
|
42
|
+
* actor errors, and removing the handler restores the loud default below.
|
|
43
|
+
*
|
|
44
|
+
* With a handler in place, the error is routed there and counts as
|
|
45
|
+
* handled. XState decides its global rethrow per observer, beyond this
|
|
46
|
+
* option's reach: a subscription of your own without an `error` listener
|
|
47
|
+
* still forces it, `onError` or not.
|
|
48
|
+
*
|
|
49
|
+
* Without `onError`, actor errors stay loud (an unhandled rethrow via
|
|
50
|
+
* `setTimeout`) so they are never silently swallowed — and your own
|
|
51
|
+
* `error` subscribers do not suppress that default; only `onError` does.
|
|
52
|
+
*
|
|
53
|
+
* An actor failure that is already an `Error` arrives unchanged, keeping the
|
|
54
|
+
* identity the machine gave it. A machine that throws a non-`Error` value
|
|
55
|
+
* arrives as `ActorThrewNonErrorError` with the thrown value on `cause`.
|
|
56
|
+
*/
|
|
27
57
|
onError?: (actor: PlayerActorClass<TMachine>, error: Error) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Inspection observer forwarded verbatim to XState's `createActor`.
|
|
60
|
+
*
|
|
61
|
+
* This is the creation-time attachment route, and the only one that observes
|
|
62
|
+
* the actor's construction events. Attaching later via
|
|
63
|
+
* `actor.system.inspect(fn)` also works, but only sees events from that
|
|
64
|
+
* point on.
|
|
65
|
+
*
|
|
66
|
+
* A `PlayerActor` is itself the XState actor, so its own events carry
|
|
67
|
+
* `actorRef === playerActor` and can be recognised by identity. Each
|
|
68
|
+
* `PlayerActor` is also its own root system, so `event.rootId ===
|
|
69
|
+
* actor.sessionId` demultiplexes the whole tree — including events from
|
|
70
|
+
* invoked and spawned children, whose `actorRef` is the child.
|
|
71
|
+
*
|
|
72
|
+
* One caveat comes with that identity: the `@xstate.actor` event fires from
|
|
73
|
+
* inside the actor's constructor, so its `actorRef` is the instance
|
|
74
|
+
* mid-construction. `state`, `currentRoute`, `currentView` and
|
|
75
|
+
* `initialRoute` do not exist yet — reading them there throws. Capture the
|
|
76
|
+
* reference and read the signals from a later event, or from outside the
|
|
77
|
+
* observer.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```typescript
|
|
81
|
+
* import { createBrowserInspector } from "@statelyai/inspect";
|
|
82
|
+
*
|
|
83
|
+
* const { inspect } = createBrowserInspector();
|
|
84
|
+
* const createPlayer = definePlayer({ machine, options: { inspect } });
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* For an inspector created after the factory (e.g. behind a dev-tools toggle),
|
|
88
|
+
* pass a forwarding function: `inspect: (event) => currentInspector?.(event)`.
|
|
89
|
+
*/
|
|
90
|
+
inspect?: ActorOptions<TMachine>["inspect"];
|
|
28
91
|
}
|
|
29
92
|
/**
|
|
30
93
|
* Optional restore arguments for the player factory.
|
|
@@ -33,13 +96,23 @@ export interface PlayerOptions<TMachine extends AnyStateMachine> {
|
|
|
33
96
|
* `createPlayer(input?)` calling convention for fresh actors.
|
|
34
97
|
*/
|
|
35
98
|
export interface PlayerFactoryResumeOptions<TMachine extends AnyStateMachine> {
|
|
36
|
-
/**
|
|
37
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Persisted XState snapshot used to restore actor state.
|
|
101
|
+
*
|
|
102
|
+
* Typed as XState's own `ActorOptions["snapshot"]` — the exact type
|
|
103
|
+
* `createActor` accepts and `getPersistedSnapshot()` returns — so restoring
|
|
104
|
+
* a stored snapshot never needs a cast.
|
|
105
|
+
*/
|
|
106
|
+
snapshot?: ActorOptions<TMachine>["snapshot"];
|
|
38
107
|
}
|
|
39
108
|
/**
|
|
40
|
-
* Factory function returned by definePlayer()
|
|
109
|
+
* Factory function returned by definePlayer() — each call creates an
|
|
110
|
+
* independent actor instance from the same configuration.
|
|
41
111
|
*
|
|
42
|
-
*
|
|
112
|
+
* Input requiredness mirrors XState's `createActor`: a machine whose input
|
|
113
|
+
* cannot be `undefined` makes the factory's first argument required, so
|
|
114
|
+
* forgetting it is a compile error instead of an actor that starts in an
|
|
115
|
+
* error status with a `null` initial route.
|
|
43
116
|
*/
|
|
44
|
-
export type PlayerFactory<TMachine extends AnyStateMachine> = (input?: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine>;
|
|
117
|
+
export type PlayerFactory<TMachine extends AnyStateMachine> = undefined extends InputFrom<TMachine> ? (input?: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine> : (input: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine>;
|
|
45
118
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,KAAK,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,QAAQ,SAAS,eAAe;IAC7D,8BAA8B;IAC9B,OAAO,EAAE,QAAQ,CAAC;IAElB,wCAAwC;IACxC,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,eAAe;IAC9D;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAEtD;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAErD;;;;OAIG;IACH,YAAY,CAAC,EAAE,CACd,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,KAC7B,IAAI,CAAC;IAEV,uCAAuC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAE3F;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC;CAC5C;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B,CAAC,QAAQ,SAAS,eAAe;IAC3E;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,QAAQ,SAAS,eAAe,IACzD,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC,GAClC,CACA,KAAK,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC3B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,GAC9B,CACA,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC1B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View derivation — the meta.view half of the player pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Kept beside src/routing/ so player-actor.ts holds only the actor itself:
|
|
5
|
+
* signals, hooks, and lifecycle. The active-branch walk is shared with route
|
|
6
|
+
* derivation so a parallel machine's view always belongs to the region its
|
|
7
|
+
* URL points at.
|
|
8
|
+
*/
|
|
9
|
+
import type { AnyMachineSnapshot } from "xstate";
|
|
10
|
+
import { type PlaySpec } from "@xmachines/play-actor";
|
|
11
|
+
/**
|
|
12
|
+
* Derive the actor's current view from state metadata.
|
|
13
|
+
*
|
|
14
|
+
* Always returns a **fresh** `PlaySpec` object so a genuine view change is never
|
|
15
|
+
* suppressed by `Signal.State`'s `Object.is` equality check. Whether that fresh
|
|
16
|
+
* object is actually emitted is decided by `PlayerActor.validateAndCacheView`,
|
|
17
|
+
* which compares against the last emitted spec (reusing the composed `state`
|
|
18
|
+
* reference when the projection is value-unchanged) and skips emission when the
|
|
19
|
+
* rendered view is unchanged — preventing downstream providers from remounting
|
|
20
|
+
* the UI on every event.
|
|
21
|
+
*
|
|
22
|
+
* ### Context projection
|
|
23
|
+
*
|
|
24
|
+
* The machine's context is projected into the derived spec's `state` under the
|
|
25
|
+
* read-only `/context` subtree: `state: { ...meta.view.state, context: slice }`.
|
|
26
|
+
* The emitted spec is therefore **self-consistent** — its `state` honestly
|
|
27
|
+
* describes the store contents — so `repeat.statePath: "/context/tasks"`,
|
|
28
|
+
* `visible: { $state: "/context/…" }`, and `{ $state: "/context/…" }` props all
|
|
29
|
+
* resolve through the ordinary state grammar, and tools like `validateSpec`
|
|
30
|
+
* pass on derived views with no special-casing (validate the derived view, not
|
|
31
|
+
* the raw `meta.view`).
|
|
32
|
+
*
|
|
33
|
+
* The whole context is always projected; the authored `meta.view` object is
|
|
34
|
+
* never mutated.
|
|
35
|
+
*
|
|
36
|
+
* ### viewKey
|
|
37
|
+
*
|
|
38
|
+
* The derived spec carries `viewKey` — the meta record key (state node id) of
|
|
39
|
+
* the entry this derivation actually selected. Providers key their store
|
|
40
|
+
* lifecycle on it: changed → reseed, unchanged → refresh `/context` in place.
|
|
41
|
+
* It is taken from the selected entry rather than "the active state id"
|
|
42
|
+
* because for parallel machines the walked branch and the flat `getMeta()`
|
|
43
|
+
* fallback can select a view from a different region than the branch leaf.
|
|
44
|
+
*
|
|
45
|
+
* @param snapshot - Current XState machine snapshot.
|
|
46
|
+
* @returns Derived `PlaySpec`, or `null` if the current state has no view metadata.
|
|
47
|
+
*/
|
|
48
|
+
export declare const deriveCurrentView: (snapshot: AnyMachineSnapshot) => PlaySpec | null;
|
|
49
|
+
//# sourceMappingURL=derive-current-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive-current-view.d.ts","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAsDrF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,kBAAkB,KAAG,QAAQ,GAAG,IA4C3E,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { composePlayState, toAtomState } from "@xmachines/play-actor";
|
|
2
|
+
import { activeStateMeta } from "../routing/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Once-per-spec migration warning for the removed 1.x `contextProps` field.
|
|
5
|
+
* Hand-written meta.view objects bypass `typedSpec`, so a spec still carrying
|
|
6
|
+
* the field compiles clean — but its meaning inverted (an allowlist, or an
|
|
7
|
+
* empty filter projecting nothing, is now the whole context). Keyed on the
|
|
8
|
+
* static meta.view object so the warning fires once, not per snapshot.
|
|
9
|
+
*/
|
|
10
|
+
const warnedContextProps = new WeakSet();
|
|
11
|
+
const warnRemovedContextProps = (viewMeta) => {
|
|
12
|
+
if (warnedContextProps.has(viewMeta))
|
|
13
|
+
return;
|
|
14
|
+
warnedContextProps.add(viewMeta);
|
|
15
|
+
console.warn("[play-xstate] meta.view.contextProps has been removed: the whole machine context " +
|
|
16
|
+
"is always projected under /context. Delete the field — it no longer filters anything.");
|
|
17
|
+
};
|
|
18
|
+
const resolveViewMeta = (meta) => {
|
|
19
|
+
// Iterate last-to-first: snapshot.getMeta() orders keys ancestors-first, so
|
|
20
|
+
// scanning from the end makes the deepest active state's meta.view win over
|
|
21
|
+
// an ancestor's instead of being shadowed by it.
|
|
22
|
+
const entries = Object.entries(meta);
|
|
23
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
24
|
+
// Loop-bounded array index, not user-controlled property access.
|
|
25
|
+
const [key, stateMeta] = entries[i]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
26
|
+
const maybeView = stateMeta && typeof stateMeta === "object"
|
|
27
|
+
? stateMeta.view
|
|
28
|
+
: undefined;
|
|
29
|
+
if (maybeView &&
|
|
30
|
+
typeof maybeView === "object" &&
|
|
31
|
+
"root" in maybeView &&
|
|
32
|
+
"elements" in maybeView) {
|
|
33
|
+
return { key, view: maybeView };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Derive the actor's current view from state metadata.
|
|
40
|
+
*
|
|
41
|
+
* Always returns a **fresh** `PlaySpec` object so a genuine view change is never
|
|
42
|
+
* suppressed by `Signal.State`'s `Object.is` equality check. Whether that fresh
|
|
43
|
+
* object is actually emitted is decided by `PlayerActor.validateAndCacheView`,
|
|
44
|
+
* which compares against the last emitted spec (reusing the composed `state`
|
|
45
|
+
* reference when the projection is value-unchanged) and skips emission when the
|
|
46
|
+
* rendered view is unchanged — preventing downstream providers from remounting
|
|
47
|
+
* the UI on every event.
|
|
48
|
+
*
|
|
49
|
+
* ### Context projection
|
|
50
|
+
*
|
|
51
|
+
* The machine's context is projected into the derived spec's `state` under the
|
|
52
|
+
* read-only `/context` subtree: `state: { ...meta.view.state, context: slice }`.
|
|
53
|
+
* The emitted spec is therefore **self-consistent** — its `state` honestly
|
|
54
|
+
* describes the store contents — so `repeat.statePath: "/context/tasks"`,
|
|
55
|
+
* `visible: { $state: "/context/…" }`, and `{ $state: "/context/…" }` props all
|
|
56
|
+
* resolve through the ordinary state grammar, and tools like `validateSpec`
|
|
57
|
+
* pass on derived views with no special-casing (validate the derived view, not
|
|
58
|
+
* the raw `meta.view`).
|
|
59
|
+
*
|
|
60
|
+
* The whole context is always projected; the authored `meta.view` object is
|
|
61
|
+
* never mutated.
|
|
62
|
+
*
|
|
63
|
+
* ### viewKey
|
|
64
|
+
*
|
|
65
|
+
* The derived spec carries `viewKey` — the meta record key (state node id) of
|
|
66
|
+
* the entry this derivation actually selected. Providers key their store
|
|
67
|
+
* lifecycle on it: changed → reseed, unchanged → refresh `/context` in place.
|
|
68
|
+
* It is taken from the selected entry rather than "the active state id"
|
|
69
|
+
* because for parallel machines the walked branch and the flat `getMeta()`
|
|
70
|
+
* fallback can select a view from a different region than the branch leaf.
|
|
71
|
+
*
|
|
72
|
+
* @param snapshot - Current XState machine snapshot.
|
|
73
|
+
* @returns Derived `PlaySpec`, or `null` if the current state has no view metadata.
|
|
74
|
+
*/
|
|
75
|
+
export const deriveCurrentView = (snapshot) => {
|
|
76
|
+
// Follow the SAME single active branch the route derivation walks, so that
|
|
77
|
+
// for a parallel machine the rendered view belongs to the region the URL
|
|
78
|
+
// points at whenever that region declares one.
|
|
79
|
+
const meta = activeStateMeta(snapshot);
|
|
80
|
+
if (!meta) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
// A parallel machine may keep routes and views in DIFFERENT regions (one
|
|
84
|
+
// region owns navigation, another owns the shell). When the walked branch
|
|
85
|
+
// declares no view, scan the flat record of every active region — deepest
|
|
86
|
+
// entry wins — before concluding there is no view at all.
|
|
87
|
+
let resolved = resolveViewMeta(meta);
|
|
88
|
+
if (!resolved) {
|
|
89
|
+
const flatMeta = snapshot.getMeta();
|
|
90
|
+
if (flatMeta && typeof flatMeta === "object") {
|
|
91
|
+
resolved = resolveViewMeta(flatMeta);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (!resolved) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const { key: viewKey, view: viewMeta } = resolved;
|
|
98
|
+
if ("contextProps" in viewMeta) {
|
|
99
|
+
warnRemovedContextProps(viewMeta);
|
|
100
|
+
}
|
|
101
|
+
// Project the whole context under /context. composePlayState skips the
|
|
102
|
+
// projection (authored state wins, with a dev warning) when spec.state
|
|
103
|
+
// already declares a top-level "context" key.
|
|
104
|
+
const slice = snapshot.context !== null && typeof snapshot.context === "object"
|
|
105
|
+
? snapshot.context
|
|
106
|
+
: undefined;
|
|
107
|
+
const authoredState = viewMeta.state !== undefined ? toAtomState(viewMeta.state) : undefined;
|
|
108
|
+
const state = composePlayState(authoredState, slice);
|
|
109
|
+
return {
|
|
110
|
+
...viewMeta,
|
|
111
|
+
viewKey,
|
|
112
|
+
...(state !== undefined && { state }),
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=derive-current-view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive-current-view.js","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"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"}
|