@xmachines/play-xstate 1.1.0 → 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 +36 -2
- package/dist/guards/compose.d.ts.map +1 -1
- package/dist/guards/compose.js +24 -28
- package/dist/guards/compose.js.map +1 -1
- package/dist/player-actor.d.ts +5 -3
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +16 -20
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
- package/dist/routing/format-play-route-transitions.js +15 -2
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/view/derive-current-view.d.ts +22 -27
- package/dist/view/derive-current-view.d.ts.map +1 -1
- package/dist/view/derive-current-view.js +62 -114
- package/dist/view/derive-current-view.js.map +1 -1
- package/package.json +13 -10
package/README.md
CHANGED
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> XState v5 adapter for the XMachines Play Architecture — bind state machines to the actor base with signal-driven reactivity and router integration.
|
|
4
4
|
|
|
5
|
-
[](https://opensource.org/licenses/MIT)
|
|
6
|
-
[](https://www.npmjs.com/package/@xmachines/play-xstate)
|
|
5
|
+
[](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/@xmachines/play-xstate)
|
|
7
6
|
|
|
8
7
|
Part of the [XMachines Play](../../README.md) monorepo.
|
|
9
8
|
|
|
@@ -253,6 +252,41 @@ const machine = setup({}).createMachine(config);
|
|
|
253
252
|
|
|
254
253
|
---
|
|
255
254
|
|
|
255
|
+
## Inspection
|
|
256
|
+
|
|
257
|
+
`options.inspect` is forwarded verbatim to XState's `createActor`, so every XState
|
|
258
|
+
inspection tool — [`@statelyai/inspect`](https://stately.ai/docs/inspector)
|
|
259
|
+
included — works against a `PlayerActor` unchanged:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { createBrowserInspector } from "@statelyai/inspect";
|
|
263
|
+
|
|
264
|
+
const { inspect } = createBrowserInspector();
|
|
265
|
+
const createPlayer = definePlayer({ machine, options: { inspect } });
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Three things are worth knowing:
|
|
269
|
+
|
|
270
|
+
- **It is a factory option, not a per-instance one.** Every actor a factory creates
|
|
271
|
+
reports to the same observer. Demultiplex by root: `event.rootId === actor.sessionId`
|
|
272
|
+
covers an actor's whole tree, children included.
|
|
273
|
+
- **It is the only route that sees construction.** `actor.system.inspect(fn)` attaches
|
|
274
|
+
later and only sees events from that point on — including missing the `@xstate.actor`
|
|
275
|
+
registration an inspector needs in order to draw the machine at all.
|
|
276
|
+
- **A `PlayerActor` is the actor.** Its own events carry `actorRef === playerActor`, so a
|
|
277
|
+
player can be recognised by identity. The one caveat: `@xstate.actor` fires from inside
|
|
278
|
+
the constructor, where `state`, `currentRoute`, `currentView` and `initialRoute` do not
|
|
279
|
+
exist yet — reading them there throws.
|
|
280
|
+
|
|
281
|
+
For an inspector created after the factory (a dev-tools toggle, say), pass a forwarding
|
|
282
|
+
function: `inspect: (event) => currentInspector?.(event)`.
|
|
283
|
+
|
|
284
|
+
See the [inspector guide](../docs/guides/inspector.md) for the full walkthrough —
|
|
285
|
+
late attachment with replay, browser-free WebSocket inspection, and production
|
|
286
|
+
considerations.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
256
290
|
## Exported Types
|
|
257
291
|
|
|
258
292
|
```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAkB/E;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,CACzC,cAAc,EACd,WAAW,EACX,OAAO,EACP,mBAAmB,CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACzD,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAYF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,eAAO,MAAM,eAAe,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAC3D,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAYF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,eAAO,MAAM,WAAW,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACvD,OAAO,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,KACrC,aAIF,CAAC"}
|
package/dist/guards/compose.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { and, or, not } from "xstate";
|
|
2
2
|
import { EmptyGuardArrayError } from "../errors.js";
|
|
3
|
+
/**
|
|
4
|
+
* PRODUCTION code's single unsound boundary, scoped to XState's guard typings.
|
|
5
|
+
* (Test code uses `unsafeCast` from `@xmachines/shared/test-support` instead —
|
|
6
|
+
* the two are counterparts; a grep-based cast audit must cover both names.)
|
|
7
|
+
*
|
|
8
|
+
* These deprecated helpers bridge two known gaps in XState 5.28's types: our
|
|
9
|
+
* `Guard<TContext, TEvent>` does not structurally match `ComposedGuard`
|
|
10
|
+
* (generic event mismatch), and `and()`/`or()` require `readonly [...tuple]`
|
|
11
|
+
* where `GuardArray` is a mutable array. The runtime values are identical in
|
|
12
|
+
* every case. The parameter is `unknown`, so the one `as` lives here instead
|
|
13
|
+
* of double-casts at each call site.
|
|
14
|
+
* Track XState typing improvements: https://github.com/statelyai/xstate/issues
|
|
15
|
+
*/
|
|
16
|
+
const asXStateGuard = (value) => value;
|
|
3
17
|
/**
|
|
4
18
|
* Compose guards with AND logic using XState's and() helper
|
|
5
19
|
*
|
|
@@ -63,19 +77,11 @@ export const composeGuards = (guards) => {
|
|
|
63
77
|
throw new EmptyGuardArrayError("and");
|
|
64
78
|
}
|
|
65
79
|
if (guards.length === 1) {
|
|
66
|
-
// Single guard passthrough —
|
|
67
|
-
|
|
68
|
-
// At runtime both are plain function objects with identical shape.
|
|
69
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
70
|
-
return guards[0];
|
|
80
|
+
// Single guard passthrough — see asXStateGuard for why the boundary exists.
|
|
81
|
+
return asXStateGuard(guards[0]);
|
|
71
82
|
}
|
|
72
83
|
// Use XState's built-in and() for type inference and serialization.
|
|
73
|
-
|
|
74
|
-
// We cast through unknown to express the narrowest possible type boundary rather than
|
|
75
|
-
// escaping to `any`. The runtime value is identical.
|
|
76
|
-
// Track XState typing improvements: https://github.com/statelyai/xstate/issues
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
-
return and(guards);
|
|
84
|
+
return and(asXStateGuard(guards));
|
|
79
85
|
};
|
|
80
86
|
/**
|
|
81
87
|
* Compose guards with OR logic using XState's or() helper
|
|
@@ -125,18 +131,11 @@ export const composeGuardsOr = (guards) => {
|
|
|
125
131
|
throw new EmptyGuardArrayError("or");
|
|
126
132
|
}
|
|
127
133
|
if (guards.length === 1) {
|
|
128
|
-
// Single guard passthrough —
|
|
129
|
-
|
|
130
|
-
// At runtime both are plain function objects with identical shape.
|
|
131
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
132
|
-
return guards[0];
|
|
134
|
+
// Single guard passthrough — see asXStateGuard for why the boundary exists.
|
|
135
|
+
return asXStateGuard(guards[0]);
|
|
133
136
|
}
|
|
134
|
-
// XState
|
|
135
|
-
|
|
136
|
-
// escaping to `any`. The runtime value is identical.
|
|
137
|
-
// Track XState typing improvements: https://github.com/statelyai/xstate/issues
|
|
138
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
139
|
-
return or(guards);
|
|
137
|
+
// Use XState's built-in or() for type inference and serialization.
|
|
138
|
+
return or(asXStateGuard(guards));
|
|
140
139
|
};
|
|
141
140
|
/**
|
|
142
141
|
* Negate a guard using XState's not() helper
|
|
@@ -178,11 +177,8 @@ export const composeGuardsOr = (guards) => {
|
|
|
178
177
|
*/
|
|
179
178
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
180
179
|
export const negateGuard = (guard) => {
|
|
181
|
-
// XState 5.28.0: not() requires a specific SingleGuardArg shape, not our
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
// Track XState typing improvements: https://github.com/statelyai/xstate/issues
|
|
185
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
-
return not(guard);
|
|
180
|
+
// XState 5.28.0: not() requires a specific SingleGuardArg shape, not our
|
|
181
|
+
// Guard type — see asXStateGuard.
|
|
182
|
+
return not(asXStateGuard(guard));
|
|
187
183
|
};
|
|
188
184
|
//# sourceMappingURL=compose.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAItC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD;;;;;;;;;;;;GAYG;AACH,MAAM,aAAa,GAAG,CAAI,KAAc,EAAK,EAAE,CAAC,KAAU,CAAC;AAmB3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,CAC5B,MAAoC,EACpB,EAAE;IAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,4EAA4E;QAC5E,OAAO,aAAa,CAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,oEAAoE;IACpE,OAAO,GAAG,CAAC,aAAa,CAA4B,MAAM,CAAC,CAAC,CAAC;AAC9D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAG,CAC9B,MAAoC,EACpB,EAAE;IAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,4EAA4E;QAC5E,OAAO,aAAa,CAAgB,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC;IAED,mEAAmE;IACnE,OAAO,EAAE,CAAC,aAAa,CAA2B,MAAM,CAAC,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAC1B,KAAuC,EACvB,EAAE;IAClB,yEAAyE;IACzE,kCAAkC;IAClC,OAAO,GAAG,CAAC,aAAa,CAA4B,KAAK,CAAC,CAAC,CAAC;AAC7D,CAAC,CAAC"}
|
package/dist/player-actor.d.ts
CHANGED
|
@@ -195,9 +195,11 @@ export declare class PlayerActor<TMachine extends AnyStateMachine> extends Abstr
|
|
|
195
195
|
* not change the rendered view (e.g. context-only assigns) keep the previous
|
|
196
196
|
* reference so downstream providers do not remount the UI on every event.
|
|
197
197
|
*
|
|
198
|
-
* The emitted `PlaySpec`
|
|
199
|
-
*
|
|
200
|
-
*
|
|
198
|
+
* The emitted `PlaySpec` carries the machine's context in its composed
|
|
199
|
+
* `state` under the read-only `/context` subtree, so specs read context —
|
|
200
|
+
* URL params included — through the ordinary state grammar
|
|
201
|
+
* (`{ $state: "/context/params/section" }`). See `@xmachines/play-actor`'s
|
|
202
|
+
* context-projection module for the full contract.
|
|
201
203
|
*
|
|
202
204
|
* Returns `null` when the current state has no `meta.view` metadata.
|
|
203
205
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"player-actor.d.ts","sourceRoot":"","sources":["../src/player-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,EACL,KAAK,eAAe,EACpB,KAAK,aAAa,EAElB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,MAAM,QAAQ,CAAC;AAChB,OAAO,
|
|
1
|
+
{"version":3,"file":"player-actor.d.ts","sourceRoot":"","sources":["../src/player-actor.ts"],"names":[],"mappings":"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"}
|
package/dist/player-actor.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Actor, } from "xstate";
|
|
2
|
-
import { AbstractActor } from "@xmachines/play-actor";
|
|
2
|
+
import { AbstractActor, reuseComposedState, shallowEqualExcept, } from "@xmachines/play-actor";
|
|
3
3
|
import { Signal } from "@xmachines/play-signals";
|
|
4
4
|
import { ActorThrewNonErrorError, InvalidEventError, InvalidMachineError } from "./errors.js";
|
|
5
5
|
import { deriveCurrentRoute, deriveInitialRoute } from "./routing/index.js";
|
|
@@ -39,20 +39,6 @@ const toError = (value) => {
|
|
|
39
39
|
}
|
|
40
40
|
return new ActorThrewNonErrorError(value);
|
|
41
41
|
};
|
|
42
|
-
/** Own-key shallow equality with `Object.is`, ignoring `except` on both sides. */
|
|
43
|
-
const shallowEqualExcept = (a, b, except) => {
|
|
44
|
-
const aEntries = Object.entries(a).filter(([key]) => key !== except);
|
|
45
|
-
const bKeyCount = Object.keys(b).filter((key) => key !== except).length;
|
|
46
|
-
if (aEntries.length !== bKeyCount)
|
|
47
|
-
return false;
|
|
48
|
-
const bRecord = b;
|
|
49
|
-
for (const [key, value] of aEntries) {
|
|
50
|
-
// nosemgrep: gitlab.eslint.detect-object-injection
|
|
51
|
-
if (!Object.hasOwn(b, key) || !Object.is(value, bRecord[key]))
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
return true;
|
|
55
|
-
};
|
|
56
42
|
/**
|
|
57
43
|
* Bounded structural equality for derived view specs.
|
|
58
44
|
*
|
|
@@ -72,6 +58,10 @@ const viewSpecsEquivalent = (a, b) => {
|
|
|
72
58
|
return false;
|
|
73
59
|
const aElements = a.elements ?? {};
|
|
74
60
|
const bElements = b.elements ?? {};
|
|
61
|
+
// Derived specs spread the same static meta.view, so elements is usually
|
|
62
|
+
// reference-identical — skip the per-element walk when it is.
|
|
63
|
+
if (aElements === bElements)
|
|
64
|
+
return true;
|
|
75
65
|
const elementKeys = Object.keys(aElements);
|
|
76
66
|
if (elementKeys.length !== Object.keys(bElements).length)
|
|
77
67
|
return false;
|
|
@@ -276,9 +266,11 @@ export class PlayerActor extends AbstractActor {
|
|
|
276
266
|
* not change the rendered view (e.g. context-only assigns) keep the previous
|
|
277
267
|
* reference so downstream providers do not remount the UI on every event.
|
|
278
268
|
*
|
|
279
|
-
* The emitted `PlaySpec`
|
|
280
|
-
*
|
|
281
|
-
*
|
|
269
|
+
* The emitted `PlaySpec` carries the machine's context in its composed
|
|
270
|
+
* `state` under the read-only `/context` subtree, so specs read context —
|
|
271
|
+
* URL params included — through the ordinary state grammar
|
|
272
|
+
* (`{ $state: "/context/params/section" }`). See `@xmachines/play-actor`'s
|
|
273
|
+
* context-projection module for the full contract.
|
|
282
274
|
*
|
|
283
275
|
* Returns `null` when the current state has no `meta.view` metadata.
|
|
284
276
|
*
|
|
@@ -568,10 +560,14 @@ export class PlayerActor extends AbstractActor {
|
|
|
568
560
|
// IS the signal's current value; read it untracked so the gate never
|
|
569
561
|
// registers currentView as a dependency of a surrounding computation.
|
|
570
562
|
const lastEmittedView = Signal.subtle.untrack(() => this.currentView.get());
|
|
571
|
-
|
|
563
|
+
// Reuse the previous composed state reference when the /context
|
|
564
|
+
// projection is value-unchanged, so a context-only assign that does
|
|
565
|
+
// not alter projected values cannot churn state identity.
|
|
566
|
+
const nextView = reuseComposedState(lastEmittedView, view);
|
|
567
|
+
if (viewSpecsEquivalent(lastEmittedView, nextView)) {
|
|
572
568
|
return;
|
|
573
569
|
}
|
|
574
|
-
this.currentView.set(
|
|
570
|
+
this.currentView.set(nextView);
|
|
575
571
|
}
|
|
576
572
|
catch (error) {
|
|
577
573
|
const onError = this.hooks.onError;
|
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,GAYL,MAAM,QAAQ,CAAC;AAChB,OAAO,
|
|
1
|
+
{"version":3,"file":"player-actor.js","sourceRoot":"","sources":["../src/player-actor.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-play-route-transitions.d.ts","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format-play-route-transitions.d.ts","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkBhD;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,iHAAiH;IACjH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,iEAAiE;IACjE,IAAI,CAAC,EAAE;QACN;;;WAGG;QACH,KAAK,CAAC,EAAE,aAAa,CAAC;KACtB,CAAC;IACF,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACxC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAaF;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC7C,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,0BAA0B,CAAC,CAAC,SAAS,kBAAkB,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,CAkF5F"}
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { assign } from "xstate";
|
|
2
|
+
import { shallowEqualExcept } from "@xmachines/play-actor";
|
|
2
3
|
import { MissingStateIdError } from "../errors.js";
|
|
3
4
|
import { normalizeRoute } from "./derive-route.js";
|
|
5
|
+
/**
|
|
6
|
+
* Reuse the previous params/query container when the incoming one is
|
|
7
|
+
* shallow-equal.
|
|
8
|
+
*
|
|
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);
|
|
4
17
|
/**
|
|
5
18
|
* Formats play.route transitions from declarative route configs
|
|
6
19
|
*
|
|
@@ -54,8 +67,8 @@ export function formatPlayRouteTransitions(machineConfig) {
|
|
|
54
67
|
guard: ({ event }) => event.to === `#${node.id}`,
|
|
55
68
|
reenter: true,
|
|
56
69
|
actions: assign({
|
|
57
|
-
params: ({ event }) => event.params || {},
|
|
58
|
-
query: ({ event }) => event.query || {},
|
|
70
|
+
params: ({ context, event }) => keepEqualContainer(context.params, event.params || {}),
|
|
71
|
+
query: ({ context, event }) => keepEqualContainer(context.query, event.query || {}),
|
|
59
72
|
}),
|
|
60
73
|
};
|
|
61
74
|
routeTransitions.push(transition);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format-play-route-transitions.js","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"format-play-route-transitions.js","sourceRoot":"","sources":["../../src/routing/format-play-route-transitions.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,48 +7,43 @@
|
|
|
7
7
|
* URL points at.
|
|
8
8
|
*/
|
|
9
9
|
import type { AnyMachineSnapshot } from "xstate";
|
|
10
|
-
import type
|
|
10
|
+
import { type PlaySpec } from "@xmachines/play-actor";
|
|
11
11
|
/**
|
|
12
12
|
* Derive the actor's current view from state metadata.
|
|
13
13
|
*
|
|
14
14
|
* Always returns a **fresh** `PlaySpec` object so a genuine view change is never
|
|
15
15
|
* suppressed by `Signal.State`'s `Object.is` equality check. Whether that fresh
|
|
16
16
|
* object is actually emitted is decided by `PlayerActor.validateAndCacheView`,
|
|
17
|
-
* which compares against the last emitted spec
|
|
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
|
|
18
19
|
* rendered view is unchanged — preventing downstream providers from remounting
|
|
19
20
|
* the UI on every event.
|
|
20
21
|
*
|
|
21
|
-
* ###
|
|
22
|
+
* ### Context projection
|
|
22
23
|
*
|
|
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`).
|
|
24
32
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* props without manual wiring.
|
|
33
|
+
* The whole context is always projected; the authored `meta.view` object is
|
|
34
|
+
* never mutated.
|
|
28
35
|
*
|
|
29
|
-
*
|
|
30
|
-
* Exposes selected context fields as component props for states where no URL param covers
|
|
31
|
-
* the data (e.g. `context.username` on a `/dashboard` route). Only fields explicitly named
|
|
32
|
-
* in `spec.contextProps: string[]` are ever exposed — nothing leaks from context implicitly.
|
|
36
|
+
* ### viewKey
|
|
33
37
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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.
|
|
38
44
|
*
|
|
39
45
|
* @param snapshot - Current XState machine snapshot.
|
|
40
|
-
* @returns
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```ts
|
|
44
|
-
* // spec: { contextProps: ["username"], elements: { root: { props: { username: undefined } } } }
|
|
45
|
-
* // context.username = "alice", context.params = {}
|
|
46
|
-
* // Derived props: { username: "alice" }
|
|
47
|
-
*
|
|
48
|
-
* // spec: { contextProps: ["username"], elements: { root: { props: { username: undefined } } } }
|
|
49
|
-
* // context.username = "alice", context.params = { username: "demo" }
|
|
50
|
-
* // Derived props: { username: "demo" } ← URL param wins
|
|
51
|
-
* ```
|
|
46
|
+
* @returns Derived `PlaySpec`, or `null` if the current state has no view metadata.
|
|
52
47
|
*/
|
|
53
48
|
export declare const deriveCurrentView: (snapshot: AnyMachineSnapshot) => PlaySpec | null;
|
|
54
49
|
//# sourceMappingURL=derive-current-view.d.ts.map
|
|
@@ -1 +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,KAAK,
|
|
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"}
|
|
@@ -1,11 +1,28 @@
|
|
|
1
|
+
import { composePlayState, toAtomState } from "@xmachines/play-actor";
|
|
1
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
|
+
};
|
|
2
18
|
const resolveViewMeta = (meta) => {
|
|
3
19
|
// Iterate last-to-first: snapshot.getMeta() orders keys ancestors-first, so
|
|
4
20
|
// scanning from the end makes the deepest active state's meta.view win over
|
|
5
21
|
// an ancestor's instead of being shadowed by it.
|
|
6
|
-
const
|
|
7
|
-
for (let i =
|
|
8
|
-
|
|
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
|
|
9
26
|
const maybeView = stateMeta && typeof stateMeta === "object"
|
|
10
27
|
? stateMeta.view
|
|
11
28
|
: undefined;
|
|
@@ -13,93 +30,47 @@ const resolveViewMeta = (meta) => {
|
|
|
13
30
|
typeof maybeView === "object" &&
|
|
14
31
|
"root" in maybeView &&
|
|
15
32
|
"elements" in maybeView) {
|
|
16
|
-
return maybeView;
|
|
33
|
+
return { key, view: maybeView };
|
|
17
34
|
}
|
|
18
35
|
}
|
|
19
36
|
return null;
|
|
20
37
|
};
|
|
21
|
-
/**
|
|
22
|
-
* Merge route parameters and an explicit allowlist of context fields into a single
|
|
23
|
-
* element's props.
|
|
24
|
-
*
|
|
25
|
-
* Priority rule (highest → lowest):
|
|
26
|
-
* 1. Explicit non-`undefined` spec prop — always wins (static values are authoritative).
|
|
27
|
-
* 2. URL route params (`context.params`) — fills `undefined` slots from the URL path.
|
|
28
|
-
* 3. Allowlisted context fields (`contextProps`) — fills remaining `undefined` slots from
|
|
29
|
-
* the machine context (e.g. `context.username` on a state with no URL username param).
|
|
30
|
-
*
|
|
31
|
-
* The `contextProps` allowlist is the key safety mechanism: only fields the machine
|
|
32
|
-
* explicitly opts in to are ever exposed to components.
|
|
33
|
-
*
|
|
34
|
-
* @param urlParams - Extracted URL path parameters from `context.params`.
|
|
35
|
-
* @param contextValues - Object containing only the allowlisted context fields.
|
|
36
|
-
* @param existingProps - The element's props as declared in the machine spec.
|
|
37
|
-
* @returns Merged props object with URL params and allowlisted context values filling
|
|
38
|
-
* undefined slots.
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* ```ts
|
|
42
|
-
* // spec: { section: undefined, username: undefined, title: "Dashboard" }
|
|
43
|
-
* // urlParams: { section: "profile" } ← from URL /:section
|
|
44
|
-
* // contextValues: { username: "alice" } ← from contextProps: ["username"]
|
|
45
|
-
* // result: { section: "profile", username: "alice", title: "Dashboard" }
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
function mergeRouteParamsIntoProps(urlParams, contextValues, existingProps) {
|
|
49
|
-
// Layer 3 (lowest priority): allowlisted context values
|
|
50
|
-
const merged = { ...contextValues };
|
|
51
|
-
// Layer 2: URL params override context values for the same key
|
|
52
|
-
for (const [k, v] of Object.entries(urlParams)) {
|
|
53
|
-
merged[k] = v; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
54
|
-
}
|
|
55
|
-
// Layer 1 (highest priority): explicit non-undefined spec props always win
|
|
56
|
-
for (const [k, v] of Object.entries(existingProps)) {
|
|
57
|
-
if (v !== undefined)
|
|
58
|
-
merged[k] = v; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
59
|
-
}
|
|
60
|
-
return merged;
|
|
61
|
-
}
|
|
62
38
|
/**
|
|
63
39
|
* Derive the actor's current view from state metadata.
|
|
64
40
|
*
|
|
65
41
|
* Always returns a **fresh** `PlaySpec` object so a genuine view change is never
|
|
66
42
|
* suppressed by `Signal.State`'s `Object.is` equality check. Whether that fresh
|
|
67
43
|
* object is actually emitted is decided by `PlayerActor.validateAndCacheView`,
|
|
68
|
-
* which compares against the last emitted spec
|
|
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
|
|
69
46
|
* rendered view is unchanged — preventing downstream providers from remounting
|
|
70
47
|
* the UI on every event.
|
|
71
48
|
*
|
|
72
|
-
* ###
|
|
49
|
+
* ### Context projection
|
|
73
50
|
*
|
|
74
|
-
*
|
|
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`).
|
|
75
59
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* props without manual wiring.
|
|
60
|
+
* The whole context is always projected; the authored `meta.view` object is
|
|
61
|
+
* never mutated.
|
|
79
62
|
*
|
|
80
|
-
*
|
|
81
|
-
* Exposes selected context fields as component props for states where no URL param covers
|
|
82
|
-
* the data (e.g. `context.username` on a `/dashboard` route). Only fields explicitly named
|
|
83
|
-
* in `spec.contextProps: string[]` are ever exposed — nothing leaks from context implicitly.
|
|
63
|
+
* ### viewKey
|
|
84
64
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
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.
|
|
89
71
|
*
|
|
90
72
|
* @param snapshot - Current XState machine snapshot.
|
|
91
|
-
* @returns
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```ts
|
|
95
|
-
* // spec: { contextProps: ["username"], elements: { root: { props: { username: undefined } } } }
|
|
96
|
-
* // context.username = "alice", context.params = {}
|
|
97
|
-
* // Derived props: { username: "alice" }
|
|
98
|
-
*
|
|
99
|
-
* // spec: { contextProps: ["username"], elements: { root: { props: { username: undefined } } } }
|
|
100
|
-
* // context.username = "alice", context.params = { username: "demo" }
|
|
101
|
-
* // Derived props: { username: "demo" } ← URL param wins
|
|
102
|
-
* ```
|
|
73
|
+
* @returns Derived `PlaySpec`, or `null` if the current state has no view metadata.
|
|
103
74
|
*/
|
|
104
75
|
export const deriveCurrentView = (snapshot) => {
|
|
105
76
|
// Follow the SAME single active branch the route derivation walks, so that
|
|
@@ -113,55 +84,32 @@ export const deriveCurrentView = (snapshot) => {
|
|
|
113
84
|
// region owns navigation, another owns the shell). When the walked branch
|
|
114
85
|
// declares no view, scan the flat record of every active region — deepest
|
|
115
86
|
// entry wins — before concluding there is no view at all.
|
|
116
|
-
let
|
|
117
|
-
if (!
|
|
87
|
+
let resolved = resolveViewMeta(meta);
|
|
88
|
+
if (!resolved) {
|
|
118
89
|
const flatMeta = snapshot.getMeta();
|
|
119
90
|
if (flatMeta && typeof flatMeta === "object") {
|
|
120
|
-
|
|
91
|
+
resolved = resolveViewMeta(flatMeta);
|
|
121
92
|
}
|
|
122
93
|
}
|
|
123
|
-
if (!
|
|
94
|
+
if (!resolved) {
|
|
124
95
|
return null;
|
|
125
96
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
typeof snapshot.context === "object"
|
|
130
|
-
? snapshot.context
|
|
131
|
-
: null;
|
|
132
|
-
// Values flow into props verbatim — only the URL layer stringifies. The
|
|
133
|
-
// type matches RouteContext.params; a `Record<string, string>` cast here
|
|
134
|
-
// would lie about e.g. numeric params assigned by hand-rolled handlers.
|
|
135
|
-
const urlParams = context !== null && typeof context.params === "object" && context.params !== null
|
|
136
|
-
? context.params
|
|
137
|
-
: {};
|
|
138
|
-
// Extract the allowlisted context fields declared in contextProps.
|
|
139
|
-
// Only fields explicitly named in the allowlist are ever exposed to components.
|
|
140
|
-
const contextPropsAllowlist = viewMeta?.contextProps ?? [];
|
|
141
|
-
const contextValues = {};
|
|
142
|
-
if (context !== null && contextPropsAllowlist.length > 0) {
|
|
143
|
-
for (const key of contextPropsAllowlist) {
|
|
144
|
-
// nosemgrep: gitlab.eslint.detect-object-injection
|
|
145
|
-
if (key in context && context[key] !== null && context[key] !== undefined) {
|
|
146
|
-
contextValues[key] = context[key]; // nosemgrep: gitlab.eslint.detect-object-injection
|
|
147
|
-
}
|
|
148
|
-
}
|
|
97
|
+
const { key: viewKey, view: viewMeta } = resolved;
|
|
98
|
+
if ("contextProps" in viewMeta) {
|
|
99
|
+
warnRemovedContextProps(viewMeta);
|
|
149
100
|
}
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return { ...viewMeta, elements: enrichedElements };
|
|
164
|
-
}
|
|
165
|
-
return viewMeta;
|
|
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
|
+
};
|
|
166
114
|
};
|
|
167
115
|
//# sourceMappingURL=derive-current-view.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive-current-view.js","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"derive-current-view.js","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmachines/play-xstate",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "XState v5 adapter for Play Architecture",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"actor-model",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"author": "",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "git+
|
|
16
|
+
"url": "git+https://gitlab.com/xmachin-es/xmachines-js.git",
|
|
17
17
|
"directory": "packages/play-xstate"
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
@@ -28,36 +28,39 @@
|
|
|
28
28
|
"exports": {
|
|
29
29
|
".": {
|
|
30
30
|
"types": "./dist/index.d.ts",
|
|
31
|
-
"
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
32
|
},
|
|
33
33
|
"./errors": {
|
|
34
34
|
"types": "./dist/errors.d.ts",
|
|
35
|
-
"
|
|
36
|
-
}
|
|
35
|
+
"default": "./dist/errors.js"
|
|
36
|
+
},
|
|
37
|
+
"./package.json": "./package.json"
|
|
37
38
|
},
|
|
38
39
|
"publishConfig": {
|
|
39
40
|
"access": "public"
|
|
40
41
|
},
|
|
41
42
|
"scripts": {
|
|
42
|
-
"build": "tsc --build",
|
|
43
|
+
"build": "vite build && tsc --build",
|
|
43
44
|
"clean": "rm -rf dist *.tsbuildinfo coverage node_modules/.svelte2tsx-* node_modules/.vite*",
|
|
44
45
|
"lint": "oxlint .",
|
|
45
46
|
"format": "oxfmt .",
|
|
46
47
|
"test": "vitest"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
|
-
"@xmachines/play": "
|
|
50
|
-
"@xmachines/play-actor": "
|
|
51
|
-
"@xmachines/play-signals": "
|
|
50
|
+
"@xmachines/play": "2.0.0",
|
|
51
|
+
"@xmachines/play-actor": "2.0.0",
|
|
52
|
+
"@xmachines/play-signals": "2.0.0",
|
|
52
53
|
"dequal": "^2.0.3"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
56
|
"@testing-library/jest-dom": "^6.9.1",
|
|
56
57
|
"@types/node": "^26.2.0",
|
|
57
|
-
"@xmachines/
|
|
58
|
+
"@xmachines/json-render-core": "^0.20.0-xm.2",
|
|
59
|
+
"@xmachines/play-router": "2.0.0",
|
|
58
60
|
"oxfmt": "^0.64.0",
|
|
59
61
|
"oxlint": "^1.79.0",
|
|
60
62
|
"typescript": "^5.9.3 || ^6.0.3",
|
|
63
|
+
"vite": "^8.0.10",
|
|
61
64
|
"vitest": "^4.1.11",
|
|
62
65
|
"xstate": "^5.31.0"
|
|
63
66
|
},
|