@statelyai/sdk 0.26.3 → 0.27.1

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.
Files changed (33) hide show
  1. package/README.md +30 -2
  2. package/dist/auth.d.mts +1 -1
  3. package/dist/{editorHostSession-DFjM-RoT.d.mts → editorHostSession-CWAuoMtC.d.mts} +9 -3
  4. package/dist/{editorHostSession-CwGeXJ6g.mjs → editorHostSession-shrjfosC.mjs} +6 -3
  5. package/dist/editorHostSession.d.mts +1 -1
  6. package/dist/editorHostSession.mjs +1 -1
  7. package/dist/embed.d.mts +6 -3
  8. package/dist/embed.mjs +23 -1
  9. package/dist/embedPanel-Bpbq4sfJ.d.mts +13 -0
  10. package/dist/{graph-DoUReqxz.d.mts → graph-BwHnhzpC.d.mts} +48 -6
  11. package/dist/graph.d.mts +1 -1
  12. package/dist/graph.mjs +36 -4
  13. package/dist/{index-DKRB-u93.d.mts → index-D2I1qPsf.d.mts} +19 -3
  14. package/dist/index.d.mts +8 -7
  15. package/dist/index.mjs +6 -6
  16. package/dist/{inspect-CiPPDR7Q.mjs → inspect-CebH2l6F.mjs} +3 -5
  17. package/dist/{inspect-Br_vS_lK.d.mts → inspect-D61HS-t7.d.mts} +2 -5
  18. package/dist/inspect.d.mts +1 -1
  19. package/dist/inspect.mjs +2 -2
  20. package/dist/patchTypes.d.mts +1 -1
  21. package/dist/protocol.d.mts +46 -15
  22. package/dist/{statelyPragma-B-axv279.mjs → statelyPragma-ByF0-L-N.mjs} +1198 -31
  23. package/dist/{studio-B6P177N3.d.mts → studio-B9-1Ynrx.d.mts} +4 -2
  24. package/dist/{studio-iNSHtNmP.mjs → studio-CNkxMZyz.mjs} +4 -1
  25. package/dist/studio.d.mts +1 -1
  26. package/dist/studio.mjs +1 -1
  27. package/dist/sync.d.mts +12 -4
  28. package/dist/sync.mjs +2920 -262
  29. package/dist/{version-At1lONTa.mjs → version-usAEzut8.mjs} +19 -7
  30. package/package.json +3 -3
  31. package/schemas/xstate.schema.json +41 -5
  32. /package/dist/{auth-B0ZTKri2.d.mts → auth-BPyCCHYo.d.mts} +0 -0
  33. /package/dist/{editor-sync-types-C-zWaaVk.d.mts → editor-sync-types-CTKArS8n.d.mts} +0 -0
@@ -2334,6 +2334,57 @@ var index_vite_proxy_tmp_default = import_js_yaml.default;
2334
2334
 
2335
2335
  //#endregion
2336
2336
  //#region ../graph-tools/dist/index.mjs
2337
+ /**
2338
+ * Convert a resolved {@link GraphNode} back into a {@link NodeConfig}.
2339
+ *
2340
+ * Faithful and complete: round-tripping through `createGraphNode` yields a
2341
+ * deep-equal node. Optional fields are only included when present; ports are
2342
+ * deep-copied so the config does not share port objects with the source node.
2343
+ */
2344
+ function toNodeConfig(node) {
2345
+ const config = { id: node.id };
2346
+ if (node.parentId != null) config.parentId = node.parentId;
2347
+ if (node.initialNodeId != null) config.initialNodeId = node.initialNodeId;
2348
+ if (node.label != null) config.label = node.label;
2349
+ if (node.data != null) config.data = node.data;
2350
+ if (node.ports !== void 0) config.ports = node.ports.map((p) => ({ ...p }));
2351
+ if (node.x !== void 0) config.x = node.x;
2352
+ if (node.y !== void 0) config.y = node.y;
2353
+ if (node.width !== void 0) config.width = node.width;
2354
+ if (node.height !== void 0) config.height = node.height;
2355
+ if (node.shape !== void 0) config.shape = node.shape;
2356
+ if (node.color !== void 0) config.color = node.color;
2357
+ if (node.style !== void 0) config.style = node.style;
2358
+ return config;
2359
+ }
2360
+ /**
2361
+ * Convert a resolved {@link GraphEdge} back into an {@link EdgeConfig}.
2362
+ *
2363
+ * Faithful and complete: round-tripping through `createGraphEdge` yields a
2364
+ * deep-equal edge. Optional fields are only included when present.
2365
+ */
2366
+ function toEdgeConfig(edge) {
2367
+ const config = {
2368
+ id: edge.id,
2369
+ sourceId: edge.sourceId,
2370
+ targetId: edge.targetId
2371
+ };
2372
+ if (edge.label != null) config.label = edge.label;
2373
+ if (edge.data != null) config.data = edge.data;
2374
+ if (edge.weight !== void 0) config.weight = edge.weight;
2375
+ if (edge.mode !== void 0) config.mode = edge.mode;
2376
+ if (edge.sourcePort !== void 0) config.sourcePort = edge.sourcePort;
2377
+ if (edge.targetPort !== void 0) config.targetPort = edge.targetPort;
2378
+ if (edge.points !== void 0) config.points = edge.points.map((p) => ({ ...p }));
2379
+ if (edge.routing !== void 0) config.routing = edge.routing;
2380
+ if (edge.x !== void 0) config.x = edge.x;
2381
+ if (edge.y !== void 0) config.y = edge.y;
2382
+ if (edge.width !== void 0) config.width = edge.width;
2383
+ if (edge.height !== void 0) config.height = edge.height;
2384
+ if (edge.color !== void 0) config.color = edge.color;
2385
+ if (edge.style !== void 0) config.style = edge.style;
2386
+ return config;
2387
+ }
2337
2388
  const LAYOUT_KEYS = {
2338
2389
  node: [
2339
2390
  "x",
@@ -2356,6 +2407,872 @@ const LAYOUT_KEYS = {
2356
2407
  ]
2357
2408
  };
2358
2409
  new Set(LAYOUT_KEYS.node), new Set(LAYOUT_KEYS.edge);
2410
+ /** Shallow-compare two values, returning true if they differ. */
2411
+ function differs(a, b) {
2412
+ if (a === b) return false;
2413
+ if (a == null || b == null) return a !== b;
2414
+ if (typeof a === "object" && typeof b === "object") return JSON.stringify(a) !== JSON.stringify(b);
2415
+ return true;
2416
+ }
2417
+ const NODE_COMPARE_KEYS = [
2418
+ "parentId",
2419
+ "initialNodeId",
2420
+ "label",
2421
+ "data",
2422
+ "ports",
2423
+ "x",
2424
+ "y",
2425
+ "width",
2426
+ "height",
2427
+ "shape",
2428
+ "color",
2429
+ "style"
2430
+ ];
2431
+ const EDGE_COMPARE_KEYS = [
2432
+ "sourceId",
2433
+ "targetId",
2434
+ "label",
2435
+ "data",
2436
+ "weight",
2437
+ "mode",
2438
+ "sourcePort",
2439
+ "targetPort",
2440
+ "points",
2441
+ "routing",
2442
+ "x",
2443
+ "y",
2444
+ "width",
2445
+ "height",
2446
+ "color",
2447
+ "style"
2448
+ ];
2449
+ /**
2450
+ * Compute a structured diff from graph `a` to graph `b` by matching IDs.
2451
+ *
2452
+ * @example
2453
+ * ```ts
2454
+ * import { createGraph, getDiff } from '@statelyai/graph';
2455
+ *
2456
+ * const a = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
2457
+ * const b = createGraph({ nodes: [{ id: 'n1', label: 'hello' }, { id: 'n2' }], edges: [] });
2458
+ *
2459
+ * const diff = getDiff(a, b);
2460
+ * // diff.nodes.added → [{ id: 'n2' }]
2461
+ * // diff.nodes.updated → [{ id: 'n1', old: { label: '' }, new: { label: 'hello' } }]
2462
+ * ```
2463
+ */
2464
+ function getDiff(a, b) {
2465
+ const aNodeMap = new Map(a.nodes.map((n) => [n.id, n]));
2466
+ const bNodeMap = new Map(b.nodes.map((n) => [n.id, n]));
2467
+ const aEdgeMap = new Map(a.edges.map((e) => [e.id, e]));
2468
+ const bEdgeMap = new Map(b.edges.map((e) => [e.id, e]));
2469
+ const diff = {
2470
+ nodes: {
2471
+ added: [],
2472
+ removed: [],
2473
+ updated: []
2474
+ },
2475
+ edges: {
2476
+ added: [],
2477
+ removed: [],
2478
+ updated: []
2479
+ }
2480
+ };
2481
+ for (const [id, nodeB] of bNodeMap) {
2482
+ const nodeA = aNodeMap.get(id);
2483
+ if (!nodeA) diff.nodes.added.push(toNodeConfig(nodeB));
2484
+ else {
2485
+ const oldPartial = {};
2486
+ const newPartial = {};
2487
+ for (const key of NODE_COMPARE_KEYS) {
2488
+ const oldValue = nodeA[key] ?? null;
2489
+ const newValue = nodeB[key] ?? null;
2490
+ if (differs(oldValue, newValue)) {
2491
+ oldPartial[key] = oldValue;
2492
+ newPartial[key] = newValue;
2493
+ }
2494
+ }
2495
+ if (Object.keys(oldPartial).length > 0) diff.nodes.updated.push({
2496
+ id,
2497
+ old: oldPartial,
2498
+ new: newPartial
2499
+ });
2500
+ }
2501
+ }
2502
+ for (const [id, nodeA] of aNodeMap) if (!bNodeMap.has(id)) diff.nodes.removed.push(toNodeConfig(nodeA));
2503
+ for (const [id, edgeB] of bEdgeMap) {
2504
+ const edgeA = aEdgeMap.get(id);
2505
+ if (!edgeA) diff.edges.added.push(toEdgeConfig(edgeB));
2506
+ else {
2507
+ const oldPartial = {};
2508
+ const newPartial = {};
2509
+ for (const key of EDGE_COMPARE_KEYS) {
2510
+ const oldValue = edgeA[key] ?? null;
2511
+ const newValue = edgeB[key] ?? null;
2512
+ if (differs(oldValue, newValue)) {
2513
+ oldPartial[key] = oldValue;
2514
+ newPartial[key] = newValue;
2515
+ }
2516
+ }
2517
+ if (Object.keys(oldPartial).length > 0) diff.edges.updated.push({
2518
+ id,
2519
+ old: oldPartial,
2520
+ new: newPartial
2521
+ });
2522
+ }
2523
+ }
2524
+ for (const [id, edgeA] of aEdgeMap) if (!bEdgeMap.has(id)) diff.edges.removed.push(toEdgeConfig(edgeA));
2525
+ return diff;
2526
+ }
2527
+ /**
2528
+ * Check if a diff has zero changes.
2529
+ *
2530
+ * @example
2531
+ * ```ts
2532
+ * import { createGraph, getDiff, isEmptyDiff } from '@statelyai/graph';
2533
+ *
2534
+ * const g = createGraph({ nodes: [{ id: 'n1' }], edges: [] });
2535
+ * const diff = getDiff(g, g);
2536
+ * isEmptyDiff(diff); // true
2537
+ * ```
2538
+ */
2539
+ function isEmptyDiff(diff) {
2540
+ return diff.nodes.added.length === 0 && diff.nodes.removed.length === 0 && diff.nodes.updated.length === 0 && diff.edges.added.length === 0 && diff.edges.removed.length === 0 && diff.edges.updated.length === 0;
2541
+ }
2542
+ function summarizeGraphDiff(diff) {
2543
+ return {
2544
+ hasChanges: !isEmptyDiff(diff),
2545
+ nodeChanges: diff.nodes.added.length + diff.nodes.removed.length + diff.nodes.updated.length,
2546
+ edgeChanges: diff.edges.added.length + diff.edges.removed.length + diff.edges.updated.length
2547
+ };
2548
+ }
2549
+ function nodeDepth$1(graph, node) {
2550
+ let depth = 0;
2551
+ let parentId = node.parentId;
2552
+ while (parentId) {
2553
+ depth++;
2554
+ parentId = graph.nodes.find((candidate) => candidate.id === parentId)?.parentId;
2555
+ }
2556
+ return depth;
2557
+ }
2558
+ function nodeKey(node) {
2559
+ return node.data?.key || node.id;
2560
+ }
2561
+ function edgeSignature(edge) {
2562
+ return [
2563
+ edge.sourceId,
2564
+ edge.data?.eventType,
2565
+ edge.targetId,
2566
+ edge.data?.guard?.type ?? ""
2567
+ ].join("->");
2568
+ }
2569
+ function getStableNodeId(node, parentStableId, siblingIndex, preferredIds) {
2570
+ const preferredId = preferredIds?.get(node.id);
2571
+ if (preferredId !== void 0) return preferredId;
2572
+ if (node.parentId === null) return "root";
2573
+ const key = nodeKey(node);
2574
+ const suffix = siblingIndex === 0 ? key : `${key}_${siblingIndex + 1}`;
2575
+ return parentStableId ? `${parentStableId}.${suffix}` : suffix;
2576
+ }
2577
+ function getStableEdgeId(edge, siblingIndex, preferredIds) {
2578
+ const preferredId = preferredIds?.get(edge.id);
2579
+ if (preferredId !== void 0) return preferredId;
2580
+ const suffix = siblingIndex === 0 ? "" : `.${siblingIndex + 1}`;
2581
+ return edgeSignature(edge).concat(suffix);
2582
+ }
2583
+ function removePresentationFields(entity, kind) {
2584
+ const mutableEntity = entity;
2585
+ for (const key of LAYOUT_KEYS[kind]) delete mutableEntity[key];
2586
+ const data = mutableEntity.data;
2587
+ if (data && typeof data === "object" && !Array.isArray(data)) delete data.color;
2588
+ }
2589
+ /**
2590
+ * Rewrites entity ids to structural ("semantic") ids so two graphs that model
2591
+ * the same machine compare equal regardless of how their ids were minted.
2592
+ *
2593
+ * Invariant: node and edge array order is preserved exactly. Callers
2594
+ * (`alignCompareIds` in the editor's /v1/diff route) rely on
2595
+ * `normalized.nodes[i]` describing `graph.nodes[i]` to translate a semantic id
2596
+ * back to the caller's original id. Never sort, filter, or reorder the arrays
2597
+ * on the returned graph; sorting for traversal must be done on a copy, as the
2598
+ * depth ordering below does.
2599
+ *
2600
+ * Presentation-only fields defined by `LAYOUT_KEYS`, plus entity data colors,
2601
+ * are removed. When preferred ids are supplied, matching raw ids retain the
2602
+ * base graph's semantic identity so a stable-id rename is reported as an
2603
+ * update.
2604
+ *
2605
+ * Entity `data` is treated as optional throughout: sparse graphs (a node with
2606
+ * `data: {}`, an edge with `data: null`) normalize instead of throwing.
2607
+ */
2608
+ function normalizeGraphForSemanticDiff(graph, preferredIds) {
2609
+ const normalized = structuredClone(graph);
2610
+ const nodeIdMap = /* @__PURE__ */ new Map();
2611
+ const siblingKeys = /* @__PURE__ */ new Map();
2612
+ const reservedNodeIds = new Set(preferredIds?.nodes.values());
2613
+ const claimedNodeIds = /* @__PURE__ */ new Set();
2614
+ const nodesByDepth = [...normalized.nodes].sort((a, b) => nodeDepth$1(normalized, a) - nodeDepth$1(normalized, b));
2615
+ for (const node of nodesByDepth) {
2616
+ const parentStableId = node.parentId ? nodeIdMap.get(node.parentId) ?? node.parentId : null;
2617
+ const key = `${parentStableId ?? ""}:${nodeKey(node)}`;
2618
+ const siblingIndex = siblingKeys.get(key) ?? 0;
2619
+ siblingKeys.set(key, siblingIndex + 1);
2620
+ const proposedId = getStableNodeId(node, parentStableId, siblingIndex, preferredIds?.nodes);
2621
+ let stableId = proposedId;
2622
+ let collisionIndex = 2;
2623
+ while (!preferredIds?.nodes.has(node.id) && (reservedNodeIds.has(stableId) || claimedNodeIds.has(stableId))) stableId = `${proposedId}:unmatched:${collisionIndex++}`;
2624
+ claimedNodeIds.add(stableId);
2625
+ nodeIdMap.set(node.id, stableId);
2626
+ }
2627
+ for (const node of normalized.nodes) {
2628
+ removePresentationFields(node, "node");
2629
+ node.id = nodeIdMap.get(node.id) ?? node.id;
2630
+ if (node.parentId) node.parentId = nodeIdMap.get(node.parentId) ?? node.parentId;
2631
+ if (node.initialNodeId) node.initialNodeId = nodeIdMap.get(node.initialNodeId) ?? node.initialNodeId;
2632
+ if (node.data?.initialId) node.data.initialId = nodeIdMap.get(node.data.initialId) ?? node.data.initialId;
2633
+ }
2634
+ const edgeSiblingKeys = /* @__PURE__ */ new Map();
2635
+ const reservedEdgeIds = new Set(preferredIds?.edges.values());
2636
+ const claimedEdgeIds = /* @__PURE__ */ new Set();
2637
+ for (const edge of normalized.edges) {
2638
+ removePresentationFields(edge, "edge");
2639
+ edge.sourceId = nodeIdMap.get(edge.sourceId) ?? edge.sourceId;
2640
+ edge.targetId = nodeIdMap.get(edge.targetId) ?? edge.targetId;
2641
+ const key = edgeSignature(edge);
2642
+ const siblingIndex = edgeSiblingKeys.get(key) ?? 0;
2643
+ edgeSiblingKeys.set(key, siblingIndex + 1);
2644
+ const proposedId = getStableEdgeId(edge, siblingIndex, preferredIds?.edges);
2645
+ let stableId = proposedId;
2646
+ let collisionIndex = 2;
2647
+ while (!preferredIds?.edges.has(edge.id) && (reservedEdgeIds.has(stableId) || claimedEdgeIds.has(stableId))) stableId = `${proposedId}:unmatched:${collisionIndex++}`;
2648
+ claimedEdgeIds.add(stableId);
2649
+ edge.id = stableId;
2650
+ }
2651
+ if (normalized.initialNodeId) normalized.initialNodeId = nodeIdMap.get(normalized.initialNodeId) ?? normalized.initialNodeId;
2652
+ return normalized;
2653
+ }
2654
+ function diffGraphsSemantically(baseGraph, compareGraph) {
2655
+ const base = normalizeGraphForSemanticDiff(baseGraph);
2656
+ const compareNodeIds = new Set(compareGraph.nodes.map((node) => node.id));
2657
+ const compareEdgeIds = new Set(compareGraph.edges.map((edge) => edge.id));
2658
+ const compare = normalizeGraphForSemanticDiff(compareGraph, {
2659
+ nodes: new Map(baseGraph.nodes.map((node, index) => [node.id, base.nodes[index].id]).filter(([id]) => compareNodeIds.has(id))),
2660
+ edges: new Map(baseGraph.edges.map((edge, index) => [edge.id, base.edges[index].id]).filter(([id]) => compareEdgeIds.has(id)))
2661
+ });
2662
+ const diff = getDiff(base, compare);
2663
+ return {
2664
+ base,
2665
+ compare,
2666
+ diff,
2667
+ summary: summarizeGraphDiff(diff)
2668
+ };
2669
+ }
2670
+ function stableStringify(value) {
2671
+ return JSON.stringify(value, (_key, item) => {
2672
+ if (item && typeof item === "object" && !Array.isArray(item)) return Object.fromEntries(Object.entries(item).sort(([left], [right]) => left.localeCompare(right)));
2673
+ return item;
2674
+ });
2675
+ }
2676
+ function isEqual(a, b) {
2677
+ return stableStringify(a) === stableStringify(b);
2678
+ }
2679
+ function toStateColor(value) {
2680
+ return value ?? null;
2681
+ }
2682
+ function toTransitionColor(value) {
2683
+ return value ?? null;
2684
+ }
2685
+ function nodeDepth(graph, nodeId) {
2686
+ const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
2687
+ let depth = 0;
2688
+ let current = nodeById.get(nodeId);
2689
+ while (current?.parentId) {
2690
+ depth += 1;
2691
+ current = nodeById.get(current.parentId);
2692
+ }
2693
+ return depth;
2694
+ }
2695
+ function isRootNode(node) {
2696
+ return node.parentId == null;
2697
+ }
2698
+ function buildStateUpdatePatch(prevNode, nextNode) {
2699
+ const patch = {
2700
+ op: "updateState",
2701
+ stateId: nextNode.id
2702
+ };
2703
+ let changed = false;
2704
+ if (!prevNode || prevNode.data.key !== nextNode.data.key) {
2705
+ patch.key = nextNode.data.key;
2706
+ changed = true;
2707
+ }
2708
+ if (!prevNode || prevNode.data.type !== nextNode.data.type) {
2709
+ patch.type = nextNode.data.type ?? null;
2710
+ changed = true;
2711
+ }
2712
+ if (!prevNode || prevNode.data.description !== nextNode.data.description) {
2713
+ patch.stateDescription = nextNode.data.description ?? null;
2714
+ changed = true;
2715
+ }
2716
+ if (!prevNode || prevNode.data.initialId !== nextNode.data.initialId) {
2717
+ patch.initialId = nextNode.data.initialId ?? null;
2718
+ changed = true;
2719
+ }
2720
+ if (!prevNode || !isEqual(prevNode.data.initialInput, nextNode.data.initialInput)) {
2721
+ patch.initialInput = nextNode.data.initialInput ?? null;
2722
+ changed = true;
2723
+ }
2724
+ if (!prevNode || !isEqual(prevNode.data.output, nextNode.data.output)) {
2725
+ patch.output = nextNode.data.output ?? null;
2726
+ changed = true;
2727
+ }
2728
+ if (!prevNode || !isEqual(prevNode.data.timeout, nextNode.data.timeout)) {
2729
+ patch.timeout = nextNode.data.timeout ?? null;
2730
+ changed = true;
2731
+ }
2732
+ if (!prevNode || !isEqual(prevNode.data.route, nextNode.data.route)) {
2733
+ patch.route = nextNode.data.route ?? null;
2734
+ changed = true;
2735
+ }
2736
+ if (!prevNode || prevNode.data.color !== nextNode.data.color) {
2737
+ patch.color = toStateColor(nextNode.data.color);
2738
+ changed = true;
2739
+ }
2740
+ if (!prevNode || !isEqual(prevNode.data.meta, nextNode.data.meta)) {
2741
+ patch.meta = nextNode.data.meta ?? null;
2742
+ changed = true;
2743
+ }
2744
+ if (!prevNode || prevNode.data.history !== nextNode.data.history) {
2745
+ patch.history = nextNode.data.history === true ? "shallow" : nextNode.data.history === false ? null : nextNode.data.history ?? null;
2746
+ changed = true;
2747
+ }
2748
+ return changed ? patch : null;
2749
+ }
2750
+ function buildTransitionUpdatePatch(prevEdge, nextEdge) {
2751
+ const patch = {
2752
+ op: "updateTransition",
2753
+ transitionId: nextEdge.id
2754
+ };
2755
+ let changed = false;
2756
+ if (!prevEdge || prevEdge.sourceId !== nextEdge.sourceId) {
2757
+ patch.sourceId = nextEdge.sourceId;
2758
+ changed = true;
2759
+ }
2760
+ if (!prevEdge || prevEdge.targetId !== nextEdge.targetId) {
2761
+ patch.targetId = nextEdge.targetId;
2762
+ changed = true;
2763
+ }
2764
+ if (!prevEdge || prevEdge.data.eventType !== nextEdge.data.eventType) {
2765
+ patch.eventType = nextEdge.data.eventType;
2766
+ changed = true;
2767
+ }
2768
+ if (!prevEdge || !isEqual(prevEdge.data.matches, nextEdge.data.matches)) {
2769
+ patch.matches = nextEdge.data.matches ?? null;
2770
+ changed = true;
2771
+ }
2772
+ if (!prevEdge || prevEdge.data.transitionType !== nextEdge.data.transitionType) {
2773
+ patch.transitionType = nextEdge.data.transitionType ?? "normal";
2774
+ changed = true;
2775
+ }
2776
+ if (!prevEdge || prevEdge.data.description !== nextEdge.data.description) {
2777
+ patch.transitionDescription = nextEdge.data.description ?? null;
2778
+ changed = true;
2779
+ }
2780
+ if (!prevEdge || !isEqual(prevEdge.data.input, nextEdge.data.input)) {
2781
+ patch.input = nextEdge.data.input ?? null;
2782
+ changed = true;
2783
+ }
2784
+ if (!prevEdge || prevEdge.data.color !== nextEdge.data.color) {
2785
+ patch.color = toTransitionColor(nextEdge.data.color);
2786
+ changed = true;
2787
+ }
2788
+ if (!prevEdge || !isEqual(prevEdge.data.meta, nextEdge.data.meta)) {
2789
+ patch.meta = nextEdge.data.meta ?? null;
2790
+ changed = true;
2791
+ }
2792
+ return changed ? patch : null;
2793
+ }
2794
+ function diffTags(patches, nodeId, prevTags, nextTags) {
2795
+ const getTagName = (tag) => typeof tag === "string" ? tag : tag.name;
2796
+ const prev = new Set(prevTags.map(getTagName));
2797
+ const next = new Set(nextTags.map(getTagName));
2798
+ for (const tag of next) if (!prev.has(tag)) patches.push({
2799
+ op: "createTag",
2800
+ nodeId,
2801
+ tag: { name: tag }
2802
+ });
2803
+ for (const tag of prev) if (!next.has(tag)) patches.push({
2804
+ op: "deleteTag",
2805
+ nodeId,
2806
+ tagName: tag
2807
+ });
2808
+ }
2809
+ function requiresAppendOnlyListRebuild(prevIds, nextIds) {
2810
+ const prevIdSet = new Set(prevIds);
2811
+ const nextIdSet = new Set(nextIds);
2812
+ const retainedPrevIds = prevIds.filter((id) => nextIdSet.has(id));
2813
+ const retainedNextIds = nextIds.filter((id) => prevIdSet.has(id));
2814
+ let sawNewId = false;
2815
+ for (const id of nextIds) if (prevIdSet.has(id)) {
2816
+ if (sawNewId) return true;
2817
+ } else sawNewId = true;
2818
+ return !isEqual(retainedPrevIds, retainedNextIds);
2819
+ }
2820
+ function appendCreateInvokePatch(patches, nodeId, invoke) {
2821
+ patches.push({
2822
+ op: "createInvoke",
2823
+ nodeId,
2824
+ invoke: {
2825
+ id: invoke.id,
2826
+ ...invoke.invocationId ? { invocationId: invoke.invocationId } : {},
2827
+ src: invoke.src,
2828
+ ...invoke.srcExpression ? { srcExpression: invoke.srcExpression } : {},
2829
+ ...invoke.code ? { code: invoke.code } : {},
2830
+ ...invoke.registryKey ? { registryKey: invoke.registryKey } : {},
2831
+ ...invoke.timeout !== void 0 ? { timeout: invoke.timeout } : {},
2832
+ ...invoke.input ? { input: invoke.input } : {},
2833
+ ...invoke.output ? { output: invoke.output } : {}
2834
+ }
2835
+ });
2836
+ }
2837
+ function diffInvokes(patches, nodeId, prevInvokes, nextInvokes) {
2838
+ if (requiresAppendOnlyListRebuild(prevInvokes.map((invoke) => invoke.id), nextInvokes.map((invoke) => invoke.id))) {
2839
+ for (const invoke of prevInvokes) patches.push({
2840
+ op: "deleteInvoke",
2841
+ nodeId,
2842
+ invokeId: invoke.id
2843
+ });
2844
+ for (const invoke of nextInvokes) appendCreateInvokePatch(patches, nodeId, invoke);
2845
+ return;
2846
+ }
2847
+ const prevById = new Map(prevInvokes.map((invoke) => [invoke.id, invoke]));
2848
+ const nextById = new Map(nextInvokes.map((invoke) => [invoke.id, invoke]));
2849
+ for (const invoke of nextInvokes) {
2850
+ const previous = prevById.get(invoke.id);
2851
+ if (!previous) {
2852
+ appendCreateInvokePatch(patches, nodeId, invoke);
2853
+ continue;
2854
+ }
2855
+ const data = {};
2856
+ if (previous.invocationId !== invoke.invocationId) data.invocationId = invoke.invocationId ?? null;
2857
+ if (previous.src !== invoke.src) data.src = invoke.src;
2858
+ if (previous.code !== invoke.code) data.code = invoke.code ?? null;
2859
+ if (!isEqual(previous.srcExpression, invoke.srcExpression)) data.srcExpression = invoke.srcExpression ?? null;
2860
+ if (previous.registryKey !== invoke.registryKey) data.registryKey = invoke.registryKey ?? null;
2861
+ if (!isEqual(previous.timeout, invoke.timeout)) data.timeout = invoke.timeout ?? null;
2862
+ if (!isEqual(previous.input, invoke.input)) data.input = invoke.input ?? null;
2863
+ if (!isEqual(previous.output, invoke.output)) data.output = invoke.output ?? null;
2864
+ if (Object.keys(data).length > 0) patches.push({
2865
+ op: "updateInvoke",
2866
+ nodeId,
2867
+ invokeId: invoke.id,
2868
+ data
2869
+ });
2870
+ }
2871
+ for (const invoke of prevInvokes) if (!nextById.has(invoke.id)) patches.push({
2872
+ op: "deleteInvoke",
2873
+ nodeId,
2874
+ invokeId: invoke.id
2875
+ });
2876
+ }
2877
+ function diffActions(patches, location, prevActions, nextActions) {
2878
+ const actionId = (action, index) => action.id ?? `${index}:${action.type}`;
2879
+ const prevIds = prevActions.map(actionId);
2880
+ const nextIds = nextActions.map(actionId);
2881
+ if (requiresAppendOnlyListRebuild(prevIds, nextIds)) {
2882
+ prevActions.forEach((action, index) => {
2883
+ patches.push({
2884
+ op: "deleteAction",
2885
+ location,
2886
+ actionId: actionId(action, index)
2887
+ });
2888
+ });
2889
+ nextActions.forEach((action, index) => {
2890
+ patches.push({
2891
+ op: "createAction",
2892
+ location,
2893
+ index,
2894
+ action: {
2895
+ id: action.id,
2896
+ type: action.type,
2897
+ params: action.params
2898
+ }
2899
+ });
2900
+ });
2901
+ return;
2902
+ }
2903
+ const prevById = new Map(prevActions.map((action, index) => [actionId(action, index), action]));
2904
+ const nextIdSet = new Set(nextIds);
2905
+ prevActions.forEach((action, index) => {
2906
+ const id = actionId(action, index);
2907
+ if (!nextIdSet.has(id)) patches.push({
2908
+ op: "deleteAction",
2909
+ location,
2910
+ actionId: id
2911
+ });
2912
+ });
2913
+ nextActions.forEach((action, index) => {
2914
+ const id = actionId(action, index);
2915
+ const previous = prevById.get(id);
2916
+ if (!previous) {
2917
+ patches.push({
2918
+ op: "createAction",
2919
+ location,
2920
+ index,
2921
+ action: {
2922
+ id: action.id,
2923
+ type: action.type,
2924
+ params: action.params
2925
+ }
2926
+ });
2927
+ return;
2928
+ }
2929
+ const data = {};
2930
+ if (previous.type !== action.type) data.type = action.type;
2931
+ if (!isEqual(previous.params, action.params)) data.params = action.params ?? {};
2932
+ if (Object.keys(data).length > 0) patches.push({
2933
+ op: "updateAction",
2934
+ location,
2935
+ actionId: id,
2936
+ data
2937
+ });
2938
+ });
2939
+ }
2940
+ function implementationList$1(graph, sourceType) {
2941
+ const implementations = graph.data?.implementations;
2942
+ if (!implementations) return [];
2943
+ switch (sourceType) {
2944
+ case "action": return implementations.actions ?? [];
2945
+ case "guard": return implementations.guards ?? [];
2946
+ case "actor": return implementations.actors ?? [];
2947
+ case "delay": return implementations.delays ?? [];
2948
+ }
2949
+ }
2950
+ function collectUnsupportedChanges(prevGraph, nextGraph) {
2951
+ const unsupportedChanges = [];
2952
+ const prevNodeById = new Map(prevGraph.nodes.map((node) => [node.id, node]));
2953
+ for (const node of nextGraph.nodes) {
2954
+ const previous = prevNodeById.get(node.id);
2955
+ if (previous && (previous.parentId ?? null) !== (node.parentId ?? null)) unsupportedChanges.push(`State "${node.id}" moved to a different parent.`);
2956
+ }
2957
+ for (const sourceType of [
2958
+ "action",
2959
+ "guard",
2960
+ "actor",
2961
+ "delay"
2962
+ ]) {
2963
+ const previousById = new Map(implementationList$1(prevGraph, sourceType).map((implementation) => [implementation.id, implementation]));
2964
+ for (const implementation of implementationList$1(nextGraph, sourceType)) {
2965
+ const previous = previousById.get(implementation.id);
2966
+ const unsupportedMetadata = {
2967
+ description: implementation.description,
2968
+ lang: implementation.code?.lang,
2969
+ deps: implementation.code?.deps,
2970
+ ..."paramsSchema" in implementation ? { paramsSchema: implementation.paramsSchema } : {},
2971
+ ..."inputSchema" in implementation ? { inputSchema: implementation.inputSchema } : {},
2972
+ ..."outputSchema" in implementation ? { outputSchema: implementation.outputSchema } : {}
2973
+ };
2974
+ const previousUnsupportedMetadata = previous ? {
2975
+ description: previous.description,
2976
+ lang: previous.code?.lang,
2977
+ deps: previous.code?.deps,
2978
+ ..."paramsSchema" in previous ? { paramsSchema: previous.paramsSchema } : {},
2979
+ ..."inputSchema" in previous ? { inputSchema: previous.inputSchema } : {},
2980
+ ..."outputSchema" in previous ? { outputSchema: previous.outputSchema } : {}
2981
+ } : {};
2982
+ if (previous ? !isEqual(previousUnsupportedMetadata, unsupportedMetadata) : Object.values(unsupportedMetadata).some((value) => value !== void 0 && value !== null)) unsupportedChanges.push(`${sourceType} implementation "${implementation.id}" has metadata that source patches cannot represent.`);
2983
+ }
2984
+ }
2985
+ return unsupportedChanges;
2986
+ }
2987
+ function diffImplementations(patches, sourceType, prevGraph, nextGraph) {
2988
+ const prevById = new Map(implementationList$1(prevGraph, sourceType).map((implementation) => [implementation.id, implementation]));
2989
+ const nextById = new Map(implementationList$1(nextGraph, sourceType).map((implementation) => [implementation.id, implementation]));
2990
+ for (const implementation of nextById.values()) {
2991
+ const previous = prevById.get(implementation.id);
2992
+ const code = implementation.code?.body;
2993
+ if (!previous) {
2994
+ patches.push({
2995
+ op: "createImplementation",
2996
+ sourceType,
2997
+ implementation: {
2998
+ id: implementation.id,
2999
+ name: implementation.name,
3000
+ ...code !== void 0 ? { code } : void 0
3001
+ }
3002
+ });
3003
+ continue;
3004
+ }
3005
+ const data = {};
3006
+ if (previous.name !== implementation.name) data.name = implementation.name;
3007
+ if (previous.code?.body !== implementation.code?.body) data.code = code ?? null;
3008
+ if (Object.keys(data).length > 0) patches.push({
3009
+ op: "updateImplementation",
3010
+ sourceType,
3011
+ implementationId: implementation.id,
3012
+ data
3013
+ });
3014
+ }
3015
+ for (const implementation of prevById.values()) if (!nextById.has(implementation.id)) patches.push({
3016
+ op: "deleteImplementation",
3017
+ sourceType,
3018
+ implementationId: implementation.id
3019
+ });
3020
+ }
3021
+ function appendCreateTransitionPatches(patches, edge) {
3022
+ patches.push({
3023
+ op: "createTransition",
3024
+ id: edge.id,
3025
+ sourceId: edge.sourceId,
3026
+ targetId: edge.targetId,
3027
+ eventType: edge.data.eventType,
3028
+ ...edge.data.matches ? { matches: edge.data.matches } : {},
3029
+ transitionType: edge.data.transitionType,
3030
+ ...edge.data.guard ? { guard: edge.data.guard } : {},
3031
+ ...edge.data.color ? { color: toTransitionColor(edge.data.color) } : {},
3032
+ ...edge.data.description ? { transitionDescription: edge.data.description } : {},
3033
+ ...edge.data.input !== void 0 ? { input: edge.data.input } : {}
3034
+ });
3035
+ if (edge.data.meta) patches.push({
3036
+ op: "updateTransition",
3037
+ transitionId: edge.id,
3038
+ meta: edge.data.meta
3039
+ });
3040
+ diffActions(patches, {
3041
+ edgeId: edge.id,
3042
+ group: "transition"
3043
+ }, [], edge.data.actions ?? []);
3044
+ }
3045
+ /** Transitions are ordered relative to their (source state, event type) peers. */
3046
+ function transitionPriorityGroup(edge) {
3047
+ return `${edge.sourceId}\0${edge.data?.eventType ?? ""}`;
3048
+ }
3049
+ function groupEdgeIdsByPriority(edges) {
3050
+ const groups = /* @__PURE__ */ new Map();
3051
+ for (const edge of edges) {
3052
+ const key = transitionPriorityGroup(edge);
3053
+ const ids = groups.get(key);
3054
+ if (ids) ids.push(edge.id);
3055
+ else groups.set(key, [edge.id]);
3056
+ }
3057
+ return groups;
3058
+ }
3059
+ /**
3060
+ * Returns the ids of transitions that must be deleted and recreated because
3061
+ * their priority group cannot be reached by appends and deletions alone.
3062
+ *
3063
+ * An edge is rebuilt when either the group it came from or the group it moves
3064
+ * to needs a rebuild, so a rebuilt group is always torn down and recreated as
3065
+ * a whole.
3066
+ */
3067
+ function collectRebuiltEdgeIds(prevGraph, nextGraph) {
3068
+ const prevGroups = groupEdgeIdsByPriority(prevGraph.edges);
3069
+ const nextGroups = groupEdgeIdsByPriority(nextGraph.edges);
3070
+ const rebuiltGroups = /* @__PURE__ */ new Set();
3071
+ for (const key of new Set([...prevGroups.keys(), ...nextGroups.keys()])) if (requiresAppendOnlyListRebuild(prevGroups.get(key) ?? [], nextGroups.get(key) ?? [])) rebuiltGroups.add(key);
3072
+ const rebuiltEdgeIds = /* @__PURE__ */ new Set();
3073
+ for (const edge of [...prevGraph.edges, ...nextGraph.edges]) if (rebuiltGroups.has(transitionPriorityGroup(edge))) rebuiltEdgeIds.add(edge.id);
3074
+ return rebuiltEdgeIds;
3075
+ }
3076
+ function graphChangeToPatchesResult(prevGraph, nextGraph) {
3077
+ const patches = [];
3078
+ const unsupportedChanges = collectUnsupportedChanges(prevGraph, nextGraph);
3079
+ const prevNodeById = new Map(prevGraph.nodes.map((node) => [node.id, node]));
3080
+ const nextNodeById = new Map(nextGraph.nodes.map((node) => [node.id, node]));
3081
+ const prevEdgeById = new Map(prevGraph.edges.map((edge) => [edge.id, edge]));
3082
+ const nextEdgeById = new Map(nextGraph.edges.map((edge) => [edge.id, edge]));
3083
+ const createdNodes = nextGraph.nodes.filter((node) => !isRootNode(node) && !prevNodeById.has(node.id)).sort((a, b) => nodeDepth(nextGraph, a.id) - nodeDepth(nextGraph, b.id));
3084
+ for (const node of createdNodes) {
3085
+ const x = node.position?.x ?? node.x;
3086
+ const y = node.position?.y ?? node.y;
3087
+ patches.push({
3088
+ op: "createState",
3089
+ id: node.id,
3090
+ parentId: node.parentId,
3091
+ key: node.data.key,
3092
+ type: node.data.type,
3093
+ ...x !== void 0 ? { x } : {},
3094
+ ...y !== void 0 ? { y } : {},
3095
+ color: toStateColor(node.data.color),
3096
+ initial: nextNodeById.get(node.parentId)?.data.initialId === node.id
3097
+ });
3098
+ const stateUpdate = buildStateUpdatePatch(void 0, node);
3099
+ if (stateUpdate) patches.push(stateUpdate);
3100
+ diffTags(patches, node.id, [], node.data.tags ?? []);
3101
+ diffInvokes(patches, node.id, [], node.data.invokes ?? []);
3102
+ diffActions(patches, {
3103
+ nodeId: node.id,
3104
+ group: "entry"
3105
+ }, [], node.data.entry ?? []);
3106
+ diffActions(patches, {
3107
+ nodeId: node.id,
3108
+ group: "exit"
3109
+ }, [], node.data.exit ?? []);
3110
+ }
3111
+ for (const node of prevGraph.nodes.filter((node) => !isRootNode(node) && !nextNodeById.has(node.id)).sort((a, b) => nodeDepth(prevGraph, b.id) - nodeDepth(prevGraph, a.id))) patches.push({
3112
+ op: "deleteState",
3113
+ stateId: node.id
3114
+ });
3115
+ for (const node of nextGraph.nodes) {
3116
+ const previous = prevNodeById.get(node.id);
3117
+ if (!previous) continue;
3118
+ const stateUpdate = buildStateUpdatePatch(previous, node);
3119
+ if (stateUpdate) patches.push(stateUpdate);
3120
+ diffTags(patches, node.id, previous.data.tags ?? [], node.data.tags ?? []);
3121
+ diffInvokes(patches, node.id, previous.data.invokes ?? [], node.data.invokes ?? []);
3122
+ diffActions(patches, {
3123
+ nodeId: node.id,
3124
+ group: "entry"
3125
+ }, previous.data.entry ?? [], node.data.entry ?? []);
3126
+ diffActions(patches, {
3127
+ nodeId: node.id,
3128
+ group: "exit"
3129
+ }, previous.data.exit ?? [], node.data.exit ?? []);
3130
+ }
3131
+ const rebuiltEdgeIds = collectRebuiltEdgeIds(prevGraph, nextGraph);
3132
+ const isRebuilt = (edge) => rebuiltEdgeIds.has(edge.id);
3133
+ for (const edge of prevGraph.edges) if (isRebuilt(edge)) patches.push({
3134
+ op: "deleteTransition",
3135
+ transitionId: edge.id
3136
+ });
3137
+ for (const edge of nextGraph.edges) if (isRebuilt(edge)) appendCreateTransitionPatches(patches, edge);
3138
+ for (const edge of nextGraph.edges) {
3139
+ if (isRebuilt(edge)) continue;
3140
+ const previous = prevEdgeById.get(edge.id);
3141
+ if (!previous) {
3142
+ appendCreateTransitionPatches(patches, edge);
3143
+ continue;
3144
+ }
3145
+ const transitionUpdate = buildTransitionUpdatePatch(previous, edge);
3146
+ if (transitionUpdate) patches.push(transitionUpdate);
3147
+ if (!previous.data.guard && edge.data.guard) patches.push({
3148
+ op: "setGuard",
3149
+ edgeId: edge.id,
3150
+ guard: edge.data.guard
3151
+ });
3152
+ else if (previous.data.guard && !edge.data.guard) patches.push({
3153
+ op: "deleteGuard",
3154
+ edgeId: edge.id
3155
+ });
3156
+ else if (!isEqual(previous.data.guard, edge.data.guard) && edge.data.guard) patches.push({
3157
+ op: "setGuard",
3158
+ edgeId: edge.id,
3159
+ guard: edge.data.guard
3160
+ });
3161
+ diffActions(patches, {
3162
+ edgeId: edge.id,
3163
+ group: "transition"
3164
+ }, previous.data.actions ?? [], edge.data.actions ?? []);
3165
+ }
3166
+ for (const edge of prevGraph.edges) if (!isRebuilt(edge) && !nextEdgeById.has(edge.id)) patches.push({
3167
+ op: "deleteTransition",
3168
+ transitionId: edge.id
3169
+ });
3170
+ if (!isEqual(prevGraph.data.context, nextGraph.data.context)) patches.push({
3171
+ op: "setContext",
3172
+ context: nextGraph.data.context ?? null
3173
+ });
3174
+ if (!isEqual(prevGraph.data.schemas, nextGraph.data.schemas)) patches.push({
3175
+ op: "updateSchemas",
3176
+ schemas: {
3177
+ context: nextGraph.data.schemas?.context ?? null,
3178
+ events: nextGraph.data.schemas?.events ?? null,
3179
+ input: nextGraph.data.schemas?.input ?? null,
3180
+ output: nextGraph.data.schemas?.output ?? null
3181
+ }
3182
+ });
3183
+ diffImplementations(patches, "action", prevGraph, nextGraph);
3184
+ diffImplementations(patches, "guard", prevGraph, nextGraph);
3185
+ diffImplementations(patches, "actor", prevGraph, nextGraph);
3186
+ diffImplementations(patches, "delay", prevGraph, nextGraph);
3187
+ return {
3188
+ patches,
3189
+ unsupportedChanges
3190
+ };
3191
+ }
3192
+ const UNMATCHED_ID_PREFIX = "__diff_unmatched_";
3193
+ function createIdAllocator(reserved) {
3194
+ const taken = new Set(reserved);
3195
+ let counter = 0;
3196
+ return {
3197
+ claim(preferredId) {
3198
+ if (!taken.has(preferredId)) {
3199
+ taken.add(preferredId);
3200
+ return preferredId;
3201
+ }
3202
+ let candidate = `${UNMATCHED_ID_PREFIX}${counter++}`;
3203
+ while (taken.has(candidate)) candidate = `${UNMATCHED_ID_PREFIX}${counter++}`;
3204
+ taken.add(candidate);
3205
+ return candidate;
3206
+ },
3207
+ reserve(id) {
3208
+ taken.add(id);
3209
+ },
3210
+ isTaken(id) {
3211
+ return taken.has(id);
3212
+ }
3213
+ };
3214
+ }
3215
+ function assignAlignedIds(compareEntities, baseIds, baseIdBySemanticId) {
3216
+ const baseIdSet = new Set(baseIds);
3217
+ const assigned = /* @__PURE__ */ new Map();
3218
+ const allocator = createIdAllocator([]);
3219
+ for (const entity of compareEntities) if (baseIdSet.has(entity.id)) {
3220
+ allocator.reserve(entity.id);
3221
+ assigned.set(entity.id, entity.id);
3222
+ }
3223
+ for (const entity of compareEntities) {
3224
+ if (assigned.has(entity.id)) continue;
3225
+ const matchedBaseId = baseIdBySemanticId.get(entity.semanticId);
3226
+ if (matchedBaseId !== void 0 && !allocator.isTaken(matchedBaseId)) {
3227
+ allocator.reserve(matchedBaseId);
3228
+ assigned.set(entity.id, matchedBaseId);
3229
+ }
3230
+ }
3231
+ for (const entity of compareEntities) {
3232
+ if (assigned.has(entity.id)) continue;
3233
+ assigned.set(entity.id, allocator.claim(entity.id));
3234
+ }
3235
+ return assigned;
3236
+ }
3237
+ /**
3238
+ * Rewrites compare entity ids to the corresponding base ids.
3239
+ *
3240
+ * Shared raw ids win, then semantic ids, then collision-free compare ids.
3241
+ * Normalization must preserve entity array order so semantic ids can be mapped
3242
+ * back to the caller's original graph.
3243
+ */
3244
+ function alignCompareGraphIds(base, compare, semanticBase, semanticCompare) {
3245
+ const baseNodeIds = new Map(semanticBase.nodes.map((node, index) => [node.id, base.nodes[index].id]));
3246
+ const baseEdgeIds = new Map(semanticBase.edges.map((edge, index) => [edge.id, base.edges[index].id]));
3247
+ const compareNodeIds = assignAlignedIds(compare.nodes.map((node, index) => ({
3248
+ id: node.id,
3249
+ semanticId: semanticCompare.nodes[index].id
3250
+ })), base.nodes.map((node) => node.id), baseNodeIds);
3251
+ const compareEdgeIds = assignAlignedIds(compare.edges.map((edge, index) => ({
3252
+ id: edge.id,
3253
+ semanticId: semanticCompare.edges[index].id
3254
+ })), base.edges.map((edge) => edge.id), baseEdgeIds);
3255
+ const mapNodeId = (id) => compareNodeIds.get(id) ?? id;
3256
+ const aligned = structuredClone(compare);
3257
+ if (aligned.initialNodeId) aligned.initialNodeId = mapNodeId(aligned.initialNodeId);
3258
+ for (const node of aligned.nodes) {
3259
+ if (node.parentId) node.parentId = mapNodeId(node.parentId);
3260
+ if (node.initialNodeId) node.initialNodeId = mapNodeId(node.initialNodeId);
3261
+ if (node.data?.initialId) node.data.initialId = mapNodeId(node.data.initialId);
3262
+ node.id = mapNodeId(node.id);
3263
+ }
3264
+ for (const edge of aligned.edges) {
3265
+ edge.sourceId = mapNodeId(edge.sourceId);
3266
+ edge.targetId = mapNodeId(edge.targetId);
3267
+ edge.id = compareEdgeIds.get(edge.id) ?? edge.id;
3268
+ }
3269
+ for (const annotation of aligned.annotations ?? []) {
3270
+ const annotationData = annotation.data;
3271
+ if (!annotationData?.referenceIds) continue;
3272
+ annotationData.referenceIds = annotationData.referenceIds.map((id) => annotation.type === "edge" ? compareEdgeIds.get(id) ?? id : mapNodeId(id));
3273
+ }
3274
+ return aligned;
3275
+ }
2359
3276
  function isAutoGeneratedId(id) {
2360
3277
  return !!id && id.startsWith("$auto-");
2361
3278
  }
@@ -2472,7 +3389,7 @@ function stripExportDefault(code) {
2472
3389
  return trimmed;
2473
3390
  }
2474
3391
  const XSTATE_V5_PROFILE = "@statelyai/xstate@5.30.0";
2475
- const XSTATE_V6_PROFILE = "@statelyai/xstate@6.0.0-alpha.47";
3392
+ const XSTATE_V6_PROFILE = "@statelyai/xstate@6.0.0-alpha.51";
2476
3393
  const LEGACY_MACHINE_PROFILES = ["xstate-v5", "xstate-v6-alpha"];
2477
3394
  function normalizeMachineProfile(profile) {
2478
3395
  return profile === "xstate-v5" ? XSTATE_V5_PROFILE : profile === "xstate-v6-alpha" ? XSTATE_V6_PROFILE : profile;
@@ -2618,7 +3535,7 @@ function deepSimplify(config) {
2618
3535
  return config;
2619
3536
  }
2620
3537
  function buildMeta(meta, color) {
2621
- if (isCodeExpression$1(meta)) return meta;
3538
+ if (isCodeExpression$3(meta)) return meta;
2622
3539
  const result = {};
2623
3540
  if (meta) {
2624
3541
  for (const [k, v] of Object.entries(meta)) if (v !== void 0 && v !== null) result[k] = v;
@@ -2626,7 +3543,7 @@ function buildMeta(meta, color) {
2626
3543
  if (color) result["@statelyai.color"] = color;
2627
3544
  return Object.keys(result).length > 0 ? result : void 0;
2628
3545
  }
2629
- function isCodeExpression$1(value) {
3546
+ function isCodeExpression$3(value) {
2630
3547
  return Boolean(value && typeof value === "object" && !Array.isArray(value) && value["@type"] === "code" && typeof value.expr === "string");
2631
3548
  }
2632
3549
  /** Format event param — supports { type: string } (new) and plain string (legacy) */
@@ -2637,7 +3554,7 @@ function formatEventParam(event) {
2637
3554
  }
2638
3555
  function formatStringParam(value) {
2639
3556
  if (typeof value === "string") return `'${value}'`;
2640
- return isCodeExpression$1(value) ? serializeJS(value) : "undefined";
3557
+ return isCodeExpression$3(value) ? serializeJS(value) : "undefined";
2641
3558
  }
2642
3559
  function formatInlineObject(value) {
2643
3560
  return `{ ${Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => `${formatObjectKey(key)}: ${serializeJS(item)}`).join(", ")} }`;
@@ -2775,6 +3692,7 @@ const XSTATE_BUILT_IN_ACTIONS = {
2775
3692
  importKind: "named",
2776
3693
  paramsSchema: builtInActionParamSchemas["xstate.assign"],
2777
3694
  emit(params) {
3695
+ if (isCodeExpression$3(params?.assignment)) return `assign(${serializeJS(params.assignment)})`;
2778
3696
  const assignments = params?.assignment && typeof params.assignment === "object" && !Array.isArray(params.assignment) ? params.assignment : params;
2779
3697
  const entries = Object.entries(assignments ?? {}).filter(([k, v]) => k && v !== void 0);
2780
3698
  if (entries.length === 0) return "assign({})";
@@ -2886,6 +3804,7 @@ function graphToMachineConfig(graph, options = {}) {
2886
3804
  ...inv.output !== void 0 ? { output: inv.output } : void 0
2887
3805
  })) } : void 0,
2888
3806
  ...node.data.output !== void 0 ? { output: node.data.output } : void 0,
3807
+ ...node.data.schemas ? { schemas: node.data.schemas } : void 0,
2889
3808
  ...tags?.length ? { tags: tags.map(tagToString) } : void 0,
2890
3809
  ...showDescriptions && node.data.description ? { description: node.data.description } : void 0,
2891
3810
  ...showMeta && node.data.meta && Object.keys(node.data.meta).length > 0 ? { meta: node.data.meta } : void 0,
@@ -3005,6 +3924,8 @@ function graphToMachineConfig(graph, options = {}) {
3005
3924
  if (!rootNode) throw new Error("No root node found");
3006
3925
  getNodeConfig(rootNode);
3007
3926
  if (graph.data.context !== void 0 && graph.data.context !== null) config.context = graph.data.context;
3927
+ if (graph.data.version) config.version = graph.data.version;
3928
+ if (graph.data.options?.maxIterations !== void 0) config.options = { maxIterations: graph.data.options.maxIterations };
3008
3929
  return deepSimplify(config);
3009
3930
  }
3010
3931
  const INLINE_EXPRESSION_DIRECTIVE_FIELDS = [
@@ -4160,16 +5081,27 @@ function isCreateMachineCall(node) {
4160
5081
  return false;
4161
5082
  }
4162
5083
  function isMachineFactoryName(name) {
4163
- return name === "createMachine" || name === "createMachineFromConfig";
4164
- }
4165
- function setupCallForCreateMachine(node, bindings) {
4166
- if (!ts.isPropertyAccessExpression(node.expression)) return null;
4167
- let receiver = unwrapExpression(node.expression.expression);
4168
- if (ts.isIdentifier(receiver)) {
4169
- const binding = bindings.get(receiver.text);
4170
- if (binding && !ts.isFunctionDeclaration(binding)) receiver = unwrapExpression(binding);
4171
- }
4172
- return ts.isCallExpression(receiver) && ts.isIdentifier(receiver.expression) && receiver.expression.text === "setup" ? receiver : null;
5084
+ return name === "createMachine" || name === "createMachineFromConfig" || name === "createFSM";
5085
+ }
5086
+ function setupConfigExpressionsForCreateMachine(node, bindings) {
5087
+ if (!ts.isPropertyAccessExpression(node.expression)) return [];
5088
+ const findSetupConfigs = (value, seen = /* @__PURE__ */ new Set()) => {
5089
+ const receiver = unwrapExpression(value);
5090
+ if (ts.isIdentifier(receiver)) {
5091
+ if (seen.has(receiver.text)) return [];
5092
+ seen.add(receiver.text);
5093
+ const binding = bindings.get(receiver.text);
5094
+ return binding && !ts.isFunctionDeclaration(binding) ? findSetupConfigs(binding, seen) : [];
5095
+ }
5096
+ if (!ts.isCallExpression(receiver)) return [];
5097
+ if (ts.isIdentifier(receiver.expression) && receiver.expression.text === "setup") return receiver.arguments[0] ? [receiver.arguments[0]] : [];
5098
+ if (ts.isPropertyAccessExpression(receiver.expression) && receiver.expression.name.text === "extend") {
5099
+ const base = findSetupConfigs(receiver.expression.expression, seen);
5100
+ return receiver.arguments[0] ? [...base, receiver.arguments[0]] : base;
5101
+ }
5102
+ return [];
5103
+ };
5104
+ return findSetupConfigs(node.expression.expression);
4173
5105
  }
4174
5106
  function hasV6Syntax(source) {
4175
5107
  const file = sourceFile(source);
@@ -4221,14 +5153,14 @@ function hasV6Syntax(source) {
4221
5153
  }
4222
5154
  function visitMachineCalls(node) {
4223
5155
  if (ts.isCallExpression(node) && isCreateMachineCall(node)) {
4224
- if ((ts.isIdentifier(node.expression) ? node.expression.text : ts.isPropertyAccessExpression(node.expression) ? node.expression.name.text : void 0) === "createMachineFromConfig") {
5156
+ const factoryName = ts.isIdentifier(node.expression) ? node.expression.text : ts.isPropertyAccessExpression(node.expression) ? node.expression.name.text : void 0;
5157
+ if (factoryName === "createMachineFromConfig" || factoryName === "createFSM") {
4225
5158
  found = true;
4226
5159
  return;
4227
5160
  }
4228
5161
  const config = node.arguments[0];
4229
5162
  if (config) visitSyntax(config);
4230
- const setupConfig = setupCallForCreateMachine(node, bindings)?.arguments[0];
4231
- if (setupConfig) visitSyntax(setupConfig);
5163
+ for (const setupConfig of setupConfigExpressionsForCreateMachine(node, bindings)) visitSyntax(setupConfig);
4232
5164
  return;
4233
5165
  }
4234
5166
  ts.forEachChild(node, visitMachineCalls);
@@ -4241,24 +5173,93 @@ function detectXStateSourceProfile(source) {
4241
5173
  }
4242
5174
  function xstateSourceToConfig(source, options = {}) {
4243
5175
  const [config] = extractXStateMachineConfigs(source, options);
4244
- if (!config) throw new Error("No createMachine(...) or setup(...).createMachine(...) call found.");
5176
+ if (!config) throw new Error("No createMachine(...), createFSM(...), or setup factory call found.");
4245
5177
  return config;
4246
5178
  }
4247
5179
  /**
4248
5180
  * Extract every XState machine config from source without executing code.
4249
5181
  * XState 5/6 syntax is inferred structurally unless a profile is supplied.
4250
5182
  */
4251
- function extractXStateMachineConfigs(source, options = {}) {
5183
+ function extractXStateMachineConfigEntries(source, options = {}) {
4252
5184
  const file = sourceFile(source);
4253
5185
  const bindings = collectBindings(file);
4254
5186
  const imports = collectSourceImports(file);
4255
5187
  const found = [];
5188
+ let machineIndex = 0;
4256
5189
  const profile = options.profile === "auto" || !options.profile ? detectXStateSourceProfile(source) : options.profile;
5190
+ const isRecordValue = (value) => !!value && typeof value === "object" && !Array.isArray(value);
5191
+ const mergeSetupStateSchemas = (machineStates, setupStates) => {
5192
+ if (!isRecordValue(machineStates) || !isRecordValue(setupStates)) return machineStates;
5193
+ return Object.fromEntries(Object.entries(machineStates).map(([key, machineState]) => {
5194
+ if (!isRecordValue(machineState)) return [key, machineState];
5195
+ const contract = isRecordValue(setupStates[key]) ? setupStates[key] : void 0;
5196
+ if (!contract) return [key, machineState];
5197
+ const contractSchemas = isRecordValue(contract.schemas) ? contract.schemas : {};
5198
+ const stateSchemas = isRecordValue(machineState.schemas) ? machineState.schemas : {};
5199
+ const schemas = Object.fromEntries([
5200
+ "input",
5201
+ "context",
5202
+ "output"
5203
+ ].flatMap((schemaKey) => {
5204
+ const schema = stateSchemas[schemaKey] ?? contractSchemas[schemaKey];
5205
+ return schema === void 0 ? [] : [[schemaKey, schema]];
5206
+ }));
5207
+ return [key, {
5208
+ ...machineState,
5209
+ ...Object.keys(schemas).length ? { schemas } : {},
5210
+ states: mergeSetupStateSchemas(machineState.states, contract.states)
5211
+ }];
5212
+ }));
5213
+ };
5214
+ const mergeSetupRecords = (base, extension) => {
5215
+ const mergeMap = (left, right) => {
5216
+ if (!isRecordValue(left) && !isRecordValue(right)) return void 0;
5217
+ const merged = {
5218
+ ...isRecordValue(left) ? left : {},
5219
+ ...isRecordValue(right) ? right : {}
5220
+ };
5221
+ return Object.keys(merged).length ? merged : void 0;
5222
+ };
5223
+ const schemas = mergeMap(base.schemas, extension.schemas);
5224
+ if (isRecordValue(schemas)) for (const key of [
5225
+ "events",
5226
+ "internalEvents",
5227
+ "actions",
5228
+ "guards",
5229
+ "emitted",
5230
+ "children"
5231
+ ]) {
5232
+ const merged = mergeMap(isRecordValue(base.schemas) ? base.schemas[key] : void 0, isRecordValue(extension.schemas) ? extension.schemas[key] : void 0);
5233
+ if (merged !== void 0) schemas[key] = merged;
5234
+ else delete schemas[key];
5235
+ }
5236
+ const result = {
5237
+ ...base,
5238
+ ...extension
5239
+ };
5240
+ if (schemas !== void 0) result.schemas = schemas;
5241
+ else delete result.schemas;
5242
+ for (const key of [
5243
+ "states",
5244
+ "actions",
5245
+ "actors",
5246
+ "actorSources",
5247
+ "guards",
5248
+ "delays"
5249
+ ]) {
5250
+ const merged = mergeMap(base[key], extension[key]);
5251
+ if (merged !== void 0) result[key] = merged;
5252
+ else delete result[key];
5253
+ }
5254
+ return result;
5255
+ };
4257
5256
  function visit(node) {
4258
5257
  if (!ts.isCallExpression(node) || !isCreateMachineCall(node)) {
4259
5258
  ts.forEachChild(node, visit);
4260
5259
  return;
4261
5260
  }
5261
+ const sourceMachineIndex = machineIndex;
5262
+ machineIndex += 1;
4262
5263
  const arg = node.arguments[0];
4263
5264
  if (!arg) return;
4264
5265
  const value = expressionToValue(arg, bindings, {
@@ -4267,22 +5268,32 @@ function extractXStateMachineConfigs(source, options = {}) {
4267
5268
  imports
4268
5269
  });
4269
5270
  if (value && typeof value === "object" && !Array.isArray(value)) {
4270
- const setupArg = setupCallForCreateMachine(node, bindings)?.arguments[0];
4271
- const setupValue = setupArg ? expressionToValue(setupArg, bindings, {
4272
- v6: profile === "xstate-v6-alpha",
4273
- setupValue: true,
4274
- imports
4275
- }) : null;
4276
- const setupRecord = setupValue && typeof setupValue === "object" && !Array.isArray(setupValue) ? Object.fromEntries(Object.entries(setupValue).filter(([, item]) => !(item && typeof item === "object" && !Array.isArray(item) && Object.keys(item).length === 0))) : {};
5271
+ const { states: setupStates, ...setupWithoutStates } = setupConfigExpressionsForCreateMachine(node, bindings).reduce((merged, setupArg) => {
5272
+ const setupValue = expressionToValue(setupArg, bindings, {
5273
+ v6: profile === "xstate-v6-alpha",
5274
+ setupValue: true,
5275
+ imports
5276
+ });
5277
+ if (!isRecordValue(setupValue)) return merged;
5278
+ return mergeSetupRecords(merged, setupValue);
5279
+ }, {});
5280
+ const machineValue = value;
4277
5281
  found.push({
4278
- ...setupRecord,
4279
- ...value
5282
+ machineIndex: sourceMachineIndex,
5283
+ config: {
5284
+ ...setupWithoutStates,
5285
+ ...machineValue,
5286
+ states: mergeSetupStateSchemas(machineValue.states, setupStates)
5287
+ }
4280
5288
  });
4281
5289
  }
4282
5290
  }
4283
5291
  visit(file);
4284
5292
  return found;
4285
5293
  }
5294
+ function extractXStateMachineConfigs(source, options = {}) {
5295
+ return extractXStateMachineConfigEntries(source, options).map(({ config }) => config);
5296
+ }
4286
5297
  function jsonSchemaToTSType(schema) {
4287
5298
  if (!schema) return "unknown";
4288
5299
  if (schema.enum) return schema.enum.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
@@ -4491,6 +5502,7 @@ function graphToXStateTS(graph, options = {}) {
4491
5502
  const impls = filterInlineImplementations(graph.data.implementations);
4492
5503
  const supportsTypeSyntax = targetLanguage === "typescript";
4493
5504
  const hasSchemas = !!(schemas && (schemas.context || schemas.events || schemas.input || schemas.output));
5505
+ const hasStateSchemas = graph.nodes.some((node) => node.data.schemas);
4494
5506
  const hasActions = !!impls?.actions.length;
4495
5507
  const hasGuards = !!impls?.guards.length;
4496
5508
  const hasActors = !!impls?.actors.length;
@@ -4509,10 +5521,11 @@ function graphToXStateTS(graph, options = {}) {
4509
5521
  implementationImports,
4510
5522
  codeImports,
4511
5523
  xstateVersion,
4512
- usesTypes: xstateVersion === 6 && supportsTypeSyntax && hasSchemas && xstateV6SchemaFormat === "types",
4513
- usesZod: xstateVersion === 6 && hasSchemas && xstateV6SchemaFormat === "zod"
5524
+ usesTypes: xstateVersion === 6 && supportsTypeSyntax && (hasSchemas || hasStateSchemas) && xstateV6SchemaFormat === "types",
5525
+ usesZod: xstateVersion === 6 && (hasSchemas || hasStateSchemas) && xstateV6SchemaFormat === "zod"
4514
5526
  });
4515
5527
  const machineConfig = xstateVersion === 6 ? toV6MachineConfig(graphToMachineConfig(graph, configOptions)) : toV5MachineConfig(graphToMachineConfig(graph, configOptions));
5528
+ if (xstateVersion === 6) stripStateSchemas(machineConfig);
4516
5529
  let machineExpr;
4517
5530
  if (hasSetup) {
4518
5531
  const setupObj = buildSetupObject(schemas, impls, {
@@ -4520,6 +5533,13 @@ function graphToXStateTS(graph, options = {}) {
4520
5533
  xstateVersion,
4521
5534
  xstateV6SchemaFormat
4522
5535
  });
5536
+ if (xstateVersion === 6) {
5537
+ const states = buildV6SetupStates(graph, {
5538
+ includeTypeSyntax: supportsTypeSyntax,
5539
+ xstateV6SchemaFormat
5540
+ });
5541
+ if (states) setupObj.states = states;
5542
+ }
4523
5543
  const configStr = serializeJS(machineConfig, 2);
4524
5544
  machineExpr = `setup(${serializeJS(setupObj, 0)}).createMachine(${configStr})`;
4525
5545
  } else machineExpr = `createMachine(${serializeJS(machineConfig, 0)})`;
@@ -4536,6 +5556,51 @@ function graphToXStateTS(graph, options = {}) {
4536
5556
  }
4537
5557
  return lines.join("\n") + "\n";
4538
5558
  }
5559
+ function stripStateSchemas(config) {
5560
+ delete config.schemas;
5561
+ const states = config.states;
5562
+ if (!states || typeof states !== "object" || Array.isArray(states)) return;
5563
+ for (const state of Object.values(states)) if (state && typeof state === "object" && !Array.isArray(state)) stripStateSchemas(state);
5564
+ }
5565
+ function buildV6SetupStates(graph, options) {
5566
+ const root = graph.nodes.find((node) => node.parentId == null);
5567
+ if (!root) return void 0;
5568
+ const buildState = (nodeId) => {
5569
+ const node = graph.nodes.find((candidate) => candidate.id === nodeId);
5570
+ if (!node) return void 0;
5571
+ const result = {};
5572
+ const schemas = buildV6StateSchemasBlock(node.data.schemas, options);
5573
+ if (schemas) result.schemas = schemas;
5574
+ const childStates = Object.fromEntries(graph.nodes.filter((candidate) => candidate.parentId === node.id).flatMap((child) => {
5575
+ const contract = buildState(child.id);
5576
+ return contract ? [[child.data.key, contract]] : [];
5577
+ }));
5578
+ if (Object.keys(childStates).length) result.states = childStates;
5579
+ return Object.keys(result).length ? result : void 0;
5580
+ };
5581
+ const states = Object.fromEntries(graph.nodes.filter((node) => node.parentId === root.id).flatMap((node) => {
5582
+ const contract = buildState(node.id);
5583
+ return contract ? [[node.data.key, contract]] : [];
5584
+ }));
5585
+ return Object.keys(states).length ? states : void 0;
5586
+ }
5587
+ function buildV6StateSchemasBlock(schemas, options) {
5588
+ if (!schemas) return void 0;
5589
+ const result = {};
5590
+ const contextSchema = schemas.context;
5591
+ if (options.xstateV6SchemaFormat === "zod") {
5592
+ const context = contextSchemaToZod(contextSchema);
5593
+ if (context) result.context = raw(context);
5594
+ if (schemas.input) result.input = raw(jsonSchemaToZod(schemas.input));
5595
+ if (schemas.output) result.output = raw(jsonSchemaToZod(schemas.output));
5596
+ } else if (options.includeTypeSyntax) {
5597
+ const context = contextSchemaToTSType(contextSchema);
5598
+ if (context) result.context = raw(`types<${context}>()`);
5599
+ if (schemas.input) result.input = raw(`types<${jsonSchemaToTSType(schemas.input)}>()`);
5600
+ if (schemas.output) result.output = raw(`types<${jsonSchemaToTSType(schemas.output)}>()`);
5601
+ }
5602
+ return Object.keys(result).length ? result : void 0;
5603
+ }
4539
5604
  function filterInlineImplementations(impls) {
4540
5605
  if (!impls) return impls;
4541
5606
  return {
@@ -5283,6 +6348,108 @@ function isCompleteFunctionExpression(code) {
5283
6348
  if (!expression) return false;
5284
6349
  return ts.isFunctionExpression(expression) || ts.isArrowFunction(expression);
5285
6350
  }
6351
+ function getXStateFSMCompatibilityIssues(graph) {
6352
+ const root = graph.nodes.find((node) => node.parentId == null);
6353
+ if (!root) return ["missing root state"];
6354
+ const states = graph.nodes.filter((node) => node.parentId === root.id);
6355
+ const stateIds = new Set(states.map((node) => node.id));
6356
+ const issues = /* @__PURE__ */ new Set();
6357
+ if (!root.data.initialId || !stateIds.has(root.data.initialId)) issues.add("missing initial state");
6358
+ if (graph.nodes.some((node) => node.parentId !== null && node.parentId !== root.id)) issues.add("nested states");
6359
+ if (states.some((node) => node.data.type && node.data.type !== "normal")) issues.add("non-atomic state types");
6360
+ if (graph.nodes.some((node) => node.data.entry?.length || node.data.exit?.length || node.data.invokes?.length || node.data.timeout !== void 0 || node.data.route !== void 0 || node.data.output !== void 0 || node.data.initialInput !== void 0)) issues.add("state effects, invokes, timeouts, routes, or outputs");
6361
+ if (graph.nodes.some((node) => node.data.schemas?.input || node.data.schemas?.output) || graph.data.schemas?.input || graph.data.schemas?.output) issues.add("input or output schemas");
6362
+ if (graph.data.version || graph.data.options) issues.add("machine version or runtime options");
6363
+ const eventCounts = /* @__PURE__ */ new Map();
6364
+ for (const edge of graph.edges.filter((edge) => stateIds.has(edge.sourceId))) {
6365
+ const key = `${edge.sourceId}:${edge.data.eventType}`;
6366
+ eventCounts.set(key, (eventCounts.get(key) ?? 0) + 1);
6367
+ if (!edge.data.eventType) issues.add("eventless transitions");
6368
+ if (!stateIds.has(edge.targetId) && edge.data.transitionType !== "targetless") issues.add("transitions outside the flat state set");
6369
+ if (edge.data.guard || edge.data.actions?.length || edge.data.matches || edge.data.input !== void 0 || edge.data.transitionType === "reenter") issues.add("guards, actions, matching, transition input, or reentry");
6370
+ if (isCodeExpression$2(edge.data.context)) issues.add("dynamic transition context");
6371
+ }
6372
+ if ([...eventCounts.values()].some((count) => count > 1)) issues.add("multiple transitions for one event");
6373
+ return [...issues];
6374
+ }
6375
+ function graphToXStateFSM(graph, options = {}) {
6376
+ const root = graph.nodes.find((node) => node.parentId == null);
6377
+ if (!root) throw new Error("No root node found");
6378
+ const states = graph.nodes.filter((node) => node.parentId === root.id);
6379
+ const stateById = new Map(states.map((node) => [node.id, node]));
6380
+ const initial = root.data.initialId ? stateById.get(root.data.initialId)?.data.key : void 0;
6381
+ if (!initial) throw new Error("Cannot export XState FSM without an initial state.");
6382
+ const schemaFormat = options.xstateV6SchemaFormat ?? "types";
6383
+ const setupConfig = buildSetupConfig(graph, states, schemaFormat);
6384
+ const config = {
6385
+ id: root.data.nodeId || graph.id,
6386
+ initial,
6387
+ context: graph.data.context ?? void 0,
6388
+ states: Object.fromEntries(states.map((state) => [state.data.key, buildState(graph, state, stateById)]))
6389
+ };
6390
+ const imports = [setupConfig ? "setup" : "createFSM"];
6391
+ if (schemaFormat === "types" && setupConfig) imports.push("types");
6392
+ const lines = [`import { ${imports.join(", ")} } from 'xstate/fsm';`];
6393
+ if (schemaFormat === "zod" && setupConfig) lines.push(`import { z } from 'zod';`);
6394
+ const expression = setupConfig ? `setup(${serializeJS(setupConfig, 0)}).createFSM(${serializeJS(config, 0)})` : `createFSM(${serializeJS(config, 0)})`;
6395
+ lines.push("", `const machine = ${expression};`);
6396
+ if ((options.exportStyle ?? "named") === "named") lines.push("", "export { machine };");
6397
+ else if (options.exportStyle === "default") lines.push("", "export default machine;");
6398
+ return `${lines.join("\n")}\n`;
6399
+ }
6400
+ function buildState(graph, state, stateById) {
6401
+ const on = {};
6402
+ for (const edge of graph.edges.filter((candidate) => candidate.sourceId === state.id)) {
6403
+ const eventType = edge.data.eventType;
6404
+ if (!eventType || on[eventType] !== void 0) continue;
6405
+ const transition = buildTransition$1(edge, stateById);
6406
+ if (transition !== void 0) on[eventType] = transition;
6407
+ }
6408
+ return Object.keys(on).length ? { on } : {};
6409
+ }
6410
+ function buildTransition$1(edge, stateById) {
6411
+ const target = edge.data.transitionType === "targetless" ? void 0 : stateById.get(edge.targetId)?.data.key;
6412
+ const context = isCodeExpression$2(edge.data.context) ? void 0 : edge.data.context;
6413
+ if (context !== void 0) return {
6414
+ target,
6415
+ context
6416
+ };
6417
+ return target;
6418
+ }
6419
+ function buildSetupConfig(graph, states, format) {
6420
+ const schemas = {};
6421
+ const rootContext = graph.data.schemas?.context;
6422
+ const rootEvents = graph.data.schemas?.events;
6423
+ if (format === "types") {
6424
+ const context = contextSchemaToTSType(rootContext);
6425
+ if (context) schemas.context = raw(`types<${context}>()`);
6426
+ if (rootEvents && Object.keys(rootEvents).length) schemas.events = Object.fromEntries(Object.entries(rootEvents).map(([eventType, schema]) => [eventType, raw(`types<${eventPayloadType(schema)}>()`)]));
6427
+ } else {
6428
+ const context = contextSchemaToZod(rootContext);
6429
+ if (context) schemas.context = raw(context);
6430
+ if (rootEvents && Object.keys(rootEvents).length) schemas.events = Object.fromEntries(Object.entries(rootEvents).map(([eventType, schema]) => [eventType, raw(eventSchemaToZod(schema))]));
6431
+ }
6432
+ const stateContracts = Object.fromEntries(states.flatMap((state) => {
6433
+ const context = format === "types" ? contextSchemaToTSType(state.data.schemas?.context) : contextSchemaToZod(state.data.schemas?.context);
6434
+ return context ? [[state.data.key, { schemas: { context: raw(format === "types" ? `types<${context}>()` : context) } }]] : [];
6435
+ }));
6436
+ const setup = {};
6437
+ if (Object.keys(schemas).length) setup.schemas = schemas;
6438
+ if (Object.keys(stateContracts).length) setup.states = stateContracts;
6439
+ return Object.keys(setup).length ? setup : void 0;
6440
+ }
6441
+ function eventPayloadType(schema) {
6442
+ const properties = Object.fromEntries(Object.entries(schema.properties ?? {}).filter(([key]) => key !== "type"));
6443
+ const required = schema.required?.filter((key) => key !== "type");
6444
+ return jsonSchemaToTSType({
6445
+ ...schema,
6446
+ properties,
6447
+ required
6448
+ });
6449
+ }
6450
+ function isCodeExpression$2(value) {
6451
+ return !!value && typeof value === "object" && !Array.isArray(value) && value["@type"] === "code";
6452
+ }
5286
6453
  const colorSchema = _enum([
5287
6454
  "green",
5288
6455
  "red",
@@ -5664,4 +6831,4 @@ function getScriptKind(fileName) {
5664
6831
  }
5665
6832
 
5666
6833
  //#endregion
5667
- export { RawCode as a, eventsSchemaToTSType as c, jsonSchemaToTSType as d, normalizeMachineProfile as f, xstateSourceToConfig as h, INLINE_EXPRESSION_DIRECTIVE_FIELDS as i, graphToMachineConfig as l, serializeJS as m, getStatelyPragma as n, contextSchemaToTSType as o, raw as p, upsertStatelyPragma as r, detectXStateSourceProfile as s, findStatelyPragmaAttachments as t, graphToXStateTS as u };
6834
+ export { normalizeMachineProfile as _, RawCode as a, xstateSourceToConfig as b, detectXStateSourceProfile as c, getXStateFSMCompatibilityIssues as d, graphChangeToPatchesResult as f, jsonSchemaToTSType as g, graphToXStateTS as h, INLINE_EXPRESSION_DIRECTIVE_FIELDS as i, diffGraphsSemantically as l, graphToXStateFSM as m, getStatelyPragma as n, alignCompareGraphIds as o, graphToMachineConfig as p, upsertStatelyPragma as r, contextSchemaToTSType as s, findStatelyPragmaAttachments as t, eventsSchemaToTSType as u, raw as v, serializeJS as y };