@xmachines/play-xstate 1.0.0-beta.2 → 1.0.0-beta.21
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 +263 -107
- package/dist/define-player.d.ts +6 -56
- package/dist/define-player.d.ts.map +1 -1
- package/dist/define-player.js +8 -60
- package/dist/define-player.js.map +1 -1
- package/dist/define-player.typecheck.d.ts +2 -0
- package/dist/define-player.typecheck.d.ts.map +1 -0
- package/dist/define-player.typecheck.js +48 -0
- package/dist/define-player.typecheck.js.map +1 -0
- package/dist/errors.d.ts +66 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +76 -0
- package/dist/errors.js.map +1 -0
- package/dist/guards/compose.d.ts +14 -3
- package/dist/guards/compose.d.ts.map +1 -1
- package/dist/guards/compose.js +26 -0
- package/dist/guards/compose.js.map +1 -1
- package/dist/guards/helpers.d.ts +13 -17
- package/dist/guards/helpers.d.ts.map +1 -1
- package/dist/guards/helpers.js +20 -25
- package/dist/guards/helpers.js.map +1 -1
- package/dist/guards/index.d.ts +2 -1
- package/dist/guards/index.d.ts.map +1 -1
- package/dist/guards/index.js +1 -1
- package/dist/guards/index.js.map +1 -1
- package/dist/guards/types.d.ts +3 -2
- package/dist/guards/types.d.ts.map +1 -1
- package/dist/index.d.ts +7 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/player-actor.d.ts +70 -22
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +290 -88
- package/dist/player-actor.js.map +1 -1
- package/dist/player-actor.typecheck.d.ts +2 -0
- package/dist/player-actor.typecheck.d.ts.map +1 -0
- package/dist/player-actor.typecheck.js +27 -0
- package/dist/player-actor.typecheck.js.map +1 -0
- package/dist/routing/build-url.d.ts +22 -16
- package/dist/routing/build-url.d.ts.map +1 -1
- package/dist/routing/build-url.js +27 -20
- package/dist/routing/build-url.js.map +1 -1
- package/dist/routing/derive-route.d.ts +2 -2
- package/dist/routing/derive-route.d.ts.map +1 -1
- package/dist/routing/derive-route.js +3 -3
- package/dist/routing/derive-route.js.map +1 -1
- package/dist/routing/format-play-route-transitions.d.ts +41 -4
- package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
- package/dist/routing/format-play-route-transitions.js +22 -19
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/routing/index.d.ts +2 -1
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/types.d.ts +8 -13
- package/dist/routing/types.d.ts.map +1 -1
- package/dist/signals/index.d.ts +0 -1
- package/dist/signals/index.d.ts.map +1 -1
- package/dist/signals/index.js +0 -1
- package/dist/signals/index.js.map +1 -1
- package/dist/signals/state-signal.d.ts +1 -1
- package/dist/signals/state-signal.d.ts.map +1 -1
- package/dist/types.d.ts +20 -14
- package/dist/types.d.ts.map +1 -1
- package/package.json +26 -19
- package/dist/catalog/index.d.ts +0 -12
- package/dist/catalog/index.d.ts.map +0 -1
- package/dist/catalog/index.js +0 -11
- package/dist/catalog/index.js.map +0 -1
- package/dist/catalog/types.d.ts +0 -36
- package/dist/catalog/types.d.ts.map +0 -1
- package/dist/catalog/types.js +0 -2
- package/dist/catalog/types.js.map +0 -1
- package/dist/catalog/validate-binding.d.ts +0 -21
- package/dist/catalog/validate-binding.d.ts.map +0 -1
- package/dist/catalog/validate-binding.js +0 -30
- package/dist/catalog/validate-binding.js.map +0 -1
- package/dist/catalog/validate-props.d.ts +0 -41
- package/dist/catalog/validate-props.d.ts.map +0 -1
- package/dist/catalog/validate-props.js +0 -95
- package/dist/catalog/validate-props.js.map +0 -1
package/dist/define-player.js
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
import { PlayerActor } from "./player-actor.js";
|
|
2
2
|
/**
|
|
3
|
-
* Create a player factory from XState machine
|
|
3
|
+
* Create a player factory from an XState machine
|
|
4
4
|
*
|
|
5
|
-
* Factory pattern that accepts an XState v5 machine
|
|
5
|
+
* Factory pattern that accepts an XState v5 machine,
|
|
6
6
|
* returning a function that creates {@link PlayerActor} instances. This enables
|
|
7
7
|
* creating multiple actor instances from a single configuration, useful for
|
|
8
8
|
* testing, multi-instance scenarios, or server-side rendering.
|
|
9
9
|
*
|
|
10
|
-
* **Architectural Context:** Implements **Strict Separation (INV-02)** by accepting
|
|
11
|
-
* the machine definition (pure business logic) separately from the catalog (UI vocabulary).
|
|
12
|
-
* The machine references component names in `meta.view` without importing React/framework code.
|
|
13
|
-
*
|
|
14
10
|
* @typeParam TMachine - XState v5 state machine type
|
|
15
|
-
* @typeParam TCatalog - Optional UI component catalog type
|
|
16
11
|
*
|
|
17
12
|
* @param config - Player configuration object
|
|
18
13
|
* @param config.machine - XState v5 state machine
|
|
19
|
-
* @param config.catalog - Optional UI component catalog (allows machines without UI)
|
|
20
14
|
* @param config.options - Optional lifecycle hooks (onStart, onTransition, etc.)
|
|
21
15
|
*
|
|
22
16
|
* @returns Factory function that creates actor instances with optional input context
|
|
23
17
|
*
|
|
24
18
|
* @example
|
|
25
|
-
* Basic player factory
|
|
19
|
+
* Basic player factory
|
|
26
20
|
* ```typescript
|
|
27
21
|
* import { setup } from "xstate";
|
|
28
22
|
* import { definePlayer } from "@xmachines/play-xstate";
|
|
@@ -41,53 +35,9 @@ import { PlayerActor } from "./player-actor.js";
|
|
|
41
35
|
* ```
|
|
42
36
|
*
|
|
43
37
|
* @example
|
|
44
|
-
* Player factory with catalog and parameter-aware routing
|
|
45
|
-
* ```typescript
|
|
46
|
-
* import { setup } from "xstate";
|
|
47
|
-
* import { defineCatalog } from "@xmachines/play-catalog";
|
|
48
|
-
* import { definePlayer } from "@xmachines/play-xstate";
|
|
49
|
-
* import { z } from "zod";
|
|
50
|
-
*
|
|
51
|
-
* const catalog = defineCatalog({
|
|
52
|
-
* HomePage: z.object({}),
|
|
53
|
-
* ProfilePage: z.object({ userId: z.string() })
|
|
54
|
-
* });
|
|
55
|
-
*
|
|
56
|
-
* const machine = setup({
|
|
57
|
-
* types: {
|
|
58
|
-
* context: {} as { userId: string },
|
|
59
|
-
* events: {} as { type: 'play.route'; to: string; params?: Record<string, string> }
|
|
60
|
-
* }
|
|
61
|
-
* }).createMachine({
|
|
62
|
-
* initial: 'home',
|
|
63
|
-
* context: { userId: '' },
|
|
64
|
-
* states: {
|
|
65
|
-
* home: {
|
|
66
|
-
* route: {},
|
|
67
|
-
* meta: {
|
|
68
|
-
* route: '/',
|
|
69
|
-
* view: { component: 'HomePage' }
|
|
70
|
-
* }
|
|
71
|
-
* },
|
|
72
|
-
* profile: {
|
|
73
|
-
* route: {},
|
|
74
|
-
* meta: {
|
|
75
|
-
* route: '/profile/:userId',
|
|
76
|
-
* view: { component: 'ProfilePage', userId: (ctx) => ctx.userId }
|
|
77
|
-
* }
|
|
78
|
-
* }
|
|
79
|
-
* }
|
|
80
|
-
* });
|
|
81
|
-
*
|
|
82
|
-
* const createPlayer = definePlayer({ machine, catalog });
|
|
83
|
-
* const actor = createPlayer({ userId: 'user123' });
|
|
84
|
-
* actor.start();
|
|
85
|
-
* ```
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
38
|
* Multiple actor instances from single factory
|
|
89
39
|
* ```typescript
|
|
90
|
-
* const createPlayer = definePlayer({ machine
|
|
40
|
+
* const createPlayer = definePlayer({ machine });
|
|
91
41
|
*
|
|
92
42
|
* // Create actors for different users
|
|
93
43
|
* const alice = createPlayer({ userId: 'alice' });
|
|
@@ -100,17 +50,15 @@ import { PlayerActor } from "./player-actor.js";
|
|
|
100
50
|
* console.log(alice.state.get() !== bob.state.get());
|
|
101
51
|
* ```
|
|
102
52
|
*
|
|
103
|
-
* @see
|
|
53
|
+
* @see [Play RFC](../../docs/rfc/play.md)
|
|
104
54
|
* @see {@link PlayerActor} for the concrete actor implementation
|
|
105
55
|
* @see {@link PlayerConfig} for configuration options
|
|
106
56
|
* @see {@link PlayerFactory} for factory function signature
|
|
107
57
|
*/
|
|
108
58
|
export const definePlayer = (config) => {
|
|
109
|
-
const { machine,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return (input) => {
|
|
113
|
-
return new PlayerActor(machine, catalog || {}, options || {}, input);
|
|
59
|
+
const { machine, options } = config;
|
|
60
|
+
return (input, restore) => {
|
|
61
|
+
return new PlayerActor(machine, options ?? {}, input, restore?.snapshot);
|
|
114
62
|
};
|
|
115
63
|
};
|
|
116
64
|
//# sourceMappingURL=define-player.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-player.js","sourceRoot":"","sources":["../src/define-player.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"define-player.js","sourceRoot":"","sources":["../src/define-player.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAC3B,MAA8B,EACJ,EAAE;IAC5B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAEpC,OAAO,CAAC,KAA2B,EAAE,OAA8C,EAAE,EAAE;QACtF,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC1E,CAAC,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-player.typecheck.d.ts","sourceRoot":"","sources":["../src/define-player.typecheck.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { setup } from "xstate";
|
|
2
|
+
import { definePlayer } from "./define-player.js";
|
|
3
|
+
const machine = setup({
|
|
4
|
+
types: {
|
|
5
|
+
context: {},
|
|
6
|
+
input: {},
|
|
7
|
+
events: {},
|
|
8
|
+
},
|
|
9
|
+
}).createMachine({
|
|
10
|
+
context: ({ input }) => ({ count: input.count }),
|
|
11
|
+
initial: "active",
|
|
12
|
+
states: {
|
|
13
|
+
active: {
|
|
14
|
+
on: {
|
|
15
|
+
inc: {
|
|
16
|
+
actions: ({ context }) => {
|
|
17
|
+
context.count += 1;
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
const createPlayer = definePlayer({
|
|
25
|
+
machine,
|
|
26
|
+
options: {
|
|
27
|
+
onTransition: (actor, prevState, nextState) => {
|
|
28
|
+
const actorNotAny = false;
|
|
29
|
+
const prevNotAny = false;
|
|
30
|
+
const nextNotAny = false;
|
|
31
|
+
void actorNotAny;
|
|
32
|
+
void prevNotAny;
|
|
33
|
+
void nextNotAny;
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
const actor = createPlayer({ count: 1 });
|
|
38
|
+
const snapshot = actor.getSnapshot();
|
|
39
|
+
const restoredActor = createPlayer({ count: 1 }, { snapshot });
|
|
40
|
+
const returnNotAny = false;
|
|
41
|
+
const restoredReturnNotAny = false;
|
|
42
|
+
void returnNotAny;
|
|
43
|
+
void restoredReturnNotAny;
|
|
44
|
+
// @ts-expect-error factory input must match machine input shape
|
|
45
|
+
createPlayer("invalid");
|
|
46
|
+
// @ts-expect-error snapshot must be nested under the `snapshot` key
|
|
47
|
+
createPlayer({ count: 1 }, { persisted: snapshot });
|
|
48
|
+
//# sourceMappingURL=define-player.typecheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-player.typecheck.js","sourceRoot":"","sources":["../src/define-player.typecheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,MAAM,OAAO,GAAG,KAAK,CAAC;IACrB,KAAK,EAAE;QACN,OAAO,EAAE,EAAuB;QAChC,KAAK,EAAE,EAAuB;QAC9B,MAAM,EAAE,EAAqB;KAC7B;CACD,CAAC,CAAC,aAAa,CAAC;IAChB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAChD,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE;QACP,MAAM,EAAE;YACP,EAAE,EAAE;gBACH,GAAG,EAAE;oBACJ,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;wBACxB,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;oBACpB,CAAC;iBACD;aACD;SACD;KACD;CACD,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,YAAY,CAAC;IACjC,OAAO;IACP,OAAO,EAAE;QACR,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE;YAK7C,MAAM,WAAW,GAA4B,KAAK,CAAC;YACnD,MAAM,UAAU,GAA2B,KAAK,CAAC;YACjD,MAAM,UAAU,GAA2B,KAAK,CAAC;YAEjD,KAAK,WAAW,CAAC;YACjB,KAAK,UAAU,CAAC;YAChB,KAAK,UAAU,CAAC;QACjB,CAAC;KACD;CACD,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;AACrC,MAAM,aAAa,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;AAI/D,MAAM,YAAY,GAA6B,KAAK,CAAC;AACrD,MAAM,oBAAoB,GAAqC,KAAK,CAAC;AACrE,KAAK,YAAY,CAAC;AAClB,KAAK,oBAAoB,CAAC;AAE1B,gEAAgE;AAChE,YAAY,CAAC,SAAS,CAAC,CAAC;AAExB,oEAAoE;AACpE,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { PlayError } from "@xmachines/play";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `buildRouteUrl()` when a required route parameter is absent from the
|
|
4
|
+
* actor's context.
|
|
5
|
+
*
|
|
6
|
+
* Use the `param` and `template` fields to identify the missing parameter without
|
|
7
|
+
* parsing the `.message` string.
|
|
8
|
+
*
|
|
9
|
+
* **Error code:** `PLAY_ROUTE_PARAM_MISSING`
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { MissingRouteParamError } from "@xmachines/play-xstate/errors";
|
|
14
|
+
*
|
|
15
|
+
* // The route template "/profile/:userId" requires "userId" in context.
|
|
16
|
+
* // If userId is absent, MissingRouteParamError is thrown when the
|
|
17
|
+
* // actor.currentRoute signal is read.
|
|
18
|
+
*
|
|
19
|
+
* try {
|
|
20
|
+
* actor.currentRoute.get();
|
|
21
|
+
* } catch (err) {
|
|
22
|
+
* if (err instanceof MissingRouteParamError) {
|
|
23
|
+
* console.error(
|
|
24
|
+
* `Missing "${err.param}" for template "${err.template}"`
|
|
25
|
+
* );
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class MissingRouteParamError extends PlayError {
|
|
31
|
+
/** The name of the route parameter that was missing (e.g. `"userId"`). */
|
|
32
|
+
readonly param: string;
|
|
33
|
+
/** The route template that required the missing parameter (e.g. `"/profile/:userId"`). */
|
|
34
|
+
readonly template: string;
|
|
35
|
+
constructor(param: string, template: string);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Thrown by `PlayerActor.send()` when the event argument is not a plain object.
|
|
39
|
+
*
|
|
40
|
+
* `PlayEvent` requires `{ type: string, ...fields }`. Passing `null`, `undefined`,
|
|
41
|
+
* a string, or any other non-object value is a programmer error.
|
|
42
|
+
*
|
|
43
|
+
* The offending value is attached as the `detail` readonly class field for debugging.
|
|
44
|
+
* TypeScript consumers can access `err.detail` directly without any unsafe cast.
|
|
45
|
+
*
|
|
46
|
+
* **Error code:** `PLAY_INVALID_EVENT`
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* import { InvalidEventError } from "@xmachines/play-xstate/errors";
|
|
51
|
+
*
|
|
52
|
+
* try {
|
|
53
|
+
* actor.send(null as any);
|
|
54
|
+
* } catch (err) {
|
|
55
|
+
* if (err instanceof InvalidEventError) {
|
|
56
|
+
* // err.detail is typed as `unknown` — no cast needed
|
|
57
|
+
* console.error("Invalid event passed to actor.send():", err.detail);
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare class InvalidEventError extends PlayError {
|
|
63
|
+
readonly detail: unknown;
|
|
64
|
+
constructor(detail: unknown);
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,0FAA0F;IAC1F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAU3C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;IAC/C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,MAAM,EAAE,OAAO;CAU3B"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { PlayError } from "@xmachines/play";
|
|
2
|
+
/**
|
|
3
|
+
* Thrown by `buildRouteUrl()` when a required route parameter is absent from the
|
|
4
|
+
* actor's context.
|
|
5
|
+
*
|
|
6
|
+
* Use the `param` and `template` fields to identify the missing parameter without
|
|
7
|
+
* parsing the `.message` string.
|
|
8
|
+
*
|
|
9
|
+
* **Error code:** `PLAY_ROUTE_PARAM_MISSING`
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { MissingRouteParamError } from "@xmachines/play-xstate/errors";
|
|
14
|
+
*
|
|
15
|
+
* // The route template "/profile/:userId" requires "userId" in context.
|
|
16
|
+
* // If userId is absent, MissingRouteParamError is thrown when the
|
|
17
|
+
* // actor.currentRoute signal is read.
|
|
18
|
+
*
|
|
19
|
+
* try {
|
|
20
|
+
* actor.currentRoute.get();
|
|
21
|
+
* } catch (err) {
|
|
22
|
+
* if (err instanceof MissingRouteParamError) {
|
|
23
|
+
* console.error(
|
|
24
|
+
* `Missing "${err.param}" for template "${err.template}"`
|
|
25
|
+
* );
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export class MissingRouteParamError extends PlayError {
|
|
31
|
+
/** The name of the route parameter that was missing (e.g. `"userId"`). */
|
|
32
|
+
param;
|
|
33
|
+
/** The route template that required the missing parameter (e.g. `"/profile/:userId"`). */
|
|
34
|
+
template;
|
|
35
|
+
constructor(param, template) {
|
|
36
|
+
super("buildRouteUrl", "PLAY_ROUTE_PARAM_MISSING", `Route parameter '${param}' is required by template '${template}' but was not found in context.`);
|
|
37
|
+
this.name = "MissingRouteParamError";
|
|
38
|
+
this.param = param;
|
|
39
|
+
this.template = template;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Thrown by `PlayerActor.send()` when the event argument is not a plain object.
|
|
44
|
+
*
|
|
45
|
+
* `PlayEvent` requires `{ type: string, ...fields }`. Passing `null`, `undefined`,
|
|
46
|
+
* a string, or any other non-object value is a programmer error.
|
|
47
|
+
*
|
|
48
|
+
* The offending value is attached as the `detail` readonly class field for debugging.
|
|
49
|
+
* TypeScript consumers can access `err.detail` directly without any unsafe cast.
|
|
50
|
+
*
|
|
51
|
+
* **Error code:** `PLAY_INVALID_EVENT`
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import { InvalidEventError } from "@xmachines/play-xstate/errors";
|
|
56
|
+
*
|
|
57
|
+
* try {
|
|
58
|
+
* actor.send(null as any);
|
|
59
|
+
* } catch (err) {
|
|
60
|
+
* if (err instanceof InvalidEventError) {
|
|
61
|
+
* // err.detail is typed as `unknown` — no cast needed
|
|
62
|
+
* console.error("Invalid event passed to actor.send():", err.detail);
|
|
63
|
+
* }
|
|
64
|
+
* }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export class InvalidEventError extends PlayError {
|
|
68
|
+
detail;
|
|
69
|
+
constructor(detail) {
|
|
70
|
+
super("PlayerActor", "PLAY_INVALID_EVENT", "PlayerActor.send() received a non-object event.");
|
|
71
|
+
this.name = "InvalidEventError";
|
|
72
|
+
// Attach the invalid value for debugging without it appearing in the message
|
|
73
|
+
Object.defineProperty(this, "detail", { value: detail, enumerable: true });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,OAAO,sBAAuB,SAAQ,SAAS;IACpD,0EAA0E;IACjE,KAAK,CAAS;IAEvB,0FAA0F;IACjF,QAAQ,CAAS;IAE1B,YAAY,KAAa,EAAE,QAAgB;QAC1C,KAAK,CACJ,eAAe,EACf,0BAA0B,EAC1B,oBAAoB,KAAK,8BAA8B,QAAQ,iCAAiC,CAChG,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC1B,CAAC;CACD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,OAAO,iBAAkB,SAAQ,SAAS;IACtC,MAAM,CAAU;IAEzB,YAAY,MAAe;QAC1B,KAAK,CACJ,aAAa,EACb,oBAAoB,EACpB,iDAAiD,CACjD,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,6EAA6E;QAC7E,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5E,CAAC;CACD"}
|
package/dist/guards/compose.d.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
|
+
import type { GuardPredicate } from "xstate";
|
|
1
2
|
import type { Guard, GuardArray } from "./types.js";
|
|
3
|
+
import type { MachineContext, EventObject, ParameterizedObject } from "xstate";
|
|
4
|
+
/**
|
|
5
|
+
* Narrowest public return type for guard composition helpers.
|
|
6
|
+
*
|
|
7
|
+
* `GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>` is the
|
|
8
|
+
* widest-compatible concrete XState guard type that does not use `any`.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>;
|
|
2
13
|
/**
|
|
3
14
|
* Compose guards with AND logic using XState's and() helper
|
|
4
15
|
*
|
|
@@ -54,7 +65,7 @@ import type { Guard, GuardArray } from "./types.js";
|
|
|
54
65
|
* @see {@link composeGuardsOr} for OR composition
|
|
55
66
|
* @see {@link negateGuard} for NOT logic
|
|
56
67
|
*/
|
|
57
|
-
export declare const composeGuards: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) =>
|
|
68
|
+
export declare const composeGuards: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
|
|
58
69
|
/**
|
|
59
70
|
* Compose guards with OR logic using XState's or() helper
|
|
60
71
|
*
|
|
@@ -95,7 +106,7 @@ export declare const composeGuards: <TContext = any, TEvent = any>(guards: Guard
|
|
|
95
106
|
* @see {@link composeGuards} for AND composition
|
|
96
107
|
* @see {@link negateGuard} for NOT logic
|
|
97
108
|
*/
|
|
98
|
-
export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) =>
|
|
109
|
+
export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
|
|
99
110
|
/**
|
|
100
111
|
* Negate a guard using XState's not() helper
|
|
101
112
|
*
|
|
@@ -132,5 +143,5 @@ export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: Gua
|
|
|
132
143
|
* @see {@link composeGuards} for AND composition
|
|
133
144
|
* @see {@link composeGuardsOr} for OR composition
|
|
134
145
|
*/
|
|
135
|
-
export declare const negateGuard: <TContext = any, TEvent = any>(guard: Guard<TContext, TEvent> | string) =>
|
|
146
|
+
export declare const negateGuard: <TContext = any, TEvent = any>(guard: Guard<TContext, TEvent> | string) => ComposedGuard;
|
|
136
147
|
//# sourceMappingURL=compose.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,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;AAE/E;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,CACzC,cAAc,EACd,WAAW,EACX,OAAO,EACP,mBAAmB,CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACzD,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAqBF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,eAAO,MAAM,eAAe,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAC3D,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAmBF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,eAAO,MAAM,WAAW,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACvD,OAAO,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,KACrC,aAOF,CAAC"}
|
package/dist/guards/compose.js
CHANGED
|
@@ -54,15 +54,25 @@ import { and, or, not } from "xstate";
|
|
|
54
54
|
* @see {@link composeGuardsOr} for OR composition
|
|
55
55
|
* @see {@link negateGuard} for NOT logic
|
|
56
56
|
*/
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
57
58
|
export const composeGuards = (guards) => {
|
|
58
59
|
if (guards.length === 0) {
|
|
59
60
|
throw new Error("composeGuards requires at least one guard");
|
|
60
61
|
}
|
|
61
62
|
if (guards.length === 1) {
|
|
63
|
+
// Single guard passthrough — cast through unknown because our Guard<TContext, TEvent>
|
|
64
|
+
// does not structurally match ComposedGuard at compile time (generic event mismatch).
|
|
65
|
+
// At runtime both are plain function objects with identical shape.
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
62
67
|
return guards[0];
|
|
63
68
|
}
|
|
64
69
|
// Use XState's built-in and() for type inference and serialization
|
|
65
70
|
// Per RESEARCH.md: Don't hand-roll guard composition
|
|
71
|
+
// XState 5.28.0: and() requires `readonly [...tuple]` but our GuardArray is a mutable array.
|
|
72
|
+
// We cast through unknown to express the narrowest possible type boundary rather than
|
|
73
|
+
// escaping to `any`. The runtime value is identical.
|
|
74
|
+
// Track XState typing improvements: https://github.com/statelyai/xstate/issues
|
|
75
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
66
76
|
return and(guards);
|
|
67
77
|
};
|
|
68
78
|
/**
|
|
@@ -105,13 +115,23 @@ export const composeGuards = (guards) => {
|
|
|
105
115
|
* @see {@link composeGuards} for AND composition
|
|
106
116
|
* @see {@link negateGuard} for NOT logic
|
|
107
117
|
*/
|
|
118
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
108
119
|
export const composeGuardsOr = (guards) => {
|
|
109
120
|
if (guards.length === 0) {
|
|
110
121
|
throw new Error("composeGuardsOr requires at least one guard");
|
|
111
122
|
}
|
|
112
123
|
if (guards.length === 1) {
|
|
124
|
+
// Single guard passthrough — cast through unknown because our Guard<TContext, TEvent>
|
|
125
|
+
// does not structurally match ComposedGuard at compile time (generic event mismatch).
|
|
126
|
+
// At runtime both are plain function objects with identical shape.
|
|
127
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
128
|
return guards[0];
|
|
114
129
|
}
|
|
130
|
+
// XState 5.28.0: or() requires `readonly [...tuple]` but our GuardArray is a mutable array.
|
|
131
|
+
// We cast through unknown to express the narrowest possible type boundary rather than
|
|
132
|
+
// escaping to `any`. The runtime value is identical.
|
|
133
|
+
// Track XState typing improvements: https://github.com/statelyai/xstate/issues
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
115
135
|
return or(guards);
|
|
116
136
|
};
|
|
117
137
|
/**
|
|
@@ -150,7 +170,13 @@ export const composeGuardsOr = (guards) => {
|
|
|
150
170
|
* @see {@link composeGuards} for AND composition
|
|
151
171
|
* @see {@link composeGuardsOr} for OR composition
|
|
152
172
|
*/
|
|
173
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
153
174
|
export const negateGuard = (guard) => {
|
|
175
|
+
// XState 5.28.0: not() requires a specific SingleGuardArg shape, not our Guard type.
|
|
176
|
+
// We cast through unknown to express the narrowest possible type boundary rather than
|
|
177
|
+
// escaping to `any`. The runtime value is identical.
|
|
178
|
+
// Track XState typing improvements: https://github.com/statelyai/xstate/issues
|
|
179
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
154
180
|
return not(guard);
|
|
155
181
|
};
|
|
156
182
|
//# 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;
|
|
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;AAoBtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,aAAa,GAAG,CAC5B,MAAoC,EACpB,EAAE;IAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,sFAAsF;QACtF,sFAAsF;QACtF,mEAAmE;QACnE,8DAA8D;QAC9D,OAAO,MAAM,CAAC,CAAC,CAA6B,CAAC;IAC9C,CAAC;IAED,mEAAmE;IACnE,qDAAqD;IACrD,6FAA6F;IAC7F,sFAAsF;IACtF,qDAAqD;IACrD,+EAA+E;IAC/E,8DAA8D;IAC9D,OAAO,GAAG,CAAC,MAA8C,CAAC,CAAC;AAC5D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAG,CAC9B,MAAoC,EACpB,EAAE;IAClB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,sFAAsF;QACtF,sFAAsF;QACtF,mEAAmE;QACnE,8DAA8D;QAC9D,OAAO,MAAM,CAAC,CAAC,CAA6B,CAAC;IAC9C,CAAC;IAED,4FAA4F;IAC5F,sFAAsF;IACtF,qDAAqD;IACrD,+EAA+E;IAC/E,8DAA8D;IAC9D,OAAO,EAAE,CAAC,MAA6C,CAAC,CAAC;AAC1D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAC1B,KAAuC,EACvB,EAAE;IAClB,qFAAqF;IACrF,sFAAsF;IACtF,qDAAqD;IACrD,+EAA+E;IAC/E,8DAA8D;IAC9D,OAAO,GAAG,CAAC,KAA6C,CAAC,CAAC;AAC3D,CAAC,CAAC"}
|
package/dist/guards/helpers.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Guard } from "./types.js";
|
|
2
|
+
import type { PlayEvent } from "@xmachines/play";
|
|
2
3
|
/**
|
|
3
4
|
* Check if context has a truthy value at path
|
|
4
5
|
*
|
|
@@ -17,7 +18,7 @@ import type { Guard } from "./types.js";
|
|
|
17
18
|
* @param path - Dot-separated path to context property
|
|
18
19
|
* @returns Guard predicate checking if property is truthy
|
|
19
20
|
*/
|
|
20
|
-
export declare const hasContext: <TContext =
|
|
21
|
+
export declare const hasContext: <TContext = Record<string, unknown>>(path: string) => Guard<TContext, PlayEvent>;
|
|
21
22
|
/**
|
|
22
23
|
* Check if event type matches expected type
|
|
23
24
|
*
|
|
@@ -37,24 +38,19 @@ export declare const hasContext: <TContext = any>(path: string) => Guard<TContex
|
|
|
37
38
|
* @param eventType - Expected event type
|
|
38
39
|
* @returns Guard predicate checking event type
|
|
39
40
|
*/
|
|
40
|
-
export declare const eventMatches: <TEvent extends
|
|
41
|
-
type: string;
|
|
42
|
-
} = any>(eventType: string) => Guard<any, TEvent>;
|
|
41
|
+
export declare const eventMatches: <TEvent extends PlayEvent = PlayEvent>(eventType: string) => Guard<unknown, TEvent>;
|
|
43
42
|
/**
|
|
44
|
-
* Check if
|
|
43
|
+
* Check if a context field matches an expected value.
|
|
45
44
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* isDashboard: stateMatches('authenticated.dashboard')
|
|
52
|
-
* }
|
|
53
|
-
* });
|
|
54
|
-
* ```
|
|
45
|
+
* - Accepts an explicit dot-separated field path (e.g. `"user.role"`)
|
|
46
|
+
* - Uses strict equality for primitives, deep structural equality for objects
|
|
47
|
+
* - Does NOT use substring matching — `"a"` will not match `"active"`
|
|
48
|
+
*
|
|
49
|
+
* For XState state-node matching, use the built-in `in:` guard syntax instead.
|
|
55
50
|
*
|
|
56
|
-
* @param
|
|
57
|
-
* @
|
|
51
|
+
* @param fieldPath - Dot-separated path to context property (e.g., "status", "user.role")
|
|
52
|
+
* @param expectedValue - Value to compare against (string or object)
|
|
53
|
+
* @returns Guard predicate checking if context field matches
|
|
58
54
|
*/
|
|
59
|
-
export declare const
|
|
55
|
+
export declare const contextFieldMatches: <TContext = Record<string, unknown>>(fieldPath: string, expectedValue: unknown) => Guard<TContext, PlayEvent>;
|
|
60
56
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/guards/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/guards/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,GACrB,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,MAAM,KAAG,KAAK,CAAC,QAAQ,EAAE,SAAS,CAI5E,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,SAAS,SAAS,GAAG,SAAS,EAAE,WAAW,MAAM,KAAG,KAAK,CAAC,OAAO,EAAE,MAAM,CAG/E,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,WAAW,MAAM,EACjB,eAAe,OAAO,KACpB,KAAK,CAAC,QAAQ,EAAE,SAAS,CAa3B,CAAC"}
|
package/dist/guards/helpers.js
CHANGED
|
@@ -43,34 +43,29 @@ export const eventMatches = (eventType) => ({ event }) => {
|
|
|
43
43
|
return event.type === eventType;
|
|
44
44
|
};
|
|
45
45
|
/**
|
|
46
|
-
* Check if
|
|
46
|
+
* Check if a context field matches an expected value.
|
|
47
47
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* isDashboard: stateMatches('authenticated.dashboard')
|
|
54
|
-
* }
|
|
55
|
-
* });
|
|
56
|
-
* ```
|
|
48
|
+
* - Accepts an explicit dot-separated field path (e.g. `"user.role"`)
|
|
49
|
+
* - Uses strict equality for primitives, deep structural equality for objects
|
|
50
|
+
* - Does NOT use substring matching — `"a"` will not match `"active"`
|
|
51
|
+
*
|
|
52
|
+
* For XState state-node matching, use the built-in `in:` guard syntax instead.
|
|
57
53
|
*
|
|
58
|
-
* @param
|
|
59
|
-
* @
|
|
54
|
+
* @param fieldPath - Dot-separated path to context property (e.g., "status", "user.role")
|
|
55
|
+
* @param expectedValue - Value to compare against (string or object)
|
|
56
|
+
* @returns Guard predicate checking if context field matches
|
|
60
57
|
*/
|
|
61
|
-
export const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return currentState === stateValue;
|
|
58
|
+
export const contextFieldMatches = (fieldPath, expectedValue) => ({ context }) => {
|
|
59
|
+
const actual = getNestedValue(context, fieldPath);
|
|
60
|
+
if (actual === expectedValue)
|
|
61
|
+
return true;
|
|
62
|
+
if (typeof actual === "object" &&
|
|
63
|
+
typeof expectedValue === "object" &&
|
|
64
|
+
actual !== null &&
|
|
65
|
+
expectedValue !== null) {
|
|
66
|
+
return JSON.stringify(actual) === JSON.stringify(expectedValue);
|
|
71
67
|
}
|
|
72
|
-
|
|
73
|
-
return JSON.stringify(currentState).includes(stateValue);
|
|
68
|
+
return false;
|
|
74
69
|
};
|
|
75
70
|
/**
|
|
76
71
|
* Get nested value from object using dot-separated path
|
|
@@ -81,7 +76,7 @@ const getNestedValue = (obj, path) => {
|
|
|
81
76
|
const keys = path.split(".");
|
|
82
77
|
let value = obj;
|
|
83
78
|
for (const key of keys) {
|
|
84
|
-
if (value === null || value === undefined) {
|
|
79
|
+
if (value === null || value === undefined || typeof value !== "object") {
|
|
85
80
|
return undefined;
|
|
86
81
|
}
|
|
87
82
|
value = value[key];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/guards/helpers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/guards/helpers.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,UAAU,GACtB,CAAqC,IAAY,EAA8B,EAAE,CACjF,CAAC,EAAE,OAAO,EAAyB,EAAE,EAAE;IACtC,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5C,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;AAC9D,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,YAAY,GACxB,CAAuC,SAAiB,EAA0B,EAAE,CACpF,CAAC,EAAE,KAAK,EAAqB,EAAE,EAAE;IAChC,OAAO,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;AACjC,CAAC,CAAC;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAC/B,CACC,SAAiB,EACjB,aAAsB,EACO,EAAE,CAChC,CAAC,EAAE,OAAO,EAAyB,EAAE,EAAE;IACtC,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAClD,IAAI,MAAM,KAAK,aAAa;QAAE,OAAO,IAAI,CAAC;IAC1C,IACC,OAAO,MAAM,KAAK,QAAQ;QAC1B,OAAO,aAAa,KAAK,QAAQ;QACjC,MAAM,KAAK,IAAI;QACf,aAAa,KAAK,IAAI,EACrB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,cAAc,GAAG,CAAC,GAAY,EAAE,IAAY,EAAW,EAAE;IAC9D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,KAAK,GAAG,GAAG,CAAC;IAEhB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxE,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,KAAK,GAAI,KAAiC,CAAC,GAAG,CAAC,CAAC;IACjD,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC,CAAC"}
|
package/dist/guards/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
9
|
export { composeGuards, composeGuardsOr, negateGuard } from "./compose.js";
|
|
10
|
-
export {
|
|
10
|
+
export type { ComposedGuard } from "./compose.js";
|
|
11
|
+
export { hasContext, eventMatches, contextFieldMatches } from "./helpers.js";
|
|
11
12
|
export type { Guard, GuardArray } from "./types.js";
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guards/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guards/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC7E,YAAY,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/guards/index.js
CHANGED
|
@@ -7,5 +7,5 @@
|
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
9
|
export { composeGuards, composeGuardsOr, negateGuard } from "./compose.js";
|
|
10
|
-
export { hasContext, eventMatches,
|
|
10
|
+
export { hasContext, eventMatches, contextFieldMatches } from "./helpers.js";
|
|
11
11
|
//# sourceMappingURL=index.js.map
|
package/dist/guards/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/guards/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/guards/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3E,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/guards/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PlayEvent } from "@xmachines/play";
|
|
1
2
|
/**
|
|
2
3
|
* Standard XState guard function signature
|
|
3
4
|
*
|
|
@@ -8,7 +9,7 @@
|
|
|
8
9
|
* @param args.event - Event that triggered the guard evaluation
|
|
9
10
|
* @returns boolean indicating if guard passes
|
|
10
11
|
*/
|
|
11
|
-
export type Guard<TContext =
|
|
12
|
+
export type Guard<TContext = Record<string, unknown>, TEvent = PlayEvent> = (args: {
|
|
12
13
|
context: TContext;
|
|
13
14
|
event: TEvent;
|
|
14
15
|
}) => boolean;
|
|
@@ -17,5 +18,5 @@ export type Guard<TContext = any, TEvent = any> = (args: {
|
|
|
17
18
|
*
|
|
18
19
|
* Per CONTEXT.md: Array means AND - all guards must pass
|
|
19
20
|
*/
|
|
20
|
-
export type GuardArray<TContext =
|
|
21
|
+
export type GuardArray<TContext = Record<string, unknown>, TEvent = PlayEvent> = Array<Guard<TContext, TEvent>> | Array<string>;
|
|
21
22
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/guards/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,KAAK,CAAC,QAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/guards/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;;;;;GASG;AACH,MAAM,MAAM,KAAK,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,IAAI,CAAC,IAAI,EAAE;IAClF,OAAO,EAAE,QAAQ,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACd,KAAK,OAAO,CAAC;AAEd;;;;GAIG;AACH,MAAM,MAAM,UAAU,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,IAC1E,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,GAC9B,KAAK,CAAC,MAAM,CAAC,CAAC"}
|