@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
package/dist/errors.js
CHANGED
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { PlayError } from "@xmachines/play";
|
|
2
|
+
/**
|
|
3
|
+
* Stringify a thrown value without trusting it: `String()` itself throws for
|
|
4
|
+
* a null-prototype object or a value whose `toString`/`Symbol.toPrimitive`
|
|
5
|
+
* throw, and this runs inside the error path — a second throw here would
|
|
6
|
+
* replace the machine's real failure with a `TypeError` and bypass `onError`.
|
|
7
|
+
*/
|
|
8
|
+
const safeString = (value) => {
|
|
9
|
+
try {
|
|
10
|
+
return String(value);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
try {
|
|
14
|
+
return Object.prototype.toString.call(value);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
// A revoked Proxy throws even on brand inspection.
|
|
18
|
+
return "[unrepresentable value]";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
2
22
|
/**
|
|
3
23
|
* Thrown by `buildRouteUrl()` when a required route parameter is absent from the
|
|
4
24
|
* actor's context.
|
|
@@ -8,16 +28,17 @@ import { PlayError } from "@xmachines/play";
|
|
|
8
28
|
*
|
|
9
29
|
* **Error code:** `PLAY_XSTATE_ROUTE_PARAM_MISSING`
|
|
10
30
|
*
|
|
31
|
+
* Note: `actor.currentRoute.get()` never surfaces this error — route
|
|
32
|
+
* derivation catches it and returns `null` for the transient mid-transition
|
|
33
|
+
* case. It only escapes direct `buildRouteUrl()` calls.
|
|
34
|
+
*
|
|
11
35
|
* @example
|
|
12
36
|
* ```typescript
|
|
37
|
+
* import { buildRouteUrl } from "@xmachines/play-xstate";
|
|
13
38
|
* import { MissingRouteParamError } from "@xmachines/play-xstate/errors";
|
|
14
39
|
*
|
|
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
40
|
* try {
|
|
20
|
-
*
|
|
41
|
+
* buildRouteUrl("/profile/:userId", { params: {}, query: {} });
|
|
21
42
|
* } catch (err) {
|
|
22
43
|
* if (err instanceof MissingRouteParamError) {
|
|
23
44
|
* console.error(
|
|
@@ -40,36 +61,18 @@ export class MissingRouteParamError extends PlayError {
|
|
|
40
61
|
}
|
|
41
62
|
}
|
|
42
63
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
64
|
+
* @deprecated Never thrown any more. `buildRouteUrl` treats a missing `query`
|
|
65
|
+
* field as `query: {}` — the generated `play.route` transitions assign
|
|
66
|
+
* `query` on every navigation, so the loss this error guarded against cannot
|
|
67
|
+
* occur through route derivation. Machines that handle `play.route` by hand
|
|
68
|
+
* and want query forwarding must assign `event.query` to context themselves.
|
|
69
|
+
* Kept exported so existing `instanceof` handlers keep compiling; remove them
|
|
70
|
+
* at leisure.
|
|
49
71
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* If using `formatPlayRouteTransitions`, the field is assigned automatically on each
|
|
53
|
-
* `play.route` event — but the machine's initial context must still declare it.
|
|
72
|
+
* Formerly thrown by `buildRouteUrl()` when the context had a `params` field
|
|
73
|
+
* (a routing-aware machine context) but no `query` field.
|
|
54
74
|
*
|
|
55
75
|
* **Error code:** `PLAY_XSTATE_MISSING_QUERY_CONTEXT`
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```typescript
|
|
59
|
-
* import { MissingQueryContextError } from "@xmachines/play-xstate/errors";
|
|
60
|
-
*
|
|
61
|
-
* try {
|
|
62
|
-
* // params present but no query field — throws
|
|
63
|
-
* buildRouteUrl("/profile/:userId", { params: { userId: "42" } });
|
|
64
|
-
* } catch (err) {
|
|
65
|
-
* if (err instanceof MissingQueryContextError) {
|
|
66
|
-
* console.error("Machine context missing query field");
|
|
67
|
-
* }
|
|
68
|
-
* }
|
|
69
|
-
*
|
|
70
|
-
* // Correct — both params and query declared
|
|
71
|
-
* buildRouteUrl("/profile/:userId", { params: { userId: "42" }, query: {} });
|
|
72
|
-
* ```
|
|
73
76
|
*/
|
|
74
77
|
export class MissingQueryContextError extends PlayError {
|
|
75
78
|
constructor() {
|
|
@@ -165,51 +168,6 @@ export class EmptyGuardArrayError extends PlayError {
|
|
|
165
168
|
this.combinator = combinator;
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
|
-
/**
|
|
169
|
-
* Thrown when a composed guard cannot resolve a string guard name at call time.
|
|
170
|
-
*
|
|
171
|
-
* String names in `composeGuards`/`composeGuardsOr`/`negateGuard` resolve
|
|
172
|
-
* against `args.guards` — the named guards from `setup({ guards })` that
|
|
173
|
-
* XState v6 provides to transition functions, `always`, entry/exit actions
|
|
174
|
-
* (since 6.0.0-alpha.20), and function-form route resolvers. Resolution fails
|
|
175
|
-
* when the name was never declared or when the composed guard is called
|
|
176
|
-
* without transition arguments.
|
|
177
|
-
*
|
|
178
|
-
* **Error code:** `PLAY_XSTATE_UNRESOLVABLE_GUARD_NAME`
|
|
179
|
-
*/
|
|
180
|
-
export class UnresolvableGuardNameError extends PlayError {
|
|
181
|
-
/** The guard name that could not be resolved. */
|
|
182
|
-
guardName;
|
|
183
|
-
constructor(guardName, origin) {
|
|
184
|
-
super(origin, "PLAY_XSTATE_UNRESOLVABLE_GUARD_NAME", `Guard "${guardName}" is not a function. Either the name was never declared ` +
|
|
185
|
-
`in setup({ guards }) or the composed guard was called without ` +
|
|
186
|
-
`transition arguments.`);
|
|
187
|
-
this.name = "UnresolvableGuardNameError";
|
|
188
|
-
this.guardName = guardName;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Thrown when a composed guard evaluates an entry that is neither a predicate
|
|
193
|
-
* function nor a guard name — typically `null`/`undefined` from a typo'd
|
|
194
|
-
* import or an optional lookup.
|
|
195
|
-
*
|
|
196
|
-
* XState v5 failed loudly when evaluating such entries; silently treating them
|
|
197
|
-
* as never-passing would turn `negateGuard(undefined)` into an always-allow.
|
|
198
|
-
* Composition stays lazy (no throw at compose time); evaluation throws.
|
|
199
|
-
*
|
|
200
|
-
* **Error code:** `PLAY_XSTATE_INVALID_GUARD_ENTRY`
|
|
201
|
-
*/
|
|
202
|
-
export class InvalidGuardEntryError extends PlayError {
|
|
203
|
-
/** `typeof` of the invalid entry (e.g. `"undefined"`, `"object"` for null). */
|
|
204
|
-
entryType;
|
|
205
|
-
constructor(entryType, origin) {
|
|
206
|
-
super(origin, "PLAY_XSTATE_INVALID_GUARD_ENTRY", `Guard entry of type "${entryType}" is neither a predicate function nor a ` +
|
|
207
|
-
`guard name. Check for typo'd imports or optional lookups that resolved ` +
|
|
208
|
-
`to null/undefined.`);
|
|
209
|
-
this.name = "InvalidGuardEntryError";
|
|
210
|
-
this.entryType = entryType;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
171
|
/**
|
|
214
172
|
* Thrown by `PlayerActor.send()` when the event argument is not a plain object.
|
|
215
173
|
*
|
|
@@ -244,4 +202,38 @@ export class InvalidEventError extends PlayError {
|
|
|
244
202
|
this.detail = detail;
|
|
245
203
|
}
|
|
246
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Passed to `PlayerOptions.onError` when the actor failed with a value that is
|
|
207
|
+
* not an `Error` — e.g. a machine action ran `throw { code: 42 }`.
|
|
208
|
+
*
|
|
209
|
+
* An actor error that *is* an `Error` reaches `onError` untouched, keeping the
|
|
210
|
+
* identity the machine gave it. Only this case constructs a new error, so it
|
|
211
|
+
* carries a matchable code instead of a `String(value)` message such as
|
|
212
|
+
* `"[object Object]"`. The thrown value is preserved on `cause`.
|
|
213
|
+
*
|
|
214
|
+
* **Error code:** `PLAY_XSTATE_NON_ERROR_THROWN`
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```typescript
|
|
218
|
+
* import { ActorThrewNonErrorError } from "@xmachines/play-xstate/errors";
|
|
219
|
+
*
|
|
220
|
+
* definePlayer({
|
|
221
|
+
* machine,
|
|
222
|
+
* options: {
|
|
223
|
+
* onError: (actor, err) => {
|
|
224
|
+
* if (err instanceof ActorThrewNonErrorError) {
|
|
225
|
+
* // err.cause is the value the machine actually threw
|
|
226
|
+
* console.error("Machine threw a non-Error:", err.cause);
|
|
227
|
+
* }
|
|
228
|
+
* },
|
|
229
|
+
* },
|
|
230
|
+
* });
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export class ActorThrewNonErrorError extends PlayError {
|
|
234
|
+
constructor(value) {
|
|
235
|
+
super("PlayerActor", "PLAY_XSTATE_NON_ERROR_THROWN", `PlayerActor failed with a non-Error value: ${safeString(value)}.`, { cause: value });
|
|
236
|
+
this.name = "ActorThrewNonErrorError";
|
|
237
|
+
}
|
|
238
|
+
}
|
|
247
239
|
//# sourceMappingURL=errors.js.map
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
|
package/dist/guards/compose.d.ts
CHANGED
|
@@ -1,50 +1,35 @@
|
|
|
1
|
+
import type { GuardPredicate } from "xstate";
|
|
1
2
|
import type { Guard, GuardArray } from "./types.js";
|
|
3
|
+
import type { MachineContext, EventObject, ParameterizedObject } from "xstate";
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
5
|
+
* Narrowest public return type for guard composition helpers.
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* composed guard is therefore just another predicate with the same shape as
|
|
8
|
-
* {@link Guard}, callable anywhere transition args are available.
|
|
9
|
-
*
|
|
10
|
-
* String guard names are resolved against `args.guards` (the named guards
|
|
11
|
-
* declared in `setup({ guards })`, which XState v6 passes to every transition
|
|
12
|
-
* function). Resolving a name outside a transition function — or a name that
|
|
13
|
-
* was never declared — throws `UnresolvableGuardNameError` immediately.
|
|
14
|
-
*
|
|
15
|
-
* String names work in `on` transitions, `always`, entry/exit actions (since
|
|
16
|
-
* xstate 6.0.0-alpha.20 populates `guards` there), and function-form route
|
|
17
|
-
* resolvers.
|
|
7
|
+
* `GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>` is the
|
|
8
|
+
* widest-compatible concrete XState guard type that does not use `any`.
|
|
18
9
|
*
|
|
19
10
|
* @public
|
|
11
|
+
* @deprecated The guard utilities will be removed in the next major — use
|
|
12
|
+
* XState's own combinator types directly.
|
|
20
13
|
*/
|
|
21
|
-
export type ComposedGuard =
|
|
14
|
+
export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>;
|
|
22
15
|
/**
|
|
23
|
-
* Compose guards with AND logic
|
|
16
|
+
* Compose guards with AND logic using XState's and() helper
|
|
24
17
|
*
|
|
25
18
|
* Combines multiple guard predicates using AND semantics—all guards must pass for
|
|
26
|
-
* the composition to succeed.
|
|
19
|
+
* the composition to succeed. Uses XState's built-in `and()` helper to ensure proper
|
|
20
|
+
* type inference and machine serialization.
|
|
27
21
|
*
|
|
28
22
|
* **Architectural Context:** Supports **Actor Authority (INV-01)** by enabling
|
|
29
23
|
* declarative guard composition in state machine transitions. Guards enforce business
|
|
30
24
|
* logic rules that determine whether navigation or actions are valid.
|
|
31
25
|
*
|
|
32
|
-
*
|
|
33
|
-
* transition function and return early to block the transition:
|
|
34
|
-
*
|
|
35
|
-
* @typeParam TContext - State machine context type (defaults to `any` so the
|
|
36
|
-
* documented inline-predicate examples compile without annotations)
|
|
37
|
-
* @typeParam TEvent - Event type
|
|
38
|
-
*
|
|
39
|
-
* @typeParam TContext - State machine context type (defaults to `any` so the
|
|
40
|
-
* documented inline-predicate examples compile without annotations)
|
|
26
|
+
* @typeParam TContext - State machine context type
|
|
41
27
|
* @typeParam TEvent - Event type
|
|
42
28
|
*
|
|
43
|
-
* @param guards - Array of guard predicates or guard names (string references
|
|
44
|
-
*
|
|
45
|
-
* @returns Predicate returning `true` only when every guard passes
|
|
29
|
+
* @param guards - Array of guard predicates or guard names (string references)
|
|
30
|
+
* @returns XState and() guard composition
|
|
46
31
|
*
|
|
47
|
-
* @throws {
|
|
32
|
+
* @throws {Error} If guards array is empty
|
|
48
33
|
*
|
|
49
34
|
* @example
|
|
50
35
|
* AND composition with named guards
|
|
@@ -52,8 +37,6 @@ export type ComposedGuard = (args: unknown) => boolean;
|
|
|
52
37
|
* import { setup } from "xstate";
|
|
53
38
|
* import { composeGuards } from "@xmachines/play-xstate";
|
|
54
39
|
*
|
|
55
|
-
* const canAccessAdmin = composeGuards(['isLoggedIn', 'hasPermission']);
|
|
56
|
-
*
|
|
57
40
|
* const machine = setup({
|
|
58
41
|
* guards: {
|
|
59
42
|
* isLoggedIn: ({ context }) => !!context.userId,
|
|
@@ -61,9 +44,10 @@ export type ComposedGuard = (args: unknown) => boolean;
|
|
|
61
44
|
* }
|
|
62
45
|
* }).createMachine({
|
|
63
46
|
* on: {
|
|
64
|
-
* accessAdmin:
|
|
65
|
-
*
|
|
66
|
-
*
|
|
47
|
+
* accessAdmin: {
|
|
48
|
+
* // Both guards must pass
|
|
49
|
+
* guard: composeGuards(['isLoggedIn', 'hasPermission']),
|
|
50
|
+
* target: 'adminPanel'
|
|
67
51
|
* }
|
|
68
52
|
* }
|
|
69
53
|
* });
|
|
@@ -74,27 +58,32 @@ export type ComposedGuard = (args: unknown) => boolean;
|
|
|
74
58
|
* ```typescript
|
|
75
59
|
* import { composeGuards } from "@xmachines/play-xstate";
|
|
76
60
|
*
|
|
77
|
-
*
|
|
61
|
+
* guard: composeGuards([
|
|
78
62
|
* ({ context }) => context.age >= 18,
|
|
79
63
|
* ({ context }) => context.verified
|
|
80
|
-
* ])
|
|
64
|
+
* ])
|
|
81
65
|
* ```
|
|
82
66
|
*
|
|
83
67
|
* @see {@link composeGuardsOr} for OR composition
|
|
84
68
|
* @see {@link negateGuard} for NOT logic
|
|
69
|
+
* @deprecated Use XState's own `and()`/`or()`/`not()` directly — this helper does not
|
|
70
|
+
* compose with `setup()`-typed guard slots and will be removed in the next major.
|
|
85
71
|
*/
|
|
86
72
|
export declare const composeGuards: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
|
|
87
73
|
/**
|
|
88
|
-
* Compose guards with OR logic
|
|
74
|
+
* Compose guards with OR logic using XState's or() helper
|
|
89
75
|
*
|
|
90
76
|
* Combines multiple guard predicates using OR semantics—at least one guard must pass
|
|
91
|
-
* for the composition to succeed.
|
|
77
|
+
* for the composition to succeed. Uses XState's built-in `or()` helper for proper
|
|
78
|
+
* type inference.
|
|
79
|
+
*
|
|
80
|
+
* @typeParam TContext - State machine context type
|
|
81
|
+
* @typeParam TEvent - Event type
|
|
92
82
|
*
|
|
93
|
-
* @param guards - Array of guard predicates or guard names
|
|
94
|
-
*
|
|
95
|
-
* @returns Predicate returning `true` when any guard passes
|
|
83
|
+
* @param guards - Array of guard predicates or guard names
|
|
84
|
+
* @returns XState or() guard composition
|
|
96
85
|
*
|
|
97
|
-
* @throws {
|
|
86
|
+
* @throws {Error} If guards array is empty
|
|
98
87
|
*
|
|
99
88
|
* @example
|
|
100
89
|
* OR composition with named guards
|
|
@@ -102,8 +91,6 @@ export declare const composeGuards: <TContext = any, TEvent = any>(guards: Guard
|
|
|
102
91
|
* import { setup } from "xstate";
|
|
103
92
|
* import { composeGuardsOr } from "@xmachines/play-xstate";
|
|
104
93
|
*
|
|
105
|
-
* const canDelete = composeGuardsOr(['isOwner', 'isAdmin']);
|
|
106
|
-
*
|
|
107
94
|
* const machine = setup({
|
|
108
95
|
* guards: {
|
|
109
96
|
* isOwner: ({ context }) => context.role === 'owner',
|
|
@@ -111,9 +98,10 @@ export declare const composeGuards: <TContext = any, TEvent = any>(guards: Guard
|
|
|
111
98
|
* }
|
|
112
99
|
* }).createMachine({
|
|
113
100
|
* on: {
|
|
114
|
-
* deleteResource:
|
|
115
|
-
*
|
|
116
|
-
*
|
|
101
|
+
* deleteResource: {
|
|
102
|
+
* // Either guard can pass
|
|
103
|
+
* guard: composeGuardsOr(['isOwner', 'isAdmin']),
|
|
104
|
+
* actions: 'delete'
|
|
117
105
|
* }
|
|
118
106
|
* }
|
|
119
107
|
* });
|
|
@@ -121,20 +109,21 @@ export declare const composeGuards: <TContext = any, TEvent = any>(guards: Guard
|
|
|
121
109
|
*
|
|
122
110
|
* @see {@link composeGuards} for AND composition
|
|
123
111
|
* @see {@link negateGuard} for NOT logic
|
|
112
|
+
* @deprecated Use XState's own `and()`/`or()`/`not()` directly — this helper does not
|
|
113
|
+
* compose with `setup()`-typed guard slots and will be removed in the next major.
|
|
124
114
|
*/
|
|
125
115
|
export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
|
|
126
116
|
/**
|
|
127
|
-
* Negate a guard
|
|
117
|
+
* Negate a guard using XState's not() helper
|
|
128
118
|
*
|
|
129
119
|
* Inverts a guard's result—if the guard passes, NOT fails; if guard fails, NOT passes.
|
|
120
|
+
* Uses XState's built-in `not()` helper for proper serialization.
|
|
130
121
|
*
|
|
131
|
-
* @typeParam TContext - State machine context type
|
|
132
|
-
* inline predicates compile without annotations)
|
|
122
|
+
* @typeParam TContext - State machine context type
|
|
133
123
|
* @typeParam TEvent - Event type
|
|
134
124
|
*
|
|
135
|
-
* @param guard - Guard predicate or guard name
|
|
136
|
-
*
|
|
137
|
-
* @returns Predicate returning the inverted guard result
|
|
125
|
+
* @param guard - Guard predicate or guard name to negate
|
|
126
|
+
* @returns XState not() guard negation
|
|
138
127
|
*
|
|
139
128
|
* @example
|
|
140
129
|
* NOT composition with named guard
|
|
@@ -142,17 +131,16 @@ export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: Gua
|
|
|
142
131
|
* import { setup } from "xstate";
|
|
143
132
|
* import { negateGuard } from "@xmachines/play-xstate";
|
|
144
133
|
*
|
|
145
|
-
* const isAuthenticated = negateGuard('isGuest');
|
|
146
|
-
*
|
|
147
134
|
* const machine = setup({
|
|
148
135
|
* guards: {
|
|
149
136
|
* isGuest: ({ context }) => !context.userId
|
|
150
137
|
* }
|
|
151
138
|
* }).createMachine({
|
|
152
139
|
* on: {
|
|
153
|
-
* accessDashboard:
|
|
154
|
-
* if (
|
|
155
|
-
*
|
|
140
|
+
* accessDashboard: {
|
|
141
|
+
* // Allow if NOT a guest (i.e., authenticated)
|
|
142
|
+
* guard: negateGuard('isGuest'),
|
|
143
|
+
* target: 'dashboard'
|
|
156
144
|
* }
|
|
157
145
|
* }
|
|
158
146
|
* });
|
|
@@ -160,6 +148,8 @@ export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: Gua
|
|
|
160
148
|
*
|
|
161
149
|
* @see {@link composeGuards} for AND composition
|
|
162
150
|
* @see {@link composeGuardsOr} for OR composition
|
|
151
|
+
* @deprecated Use XState's own `and()`/`or()`/`not()` directly — this helper does not
|
|
152
|
+
* compose with `setup()`-typed guard slots and will be removed in the next major.
|
|
163
153
|
*/
|
|
164
154
|
export declare const negateGuard: <TContext = any, TEvent = any>(guard: Guard<TContext, TEvent> | string) => ComposedGuard;
|
|
165
155
|
//# sourceMappingURL=compose.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"
|
|
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"}
|