@statelyai/sdk 0.5.1 → 0.6.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.
package/dist/embed.d.mts CHANGED
@@ -1,4 +1,5 @@
1
- import { a as EmbedMode, c as ExportFormatMap, f as UploadResult, i as EmbedEventName, l as InitOptions, n as EmbedEventHandler, o as ExportCallOptions, r as EmbedEventMap, s as ExportFormat, t as CommentsConfig, u as MachineSourceLocations } from "./protocol-BPuwbNCz.mjs";
1
+ import { a as EmbedMode, c as ExportFormatMap, d as MachineSourceLocations, f as ProjectEmbedMachine, i as EmbedEventName, l as InitOptions, m as UploadResult, n as EmbedEventHandler, o as ExportCallOptions, r as EmbedEventMap, s as ExportFormat, t as CommentsConfig, u as MachineInitOptions } from "./protocol-CDoCcaIP.mjs";
2
+ import { AssetUploadAdapter } from "./assetStorage.mjs";
2
3
 
3
4
  //#region src/embed.d.ts
4
5
  interface AssetConfig {
@@ -7,9 +8,15 @@ interface AssetConfig {
7
8
  * Receives a real File object (reconstructed from serialized data).
8
9
  * Throwing or rejecting will show an error toast in the embed.
9
10
  */
10
- onUploadRequest: (file: File, context: {
11
+ onUploadRequest?: (file: File, context: {
11
12
  stateNodeId: string;
12
13
  }) => Promise<UploadResult>;
14
+ /**
15
+ * Storage adapter used by the embed upload bridge. This keeps the editor
16
+ * protocol storage-neutral while allowing integrations to plug in S3, R2,
17
+ * Supabase, or any other backing store.
18
+ */
19
+ adapter?: AssetUploadAdapter;
13
20
  /**
14
21
  * Accepted MIME types. Supports wildcards (e.g. 'image/*').
15
22
  * @default ['image/*']
@@ -21,10 +28,24 @@ interface AssetConfig {
21
28
  */
22
29
  maxFileSize?: number;
23
30
  }
24
- interface StatelyEmbedOptions {
31
+ interface StatelyEmbedOptions extends Partial<MachineInitOptions> {
25
32
  baseUrl: string;
26
33
  apiKey?: string;
27
34
  origin?: string;
35
+ /**
36
+ * Optional iframe to attach to immediately. Equivalent to calling
37
+ * `embed.attach(iframe)` after construction.
38
+ */
39
+ iframe?: HTMLIFrameElement;
40
+ /**
41
+ * Project mode: pass machines instead of `machine`. If set, an init is
42
+ * auto-sent on attach using these machines.
43
+ */
44
+ machines?: ProjectEmbedMachine[];
45
+ /** Project mode only — initially selected machine id. */
46
+ currentMachineId?: string;
47
+ /** Project mode only — initial comments keyed by machine id. */
48
+ commentsByMachineId?: Record<string, CommentsConfig>;
28
49
  /** Asset upload configuration. If omitted, files are stored as base64 data URLs. */
29
50
  assets?: AssetConfig;
30
51
  onReady?: () => void;
@@ -45,6 +66,10 @@ interface StatelyEmbed {
45
66
  init(options: InitOptions): void;
46
67
  /** Update the machine (shorthand for update message). */
47
68
  updateMachine(machine: unknown, format?: string, sourceLocations?: MachineSourceLocations): void;
69
+ /** Update the project machine list without re-creating the iframe. */
70
+ updateProject(machines: ProjectEmbedMachine[], currentMachineId?: string, commentsByMachineId?: Record<string, CommentsConfig>): void;
71
+ /** Select the active machine in project mode. */
72
+ selectMachine(machineId: string): void;
48
73
  /** Change the embed mode. */
49
74
  setMode(mode: EmbedMode): void;
50
75
  /** Change the embed theme. */
@@ -64,4 +89,4 @@ interface StatelyEmbed {
64
89
  }
65
90
  declare function createStatelyEmbed(options: StatelyEmbedOptions): StatelyEmbed;
66
91
  //#endregion
67
- export { AssetConfig, type CommentsConfig, type EmbedEventHandler, type EmbedEventMap, type EmbedEventName, type EmbedMode, type ExportCallOptions, type ExportFormat, type ExportFormatMap, type InitOptions, type MachineSourceLocations, StatelyEmbed, StatelyEmbedOptions, type UploadResult, createStatelyEmbed };
92
+ export { AssetConfig, type CommentsConfig, type EmbedEventHandler, type EmbedEventMap, type EmbedEventName, type EmbedMode, type ExportCallOptions, type ExportFormat, type ExportFormatMap, type InitOptions, type MachineInitOptions, type MachineSourceLocations, type ProjectEmbedMachine, StatelyEmbed, StatelyEmbedOptions, type UploadResult, createStatelyEmbed };
package/dist/embed.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as toInitMessage, i as createPendingExportManager, r as createEventRegistry, t as createPostMessageTransport } from "./transport-DoCHBLTu.mjs";
1
+ import { a as toInitMessage, i as createPendingExportManager, r as createEventRegistry, t as createPostMessageTransport } from "./transport-C0eTgNNu.mjs";
2
2
 
3
3
  //#region src/embed.ts
4
4
  function buildEmbedUrl(options) {
@@ -7,6 +7,32 @@ function buildEmbedUrl(options) {
7
7
  if (options.apiKey) url.searchParams.set("api_key", options.apiKey);
8
8
  return url.toString();
9
9
  }
10
+ function extractInitOptions(options) {
11
+ if (options.machines) return {
12
+ machines: options.machines,
13
+ currentMachineId: options.currentMachineId,
14
+ mode: options.mode,
15
+ theme: options.theme,
16
+ readOnly: options.readOnly,
17
+ depth: options.depth,
18
+ panels: options.panels,
19
+ commentsByMachineId: options.commentsByMachineId,
20
+ unsavedIndicator: options.unsavedIndicator
21
+ };
22
+ if (options.machine !== void 0) return {
23
+ machine: options.machine,
24
+ format: options.format,
25
+ mode: options.mode,
26
+ theme: options.theme,
27
+ readOnly: options.readOnly,
28
+ depth: options.depth,
29
+ panels: options.panels,
30
+ comments: options.comments,
31
+ sourceLocations: options.sourceLocations,
32
+ unsavedIndicator: options.unsavedIndicator
33
+ };
34
+ return null;
35
+ }
10
36
  function createStatelyEmbed(options) {
11
37
  const embedUrl = buildEmbedUrl(options);
12
38
  const targetOrigin = options.origin ?? "*";
@@ -17,6 +43,13 @@ function createStatelyEmbed(options) {
17
43
  const pendingMessages = [];
18
44
  const events = createEventRegistry();
19
45
  const exportManager = createPendingExportManager((message) => send(message));
46
+ const assetUploadAdapter = options.assets?.adapter;
47
+ const uploadAsset = options.assets?.onUploadRequest ? (file, context) => options.assets.onUploadRequest(file, context) : assetUploadAdapter ? (file, context) => assetUploadAdapter.upload({
48
+ file,
49
+ ...context
50
+ }) : void 0;
51
+ const assetAccept = options.assets?.accept ?? assetUploadAdapter?.accept;
52
+ const assetMaxFileSize = options.assets?.maxFileSize ?? assetUploadAdapter?.maxFileSize;
20
53
  function send(msg) {
21
54
  if (!transport?.ready) {
22
55
  pendingMessages.push(msg);
@@ -37,11 +70,11 @@ function createStatelyEmbed(options) {
37
70
  case "@statelyai.ready": {
38
71
  const ready = data;
39
72
  flush();
40
- if (options.assets?.onUploadRequest) send({
73
+ if (uploadAsset) send({
41
74
  type: "@statelyai.uploadCapabilities",
42
75
  enabled: true,
43
- accept: options.assets.accept,
44
- maxFileSize: options.assets.maxFileSize
76
+ accept: assetAccept,
77
+ maxFileSize: assetMaxFileSize
45
78
  });
46
79
  options.onReady?.();
47
80
  events.emit("ready", { version: ready.version });
@@ -52,6 +85,7 @@ function createStatelyEmbed(options) {
52
85
  options.onLoaded?.(loaded.graph);
53
86
  events.emit("loaded", {
54
87
  graph: loaded.graph,
88
+ machineId: loaded.machineId,
55
89
  sourceLocations: loaded.sourceLocations
56
90
  });
57
91
  break;
@@ -62,6 +96,7 @@ function createStatelyEmbed(options) {
62
96
  events.emit("change", {
63
97
  graph: change.graph,
64
98
  machineConfig: change.machineConfig,
99
+ machineId: change.machineId,
65
100
  patches: change.patches,
66
101
  sourceLocations: change.sourceLocations
67
102
  });
@@ -73,12 +108,16 @@ function createStatelyEmbed(options) {
73
108
  events.emit("save", {
74
109
  graph: save.graph,
75
110
  machineConfig: save.machineConfig,
111
+ machineId: save.machineId,
76
112
  patches: save.patches,
77
113
  validations: save.validations,
78
114
  sourceLocations: save.sourceLocations
79
115
  });
80
116
  break;
81
117
  }
118
+ case "@statelyai.project.machineSelected":
119
+ events.emit("machineSelected", { machineId: String(data.machineId) });
120
+ break;
82
121
  case "@statelyai.retrieved": {
83
122
  const retrieved = data;
84
123
  exportManager.resolve(retrieved.requestId, retrieved.data);
@@ -97,7 +136,7 @@ function createStatelyEmbed(options) {
97
136
  }
98
137
  case "@statelyai.uploadRequest": {
99
138
  const req = data;
100
- if (!options.assets?.onUploadRequest) {
139
+ if (!uploadAsset) {
101
140
  send({
102
141
  type: "@statelyai.error",
103
142
  requestId: req.requestId,
@@ -106,7 +145,7 @@ function createStatelyEmbed(options) {
106
145
  });
107
146
  break;
108
147
  }
109
- const maxSize = options.assets.maxFileSize ?? 10485760;
148
+ const maxSize = assetMaxFileSize ?? 10485760;
110
149
  if (req.file.size > maxSize) {
111
150
  send({
112
151
  type: "@statelyai.error",
@@ -119,8 +158,7 @@ function createStatelyEmbed(options) {
119
158
  const binary = atob(req.file.data);
120
159
  const bytes = new Uint8Array(binary.length);
121
160
  for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
122
- const file = new File([bytes], req.file.name, { type: req.file.mimeType });
123
- options.assets.onUploadRequest(file, { stateNodeId: req.stateNodeId }).then((result) => {
161
+ uploadAsset(new File([bytes], req.file.name, { type: req.file.mimeType }), { stateNodeId: req.stateNodeId }).then((result) => {
124
162
  send({
125
163
  type: "@statelyai.uploadResponse",
126
164
  requestId: req.requestId,
@@ -151,7 +189,7 @@ function createStatelyEmbed(options) {
151
189
  nextTransport.onMessage(handleMessage);
152
190
  nextTransport.onReady(flush);
153
191
  }
154
- return {
192
+ const embed = {
155
193
  attach(el) {
156
194
  if (destroyed) return;
157
195
  const currentSrc = el.getAttribute("src");
@@ -190,6 +228,20 @@ function createStatelyEmbed(options) {
190
228
  sourceLocations
191
229
  });
192
230
  },
231
+ updateProject(machines, currentMachineId, commentsByMachineId) {
232
+ send({
233
+ type: "@statelyai.project.update",
234
+ machines,
235
+ currentMachineId,
236
+ commentsByMachineId
237
+ });
238
+ },
239
+ selectMachine(machineId) {
240
+ send({
241
+ type: "@statelyai.project.selectMachine",
242
+ machineId
243
+ });
244
+ },
193
245
  setMode(mode) {
194
246
  send({
195
247
  type: "@statelyai.setMode",
@@ -236,6 +288,10 @@ function createStatelyEmbed(options) {
236
288
  iframe = null;
237
289
  }
238
290
  };
291
+ if (options.iframe) embed.attach(options.iframe);
292
+ const autoInit = extractInitOptions(options);
293
+ if (autoInit) embed.init(autoInit);
294
+ return embed;
239
295
  }
240
296
 
241
297
  //#endregion
package/dist/graph.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { _ as studioMachineConverter, a as StatelyGraphData, c as StatelyInvoke, d as StudioAction, f as StudioEdge, g as fromStudioMachine, h as StudioNode, i as StatelyGraph, l as StatelyNodeData, m as StudioMachine, n as StatelyActorImplementation, o as StatelyGuard, p as StudioEventTypeData, r as StatelyEdgeData, s as StatelyImplementation, t as StatelyAction, u as StatelyTagImplementation, v as toStudioMachine } from "./graph-BfezxFKJ.mjs";
1
+ import { _ as studioMachineConverter, a as StatelyGraphData, c as StatelyInvoke, d as StudioAction, f as StudioEdge, g as fromStudioMachine, h as StudioNode, i as StatelyGraph, l as StatelyNodeData, m as StudioMachine, n as StatelyActorImplementation, o as StatelyGuard, p as StudioEventTypeData, r as StatelyEdgeData, s as StatelyImplementation, t as StatelyAction, u as StatelyTagImplementation, v as toStudioMachine } from "./graph-DpBGHZwl.mjs";
2
2
  export { StatelyAction, StatelyActorImplementation, StatelyEdgeData, StatelyGraph, StatelyGraphData, StatelyGuard, StatelyImplementation, StatelyInvoke, StatelyNodeData, StatelyTagImplementation, StudioAction, StudioEdge, StudioEventTypeData, StudioMachine, StudioNode, fromStudioMachine, studioMachineConverter, toStudioMachine };
package/dist/graph.mjs CHANGED
@@ -2,6 +2,13 @@ import { createFormatConverter, createGraph } from "@statelyai/graph";
2
2
 
3
3
  //#region src/graph.ts
4
4
  const EXPR_ACTION_TYPE = "xstate.expr";
5
+ function stripMarkdownLinks(code) {
6
+ return code.replace(/\[([^\]\n]+)\]\(([^)\n]+)\)/g, "$1");
7
+ }
8
+ function stripExportDefault(code) {
9
+ const normalized = stripMarkdownLinks(code).trim();
10
+ return normalized.match(/^export\s+default\s+(.+)/s)?.[1]?.trim() ?? normalized;
11
+ }
5
12
  function toJsonObject(value) {
6
13
  return value;
7
14
  }
@@ -126,7 +133,7 @@ function toStudioAction(action) {
126
133
  }
127
134
  };
128
135
  }
129
- function fromStudioAction(action) {
136
+ function fromStudioAction(action, actionImplementations) {
130
137
  if (action.kind === "inline") return {
131
138
  type: EXPR_ACTION_TYPE,
132
139
  params: {
@@ -134,6 +141,16 @@ function fromStudioAction(action) {
134
141
  lang: "ts"
135
142
  }
136
143
  };
144
+ if (action.action.type.startsWith("inline:") && actionImplementations?.[action.action.type]?.code) {
145
+ const implementation = actionImplementations[action.action.type];
146
+ return {
147
+ type: EXPR_ACTION_TYPE,
148
+ params: {
149
+ code: stripExportDefault(implementation.code),
150
+ lang: "ts"
151
+ }
152
+ };
153
+ }
137
154
  if ("params" in action.action && action.action.params) return {
138
155
  type: action.action.type,
139
156
  params: toUnknownRecord(action.action.params)
@@ -204,7 +221,7 @@ function toStudioNode(graph, nodeId, pathIds, parentPath) {
204
221
  nodes: childNodes
205
222
  };
206
223
  }
207
- function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId) {
224
+ function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId, actionImplementations) {
208
225
  const nodeId = studioNode.id;
209
226
  pathIdToNodeId.set(studioNode.id, nodeId);
210
227
  const initialId = studioNode.data.initial ? `${studioNode.id}.${studioNode.data.initial}` : void 0;
@@ -227,8 +244,8 @@ function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId) {
227
244
  ...normalizeStudioNodeType(studioNode.data.type) ? { type: normalizeStudioNodeType(studioNode.data.type) } : {},
228
245
  ...studioNode.data.history ? { history: studioNode.data.history } : {},
229
246
  ...initialId ? { initialId } : {},
230
- entry: studioNode.data.entry.map(fromStudioAction),
231
- exit: studioNode.data.exit.map(fromStudioAction),
247
+ entry: studioNode.data.entry.map((action) => fromStudioAction(action, actionImplementations)),
248
+ exit: studioNode.data.exit.map((action) => fromStudioAction(action, actionImplementations)),
232
249
  invokes: studioNode.data.invoke.map((invoke) => ({
233
250
  src: invoke.src,
234
251
  id: invoke.id,
@@ -240,7 +257,7 @@ function flattenStudioNodes(studioNode, parentId, nodes, pathIdToNodeId) {
240
257
  ...studioNode.data.metaEntries ? { meta: Object.fromEntries(studioNode.data.metaEntries) } : {}
241
258
  }
242
259
  });
243
- studioNode.nodes.forEach((child) => flattenStudioNodes(child, nodeId, nodes, pathIdToNodeId));
260
+ studioNode.nodes.forEach((child) => flattenStudioNodes(child, nodeId, nodes, pathIdToNodeId, actionImplementations));
244
261
  }
245
262
  function toStudioMachine(graph) {
246
263
  const rootNode = graph.nodes.find((node) => node.parentId == null);
@@ -298,7 +315,7 @@ function toStudioMachine(graph) {
298
315
  function fromStudioMachine(studioMachine) {
299
316
  const nodes = [];
300
317
  const pathIdToNodeId = /* @__PURE__ */ new Map();
301
- flattenStudioNodes(studioMachine.rootNode, null, nodes, pathIdToNodeId);
318
+ flattenStudioNodes(studioMachine.rootNode, null, nodes, pathIdToNodeId, studioMachine.implementations?.actions);
302
319
  const edges = studioMachine.edges.map((edge) => ({
303
320
  type: "edge",
304
321
  id: edge.id,
@@ -319,9 +336,9 @@ function fromStudioMachine(studioMachine) {
319
336
  ...edge.data.guard ? { guard: {
320
337
  type: edge.data.guard.type,
321
338
  params: toUnknownRecord(edge.data.guard.params),
322
- ...edge.data.guard.kind === "inline" ? { code: edge.data.guard.type } : {}
339
+ ...edge.data.guard.kind === "inline" ? { code: stripExportDefault(studioMachine.implementations?.guards?.[edge.data.guard.type]?.code ?? edge.data.guard.type) } : {}
323
340
  } } : {},
324
- actions: edge.data.actions.map(fromStudioAction),
341
+ actions: edge.data.actions.map((action) => fromStudioAction(action, studioMachine.implementations?.actions)),
325
342
  ...edge.data.description ? { description: edge.data.description } : {},
326
343
  ...edge.data.color ? { color: edge.data.color } : {},
327
344
  ...edge.data.metaEntries ? { meta: Object.fromEntries(edge.data.metaEntries) } : {}
@@ -337,9 +354,9 @@ function fromStudioMachine(studioMachine) {
337
354
  data: {
338
355
  ...studioMachine.schemas ? { schemas: studioMachine.schemas } : {},
339
356
  ...studioMachine.implementations ? { implementations: {
340
- actions: Object.values(studioMachine.implementations.actions).map(fromActionSource),
341
- guards: Object.values(studioMachine.implementations.guards).map(fromGuardSource),
342
- actors: Object.values(studioMachine.implementations.actors).map(fromActorSource),
357
+ actions: Object.entries(studioMachine.implementations.actions).filter(([key]) => !key.startsWith("inline:")).map(([, source]) => fromActionSource(source)),
358
+ guards: Object.entries(studioMachine.implementations.guards).filter(([key]) => !key.startsWith("inline:")).map(([, guard]) => fromGuardSource(guard)),
359
+ actors: Object.entries(studioMachine.implementations.actors).filter(([key]) => !key.startsWith("inline:") && !/:invocation\[\d+\]$/.test(key)).map(([, actor]) => fromActorSource(actor)),
343
360
  delays: [],
344
361
  tags: []
345
362
  } } : {}
@@ -1,4 +1,104 @@
1
- //#region src/serializeJS.ts
1
+ import ts from "typescript";
2
+
3
+ //#region src/statelyPragma.ts
4
+ function findStatelyPragmaAttachments(sourceText, fileName = "machine.ts") {
5
+ const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true, getScriptKind(fileName));
6
+ const attachments = [];
7
+ const visit = (node) => {
8
+ if (ts.isCallExpression(node) && isCreateMachineExpression(node.expression)) {
9
+ const attachNode = findAttachNode(node);
10
+ if (attachNode) attachments.push({
11
+ machineStart: getMachineExpressionStart(node.expression, sourceFile),
12
+ attachStart: attachNode.getStart(sourceFile),
13
+ pragma: findAttachedStatelyPragma(sourceText, attachNode)
14
+ });
15
+ }
16
+ ts.forEachChild(node, visit);
17
+ };
18
+ visit(sourceFile);
19
+ return attachments;
20
+ }
21
+ function getStatelyPragma(sourceText, fileName = "machine.ts", machineIndex = 0) {
22
+ return findStatelyPragmaAttachments(sourceText, fileName)[machineIndex]?.pragma;
23
+ }
24
+ function upsertStatelyPragma(sourceText, id, options = {}) {
25
+ const attachment = findStatelyPragmaAttachments(sourceText, options.fileName ?? "machine.ts")[options.machineIndex ?? 0];
26
+ if (!attachment) return sourceText;
27
+ const lineEnding = options.lineEnding ?? detectLineEnding(sourceText);
28
+ const canonicalComment = `// @statelyai id=${id}`;
29
+ if (attachment.pragma) return sourceText.slice(0, attachment.pragma.start) + canonicalComment + sourceText.slice(attachment.pragma.end);
30
+ const insertText = `${getIndentationAtOffset(sourceText, attachment.attachStart)}${canonicalComment}${lineEnding}`;
31
+ return sourceText.slice(0, attachment.attachStart) + insertText + sourceText.slice(attachment.attachStart);
32
+ }
33
+ function findAttachedStatelyPragma(sourceText, node) {
34
+ const comments = ts.getLeadingCommentRanges(sourceText, node.getFullStart()) ?? [];
35
+ for (let index = comments.length - 1; index >= 0; index -= 1) {
36
+ const comment = comments[index];
37
+ const parsed = parseStatelyPragma(sourceText, comment.pos, comment.end);
38
+ if (parsed) return parsed;
39
+ }
40
+ }
41
+ function parseStatelyPragma(sourceText, start, end) {
42
+ const match = normalizeCommentContent(sourceText.slice(start, end)).match(/^@statelyai(?:\s+(.*))?$/s);
43
+ if (!match) return;
44
+ const fields = parseFields(match[1] ?? "");
45
+ return {
46
+ tag: "@statelyai",
47
+ id: fields.id,
48
+ fields,
49
+ start,
50
+ end
51
+ };
52
+ }
53
+ function normalizeCommentContent(rawComment) {
54
+ if (rawComment.startsWith("//")) return rawComment.slice(2).trim();
55
+ if (rawComment.startsWith("/*")) return rawComment.slice(2, rawComment.endsWith("*/") ? -2 : void 0).split(/\r?\n/).map((line) => line.replace(/^\s*\*\s?/, "")).join(" ").trim();
56
+ return rawComment.trim();
57
+ }
58
+ function parseFields(input) {
59
+ const fields = {};
60
+ for (const token of input.split(/\s+/)) {
61
+ if (!token) continue;
62
+ const equalsIndex = token.indexOf("=");
63
+ if (equalsIndex <= 0) continue;
64
+ const key = token.slice(0, equalsIndex);
65
+ const value = token.slice(equalsIndex + 1);
66
+ if (!key || !value) continue;
67
+ fields[key] = value;
68
+ }
69
+ return fields;
70
+ }
71
+ function findAttachNode(node) {
72
+ let current = node;
73
+ while (current?.parent) {
74
+ if (ts.isVariableStatement(current.parent) || ts.isExpressionStatement(current.parent) || ts.isExportAssignment(current.parent)) return current.parent;
75
+ current = current.parent;
76
+ }
77
+ return current;
78
+ }
79
+ function isCreateMachineExpression(expression) {
80
+ return ts.isIdentifier(expression) && expression.text === "createMachine" || ts.isPropertyAccessExpression(expression) && expression.name.text === "createMachine";
81
+ }
82
+ function getMachineExpressionStart(expression, sourceFile) {
83
+ if (ts.isPropertyAccessExpression(expression)) return expression.name.getStart(sourceFile);
84
+ return expression.getStart(sourceFile);
85
+ }
86
+ function getIndentationAtOffset(sourceText, offset) {
87
+ const lineStart = sourceText.lastIndexOf("\n", Math.max(0, offset - 1)) + 1;
88
+ return sourceText.slice(lineStart, offset).match(/^[ \t]*/)?.[0] ?? "";
89
+ }
90
+ function detectLineEnding(sourceText) {
91
+ return sourceText.includes("\r\n") ? "\r\n" : "\n";
92
+ }
93
+ function getScriptKind(fileName) {
94
+ if (fileName.endsWith(".tsx")) return ts.ScriptKind.TSX;
95
+ if (fileName.endsWith(".jsx")) return ts.ScriptKind.JSX;
96
+ if (fileName.endsWith(".js")) return ts.ScriptKind.JS;
97
+ return ts.ScriptKind.TS;
98
+ }
99
+
100
+ //#endregion
101
+ //#region ../graph-tools/src/serializeJS.ts
2
102
  /**
3
103
  * Serializes JavaScript values as JS source code (not JSON).
4
104
  * - Unquoted keys for valid identifiers
@@ -67,33 +167,19 @@ function indentRawCode(code, indent) {
67
167
  }
68
168
 
69
169
  //#endregion
70
- //#region src/textUtils.ts
71
- /**
72
- * Pure string utilities used by codegen.
73
- */
74
- /**
75
- * Removes common leading whitespace from all non-empty lines.
76
- */
77
- function dedent(text) {
78
- const lines = text.split("\n");
79
- const nonEmptyLines = lines.filter((l) => l.trim().length > 0);
80
- if (nonEmptyLines.length === 0) return text;
81
- const minIndent = Math.min(...nonEmptyLines.map((l) => l.match(/^(\s*)/)[1].length));
82
- if (minIndent === 0) return text;
83
- return lines.map((l) => l.trim().length > 0 ? l.slice(minIndent) : l).join("\n");
84
- }
170
+ //#region ../graph-tools/src/textUtils.ts
85
171
  /**
86
172
  * Strips `export default` wrapper from an expression string.
87
173
  * E.g. `"export default assign({ ... })"` → `"assign({ ... })"`
88
174
  */
89
- function stripExportDefault(code) {
175
+ function stripExportDefault$1(code) {
90
176
  const trimmed = code.trim();
91
177
  if (trimmed.startsWith("export default ")) return trimmed.slice(15).replace(/;$/, "");
92
178
  return trimmed;
93
179
  }
94
180
 
95
181
  //#endregion
96
- //#region src/graphToMachineConfig.ts
182
+ //#region ../graph-tools/src/graphToMachineConfig.ts
97
183
  function isAutoGeneratedId(id) {
98
184
  return !!id && id.startsWith("$auto-");
99
185
  }
@@ -217,7 +303,7 @@ function serializeActionItem(action) {
217
303
  return raw(`assign({ ${entries.map(([k, v]) => `${JSON.stringify(k)}: ${formatAssignValue(v)}`).join(", ")} })`);
218
304
  }
219
305
  default:
220
- if (exprCode) return raw(stripExportDefault(exprCode));
306
+ if (exprCode) return raw(stripExportDefault$1(exprCode));
221
307
  if (!params || Object.keys(params).length === 0) return { type };
222
308
  return {
223
309
  type,
@@ -282,9 +368,9 @@ function graphToMachineConfig(graph, options = {}) {
282
368
  const type = edge.data.eventType ?? "";
283
369
  const transitionMeta = showMeta ? buildMeta(edge.data.meta, edge.data.color) : void 0;
284
370
  const transitionObject = {
285
- target: `${resolvedTarget}`,
371
+ target: edge.data.transitionType === "targetless" ? void 0 : `${resolvedTarget}`,
286
372
  ...edge.data.transitionType === "reenter" ? { reenter: true } : void 0,
287
- guard: edge.data.guard ? edge.data.guard.code ? raw(stripExportDefault(edge.data.guard.code)) : edge.data.guard : void 0,
373
+ guard: edge.data.guard ? edge.data.guard.code ? raw(stripExportDefault$1(edge.data.guard.code)) : edge.data.guard : void 0,
288
374
  actions: edge.data.actions?.length ? edge.data.actions.map(serializeActionItem) : void 0,
289
375
  description: edge.data.description ?? void 0,
290
376
  ...transitionMeta ? { meta: transitionMeta } : void 0
@@ -420,12 +506,38 @@ function eventsSchemaToTSType(events) {
420
506
  }).join("\n | ");
421
507
  }
422
508
 
509
+ //#endregion
510
+ //#region src/textUtils.ts
511
+ /**
512
+ * Pure string utilities used by codegen.
513
+ */
514
+ /**
515
+ * Removes common leading whitespace from all non-empty lines.
516
+ */
517
+ function dedent(text) {
518
+ const lines = text.split("\n");
519
+ const nonEmptyLines = lines.filter((l) => l.trim().length > 0);
520
+ if (nonEmptyLines.length === 0) return text;
521
+ const minIndent = Math.min(...nonEmptyLines.map((l) => l.match(/^(\s*)/)[1].length));
522
+ if (minIndent === 0) return text;
523
+ return lines.map((l) => l.trim().length > 0 ? l.slice(minIndent) : l).join("\n");
524
+ }
525
+ /**
526
+ * Strips `export default` wrapper from an expression string.
527
+ * E.g. `"export default assign({ ... })"` → `"assign({ ... })"`
528
+ */
529
+ function stripExportDefault(code) {
530
+ const trimmed = code.trim();
531
+ if (trimmed.startsWith("export default ")) return trimmed.slice(15).replace(/;$/, "");
532
+ return trimmed;
533
+ }
534
+
423
535
  //#endregion
424
536
  //#region src/graphToXStateTS.ts
425
537
  function graphToXStateTS(graph, options = {}) {
426
538
  const { exportStyle = "named", ...configOptions } = options;
427
539
  const schemas = graph.data.schemas;
428
- const impls = graph.data.implementations;
540
+ const impls = filterInlineImplementations(graph.data.implementations);
429
541
  const hasSchemas = !!(schemas && (schemas.context || schemas.events || schemas.input || schemas.output));
430
542
  const hasActions = !!impls?.actions.length;
431
543
  const hasGuards = !!impls?.guards.length;
@@ -459,6 +571,15 @@ function graphToXStateTS(graph, options = {}) {
459
571
  }
460
572
  return lines.join("\n") + "\n";
461
573
  }
574
+ function filterInlineImplementations(impls) {
575
+ if (!impls) return impls;
576
+ return {
577
+ ...impls,
578
+ actions: impls.actions.filter((action) => !action.name.startsWith("inline:")),
579
+ guards: impls.guards.filter((guard) => !guard.name.startsWith("inline:")),
580
+ delays: impls.delays.filter((delay) => !delay.name.startsWith("inline:"))
581
+ };
582
+ }
462
583
  /** Map from xstate action type to the import name */
463
584
  const BUILTIN_ACTION_IMPORTS = {
464
585
  "xstate.raise": "raise",
@@ -536,6 +657,11 @@ function hasSchemaProperties(schema) {
536
657
  function buildActionsBlock(actions) {
537
658
  const block = {};
538
659
  for (const implementation of actions) if (implementation.code?.body) {
660
+ const exportedExpression = getExportDefaultExpression(implementation.code.body);
661
+ if (exportedExpression) {
662
+ block[implementation.name] = raw(exportedExpression);
663
+ continue;
664
+ }
539
665
  const params = hasSchemaProperties(implementation.paramsSchema) ? `, params: ${jsonSchemaToTSType(implementation.paramsSchema)}` : "";
540
666
  block[implementation.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(implementation.code.body)}\n}`);
541
667
  } else block[implementation.name] = raw(`function ({ context, event }) {\n // TODO: implement ${implementation.name}\n}`);
@@ -544,6 +670,11 @@ function buildActionsBlock(actions) {
544
670
  function buildGuardsBlock(guards) {
545
671
  const block = {};
546
672
  for (const guard of guards) if (guard.code?.body) {
673
+ const exportedExpression = getExportDefaultExpression(guard.code.body);
674
+ if (exportedExpression) {
675
+ block[guard.name] = raw(exportedExpression);
676
+ continue;
677
+ }
547
678
  const params = hasSchemaProperties(guard.paramsSchema) ? `, params: ${jsonSchemaToTSType(guard.paramsSchema)}` : "";
548
679
  block[guard.name] = raw(`function ({ context, event }${params ? params : ""}) {\n ${dedent(guard.code.body)}\n}`);
549
680
  } else block[guard.name] = raw(`function ({ context, event }) {\n // TODO: implement ${guard.name}\n return false;\n}`);
@@ -559,10 +690,20 @@ function buildActorsBlock(actors) {
559
690
  }
560
691
  function buildDelaysBlock(delays) {
561
692
  const block = {};
562
- for (const delay of delays) if (delay.code?.body) block[delay.name] = raw(`function ({ context, event }) {\n ${dedent(delay.code.body)}\n}`);
563
- else block[delay.name] = raw(`function () {\n // TODO: implement ${delay.name}\n return 1000;\n}`);
693
+ for (const delay of delays) if (delay.code?.body) {
694
+ const exportedExpression = getExportDefaultExpression(delay.code.body);
695
+ if (exportedExpression) {
696
+ block[delay.name] = raw(exportedExpression);
697
+ continue;
698
+ }
699
+ block[delay.name] = raw(`function ({ context, event }) {\n ${dedent(delay.code.body)}\n}`);
700
+ } else block[delay.name] = raw(`function () {\n // TODO: implement ${delay.name}\n return 1000;\n}`);
564
701
  return block;
565
702
  }
703
+ function getExportDefaultExpression(code) {
704
+ const stripped = stripExportDefault(code);
705
+ return stripped === code.trim() ? void 0 : stripped;
706
+ }
566
707
 
567
708
  //#endregion
568
- export { graphToMachineConfig as a, serializeJS as c, jsonSchemaToTSType as i, contextSchemaToTSType as n, RawCode as o, eventsSchemaToTSType as r, raw as s, graphToXStateTS as t };
709
+ export { graphToMachineConfig as a, serializeJS as c, upsertStatelyPragma as d, jsonSchemaToTSType as i, findStatelyPragmaAttachments as l, contextSchemaToTSType as n, RawCode as o, eventsSchemaToTSType as r, raw as s, graphToXStateTS as t, getStatelyPragma as u };