@systemfsoftware/xstate 0.0.0-stage → 6.0.0-beta.65

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.
@@ -0,0 +1,146 @@
1
+ // src/constants.ts
2
+ const XSTATE_INIT = "@xstate.init";
3
+ const XSTATE_START = "@xstate.start";
4
+ const XSTATE_SPAWN = "@xstate.spawn";
5
+ const XSTATE_STOP = "@xstate.stop";
6
+ const XSTATE_TERMINATE = "@xstate.terminate";
7
+ const XSTATE_TIMER = "xstate.timer";
8
+ const XSTATE_LOGIC_EFFECT_RESOLVE = "xstate.logic.effect.resolve";
9
+ const XSTATE_LOGIC_EFFECT_REJECT = "xstate.logic.effect.reject";
10
+ const XSTATE_LOGIC_EFFECT_START = "xstate.logic.effect.start";
11
+ // src/warnSink.ts
12
+ const defaultWarn = (message) => {
13
+ console.warn(message);
14
+ };
15
+ // src/utils.ts
16
+ function mapValues(collection, iteratee) {
17
+ const result = {};
18
+ const collectionKeys = Object.keys(collection);
19
+ for (let i = 0; i < collectionKeys.length; i++) {
20
+ const key = collectionKeys[i];
21
+ if (key === void 0) continue;
22
+ const value = iteratee(collection[key], key, collection, i);
23
+ if (key === "__proto__") Object.defineProperty(result, key, {
24
+ value,
25
+ enumerable: true,
26
+ configurable: true,
27
+ writable: true
28
+ });
29
+ else result[key] = value;
30
+ }
31
+ return result;
32
+ }
33
+ function toArrayStrict(value) {
34
+ if (isArray(value)) return value;
35
+ return [value];
36
+ }
37
+ function toArray(value) {
38
+ if (value === void 0) return [];
39
+ return toArrayStrict(value);
40
+ }
41
+ function resolveOutput(mapper, context, event, self, warn, input) {
42
+ if (typeof mapper === "function") return mapper({
43
+ context,
44
+ event,
45
+ output: getEventOutput(event),
46
+ self,
47
+ input
48
+ });
49
+ return mapper;
50
+ }
51
+ function getEventOutput(event) {
52
+ if (isDoneEvent(event)) return event.output;
53
+ }
54
+ function isDoneEvent(event) {
55
+ return event.type === "xstate.done.actor" || event.type === "xstate.done.state";
56
+ }
57
+ function isArray(value) {
58
+ return Array.isArray(value);
59
+ }
60
+ function isErrorEvent(event) {
61
+ return event.type.startsWith("xstate.error.");
62
+ }
63
+ function toTransitionConfigArray(configLike) {
64
+ return toArrayStrict(configLike).map((transitionLike) => {
65
+ if (typeof transitionLike === "undefined" || typeof transitionLike === "string") return { target: transitionLike };
66
+ if (typeof transitionLike === "function") return { to: transitionLike };
67
+ return transitionLike;
68
+ });
69
+ }
70
+ function normalizeTarget(target) {
71
+ if (target === void 0 || target === "") return;
72
+ return toArray(target);
73
+ }
74
+ /** @public */
75
+ function toObserver(nextHandler, errorHandler, completionHandler) {
76
+ const isObserver = typeof nextHandler === "object";
77
+ const self = isObserver ? nextHandler : void 0;
78
+ return {
79
+ next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),
80
+ error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),
81
+ complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(self),
82
+ ...isObserver && nextHandler.passive ? { passive: true } : {}
83
+ };
84
+ }
85
+ function createInvokeId(stateNodeId, index) {
86
+ return `${index}.${stateNodeId}`;
87
+ }
88
+ /** Whether `value` looks like an actor ref (as persisted context detects them). */
89
+ function isActorRefLike(value) {
90
+ return "sessionId" in value && "send" in value && "ref" in value;
91
+ }
92
+ function resolveReferencedActor(machine, src) {
93
+ const match = src.match(/^xstate\.invoke\.(\d+)\.(.*)/);
94
+ if (!match) return machine.sources.actors[src];
95
+ const [, indexStr, nodeId] = match;
96
+ if (nodeId === void 0) throw new Error(`Invalid invoke source '${src}'.`);
97
+ const invokeConfig = machine.getStateNodeById(nodeId).config.invoke;
98
+ const configSrc = (Array.isArray(invokeConfig) ? invokeConfig[indexStr] : invokeConfig).src;
99
+ return typeof configSrc === "string" ? machine.sources.actors[configSrc] : configSrc;
100
+ }
101
+ /** @experimental */
102
+ function getAllOwnEventDescriptors(snapshot) {
103
+ return [.../* @__PURE__ */ new Set([...snapshot.nodes.flatMap((sn) => sn.ownEvents)])];
104
+ }
105
+ /** @internal Events synthesized from active transition descriptors. */
106
+ function getAllOwnEvents(snapshot) {
107
+ const events = snapshot.nodes.flatMap((stateNode) => [...stateNode.transitions.values()].flatMap((transitions) => transitions.map((transition) => {
108
+ const event = {
109
+ type: transition.eventType,
110
+ ...transition.matches
111
+ };
112
+ if ("actorId" in event && (event.type === "xstate.done.actor" || event.type === "xstate.error.actor" || event.type === "xstate.snapshot.actor" || event.type === "xstate.timeout.actor")) event["sessionId"] = snapshot.children[event["actorId"]]?.sessionId;
113
+ return event;
114
+ })));
115
+ return events.filter((event, index) => events.findIndex((candidate) => {
116
+ const keys = Object.keys(event);
117
+ return keys.length === Object.keys(candidate).length && keys.every((key) => Object.is(event[key], candidate[key]));
118
+ }) === index);
119
+ }
120
+ /**
121
+ * Checks if an event type matches an event descriptor, supporting wildcards.
122
+ * Event descriptors can be:
123
+ *
124
+ * - Exact matches: "event.type"
125
+ * - Wildcard: "*"
126
+ * - Partial matches: "event.*"
127
+ *
128
+ * @param eventType - The actual event type string
129
+ * @param descriptor - The event descriptor to match against
130
+ * @returns True if the event type matches the descriptor
131
+ */
132
+ function matchesEventDescriptor(eventType, descriptor, warn = defaultWarn) {
133
+ if (descriptor === eventType) return true;
134
+ if (descriptor === "*") return true;
135
+ if (!descriptor.endsWith(".*")) return false;
136
+ const partialEventTokens = descriptor.split(".");
137
+ const eventTokens = eventType.split(".");
138
+ for (let tokenIndex = 0; tokenIndex < partialEventTokens.length; tokenIndex++) {
139
+ const partialEventToken = partialEventTokens[tokenIndex];
140
+ const eventToken = eventTokens[tokenIndex];
141
+ if (partialEventToken === "*") return tokenIndex === partialEventTokens.length - 1;
142
+ if (partialEventToken !== eventToken) return false;
143
+ }
144
+ return true;
145
+ }
146
+ export { XSTATE_TERMINATE as C, XSTATE_STOP as S, XSTATE_LOGIC_EFFECT_REJECT as _, isActorRefLike as a, XSTATE_SPAWN as b, matchesEventDescriptor as c, resolveReferencedActor as d, toArray as f, XSTATE_INIT as g, defaultWarn as h, getEventOutput as i, normalizeTarget as l, toTransitionConfigArray as m, getAllOwnEventDescriptors as n, isErrorEvent as o, toObserver as p, getAllOwnEvents as r, mapValues as s, createInvokeId as t, resolveOutput as u, XSTATE_LOGIC_EFFECT_RESOLVE as v, XSTATE_TIMER as w, XSTATE_START as x, XSTATE_LOGIC_EFFECT_START as y };
@@ -0,0 +1,49 @@
1
+ import { f as StandardSchemaV1 } from "./base.types-DF8ZPiXj.js";
2
+ import { Gr as ActorValidationEventOrigin, Kr as ActorValidationRequest, Ur as ActorLogicValidator, Wr as ActorValidationBoundary } from "./types-B2EAwOk-.js";
3
+ declare const actorValidationErrorSymbol: unique symbol;
4
+ /** @experimental */
5
+ export type ActorValidationReason = 'invalid' | 'unknownEvent' | 'unknownEmitted' | 'transformationUnsupported' | 'asyncValidationUnsupported' | 'schemaThrew';
6
+ /** @experimental */
7
+ export interface ActorValidationErrorOptions {
8
+ reason: ActorValidationReason;
9
+ boundary: ActorValidationBoundary;
10
+ logicId?: string;
11
+ stateNodeId?: string;
12
+ eventType?: string;
13
+ eventOrigin?: ActorValidationEventOrigin;
14
+ childId?: string;
15
+ issues?: readonly StandardSchemaV1.Issue[];
16
+ cause?: unknown;
17
+ }
18
+ /**
19
+ * A structured failure produced by `standardSchemaValidator()`.
20
+ *
21
+ * @experimental
22
+ */
23
+ export declare class ActorValidationError extends Error {
24
+ readonly [actorValidationErrorSymbol] = true;
25
+ readonly reason: ActorValidationReason;
26
+ readonly boundary: ActorValidationBoundary;
27
+ readonly logicId?: string | undefined;
28
+ readonly stateNodeId?: string | undefined;
29
+ readonly eventType?: string | undefined;
30
+ readonly eventOrigin?: ActorValidationEventOrigin | undefined;
31
+ readonly childId?: string | undefined;
32
+ readonly issues?: readonly StandardSchemaV1.Issue[] | undefined;
33
+ readonly cause?: unknown;
34
+ constructor(options: ActorValidationErrorOptions);
35
+ }
36
+ /** @experimental */
37
+ export declare function isActorValidationError(value: unknown): value is ActorValidationError;
38
+ /** @experimental */
39
+ export interface StandardSchemaValidatorOptions {
40
+ unknownEvents?: 'error' | 'ignore';
41
+ unknownEmitted?: 'error' | 'ignore';
42
+ }
43
+ /**
44
+ * Creates a synchronous, assertion-only Standard Schema validator.
45
+ *
46
+ * @experimental
47
+ */
48
+ export declare function standardSchemaValidator(options?: StandardSchemaValidatorOptions): ActorLogicValidator;
49
+ export type { ActorLogicValidator, ActorValidationBoundary, ActorValidationEventOrigin, ActorValidationRequest };
@@ -0,0 +1,216 @@
1
+ import { c as matchesEventDescriptor } from "./utils-CXBxxp3Z.mjs";
2
+ // src/validation/index.ts
3
+ const actorValidationErrorSymbol = Symbol.for("xstate.actorValidationError");
4
+ /**
5
+ * A structured failure produced by `standardSchemaValidator()`.
6
+ *
7
+ * @experimental
8
+ */
9
+ var ActorValidationError = class extends Error {
10
+ [actorValidationErrorSymbol] = true;
11
+ reason;
12
+ boundary;
13
+ logicId;
14
+ stateNodeId;
15
+ eventType;
16
+ eventOrigin;
17
+ childId;
18
+ issues;
19
+ cause;
20
+ constructor(options) {
21
+ super(getMessage(options), { cause: options.cause });
22
+ this.name = "ActorValidationError";
23
+ this.reason = options.reason;
24
+ this.boundary = options.boundary;
25
+ this.logicId = options.logicId;
26
+ this.stateNodeId = options.stateNodeId;
27
+ this.eventType = options.eventType;
28
+ this.eventOrigin = options.eventOrigin;
29
+ this.childId = options.childId;
30
+ this.issues = options.issues;
31
+ this.cause = options.cause;
32
+ }
33
+ };
34
+ /** @experimental */
35
+ function isActorValidationError(value) {
36
+ return !!(value && typeof value === "object" && actorValidationErrorSymbol in value);
37
+ }
38
+ /**
39
+ * Creates a synchronous, assertion-only Standard Schema validator.
40
+ *
41
+ * @experimental
42
+ */
43
+ function standardSchemaValidator(options = {}) {
44
+ const unknownEvents = options.unknownEvents ?? "error";
45
+ const unknownEmitted = options.unknownEmitted ?? "error";
46
+ const checkTarget = (target) => {
47
+ if (!target.schema) {
48
+ if (target.boundary === "event" && unknownEvents === "error") return createError(target, "unknownEvent");
49
+ if (target.boundary === "emitted" && unknownEmitted === "error") return createError(target, "unknownEmitted");
50
+ return;
51
+ }
52
+ let result;
53
+ try {
54
+ result = target.schema["~standard"].validate(target.value);
55
+ } catch (cause) {
56
+ return createError(target, "schemaThrew", void 0, cause);
57
+ }
58
+ if (isPromiseLike(result)) {
59
+ Promise.resolve(result).catch(() => {});
60
+ return createError(target, "asyncValidationUnsupported");
61
+ }
62
+ if (result.issues) return createError(target, "invalid", result.issues);
63
+ };
64
+ const checkEvent = (logic, event, eventOrigin) => {
65
+ const schemas = getSchemas(logic);
66
+ if (event.type.startsWith("xstate.") || event.type.startsWith("@xstate.")) return;
67
+ const eventSchemas = schemas?.events;
68
+ const internalEventSchemas = schemas?.internalEvents;
69
+ const schema = findEventSchema(internalEventSchemas, event.type) ?? findEventSchema(eventSchemas, event.type);
70
+ if (!eventSchemas && !internalEventSchemas) return;
71
+ return checkTarget({
72
+ schema,
73
+ value: getPayload(event),
74
+ boundary: "event",
75
+ logicId: getLogicId(logic),
76
+ eventType: event.type,
77
+ eventOrigin
78
+ });
79
+ };
80
+ const checkEmitted = (logic, effects) => {
81
+ const schemas = getSchemas(logic);
82
+ if (!schemas?.emitted) return;
83
+ for (const effect of effects) {
84
+ if (effect.kind !== "emit") continue;
85
+ const error = checkTarget({
86
+ schema: schemas.emitted[effect.event.type],
87
+ value: getPayload(effect.event),
88
+ boundary: "emitted",
89
+ logicId: getLogicId(logic),
90
+ eventType: effect.event.type
91
+ });
92
+ if (error) return error;
93
+ }
94
+ };
95
+ const checkMachineResult = (machine, snapshot) => {
96
+ let error = checkTarget({
97
+ schema: machine.schemas?.context,
98
+ value: snapshot.context,
99
+ boundary: "context",
100
+ logicId: machine.id
101
+ });
102
+ if (error) return error;
103
+ for (const stateNode of snapshot.nodes) {
104
+ if (stateNode === machine.root) continue;
105
+ error = checkTarget({
106
+ schema: stateNode.schemas?.context,
107
+ value: snapshot.context,
108
+ boundary: "state.context",
109
+ logicId: machine.id,
110
+ stateNodeId: stateNode.id
111
+ });
112
+ if (error) return error;
113
+ if (stateNode.schemas?.input) {
114
+ error = checkTarget({
115
+ schema: stateNode.schemas.input,
116
+ value: snapshot._stateInputs[stateNode.id],
117
+ boundary: "state.input",
118
+ logicId: machine.id,
119
+ stateNodeId: stateNode.id
120
+ });
121
+ if (error) return error;
122
+ }
123
+ }
124
+ for (const childId of Object.keys(machine.schemas?.children ?? {})) {
125
+ const child = snapshot.children[childId];
126
+ if (child !== void 0) {
127
+ error = checkTarget({
128
+ schema: machine.schemas.children[childId],
129
+ value: child,
130
+ boundary: "child",
131
+ logicId: machine.id,
132
+ childId
133
+ });
134
+ if (error) return error;
135
+ }
136
+ }
137
+ for (const timer of Object.values(snapshot.timers)) if (timer.type === "@xstate.raise") {
138
+ error = checkEvent(machine, timer.event, "raised");
139
+ if (error) return error;
140
+ }
141
+ };
142
+ return { check(request) {
143
+ const { logic } = request;
144
+ const schemas = getSchemas(logic);
145
+ if (request.kind === "input") return checkTarget({
146
+ schema: schemas?.input,
147
+ value: request.input,
148
+ boundary: "input",
149
+ logicId: getLogicId(logic)
150
+ });
151
+ if (request.kind === "event") return checkEvent(logic, request.event, request.eventOrigin);
152
+ const { snapshot, effects } = request;
153
+ if (isStateMachine(logic)) {
154
+ const error = checkMachineResult(logic, snapshot);
155
+ if (error) return error;
156
+ }
157
+ if (snapshot.status === "done") {
158
+ const error = checkTarget({
159
+ schema: schemas?.output,
160
+ value: snapshot.output,
161
+ boundary: "output",
162
+ logicId: getLogicId(logic)
163
+ });
164
+ if (error) return error;
165
+ }
166
+ return checkEmitted(logic, effects);
167
+ } };
168
+ }
169
+ function createError(request, reason, issues, cause) {
170
+ return new ActorValidationError({
171
+ reason,
172
+ boundary: request.boundary,
173
+ ...request.logicId === void 0 ? {} : { logicId: request.logicId },
174
+ ...request.stateNodeId === void 0 ? {} : { stateNodeId: request.stateNodeId },
175
+ ...request.eventType === void 0 ? {} : { eventType: request.eventType },
176
+ ...request.eventOrigin === void 0 ? {} : { eventOrigin: request.eventOrigin },
177
+ ...request.childId === void 0 ? {} : { childId: request.childId },
178
+ ...issues === void 0 ? {} : { issues },
179
+ ...cause === void 0 ? {} : { cause }
180
+ });
181
+ }
182
+ function isStateMachine(logic) {
183
+ return "root" in logic && "schemas" in logic;
184
+ }
185
+ function getSchemas(logic) {
186
+ if (isStateMachine(logic)) return logic.schemas;
187
+ return logic.config?.schemas;
188
+ }
189
+ function findEventSchema(schemas, eventType) {
190
+ if (!schemas) return;
191
+ if (Object.hasOwn(schemas, eventType)) return schemas[eventType];
192
+ const descriptor = Object.keys(schemas).find((key) => matchesEventDescriptor(eventType, key));
193
+ return descriptor === void 0 ? void 0 : schemas[descriptor];
194
+ }
195
+ function getLogicId(logic) {
196
+ return "id" in logic && typeof logic.id === "string" ? logic.id : void 0;
197
+ }
198
+ function getPayload(event) {
199
+ const { type: _, ...payload } = event;
200
+ return payload;
201
+ }
202
+ function getMessage(options) {
203
+ const subject = options.eventType !== void 0 ? ` "${options.eventType}"` : options.childId !== void 0 ? ` "${options.childId}"` : "";
204
+ switch (options.reason) {
205
+ case "unknownEvent": return `Unknown event${subject}`;
206
+ case "unknownEmitted": return `Unknown emitted event${subject}`;
207
+ case "asyncValidationUnsupported": return `Async schema validation is unsupported for ${options.boundary}${subject}`;
208
+ case "transformationUnsupported": return `Schema transformations are unsupported for ${options.boundary}${subject}`;
209
+ case "schemaThrew": return `Schema threw while validating ${options.boundary}${subject}`;
210
+ case "invalid": return `Invalid ${options.boundary}${subject}`;
211
+ }
212
+ }
213
+ function isPromiseLike(value) {
214
+ return !!value && typeof value.then === "function";
215
+ }
216
+ export { ActorValidationError, isActorValidationError, standardSchemaValidator };
package/package.json CHANGED
@@ -1,6 +1,86 @@
1
1
  {
2
2
  "name": "@systemfsoftware/xstate",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "license": "MIT",
4
+ "version": "6.0.0-beta.65",
5
+ "author": "Ryan Lee <drdgvhbh@gmail.com>",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/systemfsoftware/xstate.git",
9
+ "directory": "packages/xstate"
10
+ },
11
+ "homepage": "https://github.com/systemfsoftware/xstate/tree/main/packages/xstate#readme",
12
+ "bugs": "https://github.com/systemfsoftware/xstate/issues",
13
+ "description": "Statecharts and actors for TypeScript, as pure machine definitions and transitions — forked under systemfsoftware from statelyai/xstate (xstate at 2146ae26).",
14
+ "type": "module",
15
+ "sideEffects": false,
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "devDependencies": {
20
+ "@effect/tsgo": "0.64.1",
21
+ "@microsoft/api-extractor": "7.59.1",
22
+ "@systemfsoftware/arethetypeswrong-cli": "file:../../.deps/arethetypeswrong-cli.tgz",
23
+ "@systemfsoftware/conformance-spec": "file:../../.deps/conformance-spec.tgz",
24
+ "@systemfsoftware/effect-gherkin-spec": "file:../../.deps/effect-gherkin-spec.tgz",
25
+ "@systemfsoftware/tsconfig": "file:../../.deps/tsconfig.tgz",
26
+ "@systemfsoftware/vitest": "file:../../.deps/vitest.tgz",
27
+ "@types/node": "24.19.1",
28
+ "ajv": "8.20.0",
29
+ "effect": "4.1.2",
30
+ "rimraf": "6.1.3",
31
+ "rxjs": "7.8.2",
32
+ "tsdown": "0.23.0",
33
+ "typescript": "7.0.2",
34
+ "vitest": "5.0.3",
35
+ "zod": "3.25.76"
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "provenance": true
40
+ },
41
+ "imports": {
42
+ "#is-development": {
43
+ "development": "./src/true.ts",
44
+ "default": "./src/false.ts"
45
+ }
46
+ },
47
+ "exports": {
48
+ ".": {
49
+ "types": "./dist/index.d.ts",
50
+ "default": "./dist/index.mjs"
51
+ },
52
+ "./actors": {
53
+ "types": "./dist/actors.d.ts",
54
+ "default": "./dist/actors.mjs"
55
+ },
56
+ "./durable": {
57
+ "types": "./dist/durable.d.ts",
58
+ "default": "./dist/durable.mjs"
59
+ },
60
+ "./fsm": {
61
+ "types": "./dist/fsm.d.ts",
62
+ "default": "./dist/fsm.mjs"
63
+ },
64
+ "./graph": {
65
+ "types": "./dist/graph.d.ts",
66
+ "default": "./dist/graph.mjs"
67
+ },
68
+ "./validation": {
69
+ "types": "./dist/validation.d.ts",
70
+ "default": "./dist/validation.mjs"
71
+ },
72
+ "./package.json": "./package.json"
73
+ },
74
+ "scripts": {
75
+ "clean": "rimraf dist",
76
+ "build": "tsdown -l warn && pnpm api:check",
77
+ "typecheck": "tsc -b",
78
+ "test": "vitest run",
79
+ "lint:tsgo": "effect-tsgo diagnostics --project tsconfig.tsgo.json --format ${TSGO_FORMAT:-text} && effect-tsgo diagnostics --project tsconfig.test.json --format ${TSGO_FORMAT:-text}",
80
+ "attw": "attw --pack .",
81
+ "api:check": "api-extractor run && api-extractor run --config api-extractor.actors.json && api-extractor run --config api-extractor.durable.json && api-extractor run --config api-extractor.fsm.json && api-extractor run --config api-extractor.graph.json && api-extractor run --config api-extractor.validation.json",
82
+ "api:update": "api-extractor run --local && api-extractor run --local --config api-extractor.actors.json && api-extractor run --local --config api-extractor.durable.json && api-extractor run --local --config api-extractor.fsm.json && api-extractor run --local --config api-extractor.graph.json && api-extractor run --local --config api-extractor.validation.json",
83
+ "lint": "f=${OXLINT_FORMAT:-${AGENT:+agent}}; oxlint src/assert.ts src/stateMatching.ts src/mapState.ts src/fsm.ts src/graph src/transitionGuards.ts src/historyRecall.ts src/stateNodePredicates.ts tests/event-assertions.conformance.test.ts tests/state-matching.conformance.test.ts tests/map-state.conformance.test.ts tests/fsm.conformance.test.ts tests/graph.conformance.test.ts tests/guards.conformance.test.ts tests/history.conformance.test.ts tests/__fixtures__ --format=${f:-default}",
84
+ "mutation": "stryker run"
85
+ }
6
86
  }