@statelyai/sdk 0.14.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/studio.d.mts CHANGED
@@ -1,125 +1,2 @@
1
- import { n as StatelyCredential, t as StatelyAuthMode } from "./auth-DmPZiERd.mjs";
2
-
3
- //#region src/studio.d.ts
4
- interface StudioClientOptions {
5
- baseUrl?: string;
6
- credential?: StatelyCredential;
7
- /** @deprecated Use credential: { type: 'api_key', token }. */
8
- apiKey?: string;
9
- authMode?: StatelyAuthMode;
10
- fetch?: typeof fetch;
11
- }
12
- interface VerifyApiKeyResponse {
13
- valid: boolean;
14
- }
15
- type ProjectVisibility = 'Public' | 'Private' | 'Unlisted';
16
- type RepoType = 'GITHUB';
17
- interface ConnectedRepo {
18
- id?: string;
19
- type?: RepoType;
20
- url: string;
21
- owner: string;
22
- repo: string;
23
- branch: string;
24
- treeSha: string;
25
- autoSync?: boolean;
26
- pathForNewFiles?: string;
27
- selectedPaths?: string[];
28
- lastSyncedAt?: string;
29
- }
30
- interface ProjectMachine {
31
- machineId: string;
32
- name: string;
33
- }
34
- interface ProjectData {
35
- projectId: string;
36
- machines: ProjectMachine[];
37
- id?: string;
38
- name?: string;
39
- description?: string | null;
40
- keywords?: string[];
41
- visibility?: ProjectVisibility;
42
- projectVersionId?: string;
43
- connectedRepo?: ConnectedRepo | null;
44
- }
45
- interface ExtractedMachine {
46
- id?: string;
47
- config: Record<string, unknown>;
48
- setupConfig?: Record<string, unknown>;
49
- implementations?: Record<string, unknown>;
50
- _type: 'setup.createMachine' | 'createMachine';
51
- }
52
- interface ExtractMachinesResponse {
53
- machines: ExtractedMachine[];
54
- error?: string;
55
- }
56
- interface GetMachineOptions {
57
- version?: string;
58
- }
59
- interface CreateProjectInput {
60
- name: string;
61
- visibility: ProjectVisibility;
62
- description?: string;
63
- keywords?: string[];
64
- repo?: ConnectedRepo;
65
- }
66
- interface EnsureProjectInput extends CreateProjectInput {
67
- matchConnectedRepo?: boolean;
68
- }
69
- type XStateVersion = 4 | 5;
70
- type CreateMachineTemplate = 'blank' | 'starter';
71
- interface CreateMachineFromDefinitionInput<TDefinition = Record<string, unknown>> {
72
- projectVersionId: string;
73
- definition: TDefinition;
74
- xstateVersion?: XStateVersion;
75
- }
76
- interface CreateMachineFromTemplateInput {
77
- projectVersionId: string;
78
- name: string;
79
- template: CreateMachineTemplate;
80
- xstateVersion?: XStateVersion;
81
- }
82
- type CreateMachineInput<TDefinition = Record<string, unknown>> = CreateMachineFromDefinitionInput<TDefinition> | CreateMachineFromTemplateInput;
83
- interface UpdateMachineInput<TDefinition = Record<string, unknown>> {
84
- id: string;
85
- name?: string;
86
- definition?: TDefinition;
87
- }
88
- interface StudioMachineRecord<TDefinition = Record<string, unknown>> {
89
- id: string;
90
- name: string;
91
- definition: TDefinition;
92
- projectVersionId?: string;
93
- [key: string]: unknown;
94
- }
95
- declare class StudioApiError extends Error {
96
- readonly status: number;
97
- constructor(message: string, status: number);
98
- }
99
- interface StudioClient {
100
- auth: {
101
- verify(credential?: StatelyCredential | string): Promise<VerifyApiKeyResponse>;
102
- };
103
- projects: {
104
- list(): Promise<ProjectData[]>;
105
- create(input: CreateProjectInput): Promise<ProjectData>;
106
- ensure(input: EnsureProjectInput): Promise<ProjectData>;
107
- get(projectId: string): Promise<ProjectData>;
108
- };
109
- machines: {
110
- create<TMachine = Record<string, unknown>>(input: CreateMachineInput<TMachine>): Promise<StudioMachineRecord<TMachine>>;
111
- createMany<TMachine = Record<string, unknown>>(input: CreateMachineInput<TMachine>): Promise<Array<StudioMachineRecord<TMachine>>>;
112
- update<TMachine = Record<string, unknown>>(input: UpdateMachineInput<TMachine>): Promise<StudioMachineRecord<TMachine>>;
113
- get<TMachine = Record<string, unknown>>(machineId: string, options?: GetMachineOptions): Promise<TMachine>;
114
- };
115
- code: {
116
- extractMachines(code: string, options?: {
117
- credential?: StatelyCredential | null; /** @deprecated Use credential. */
118
- apiKey?: string | null;
119
- authMode?: StatelyAuthMode;
120
- }): Promise<ExtractMachinesResponse>;
121
- };
122
- }
123
- declare function createStatelyClient(options?: StudioClientOptions): StudioClient;
124
- //#endregion
125
- export { ConnectedRepo, CreateMachineFromDefinitionInput, CreateMachineFromTemplateInput, CreateMachineInput, CreateMachineTemplate, CreateProjectInput, EnsureProjectInput, ExtractMachinesResponse, ExtractedMachine, GetMachineOptions, ProjectData, ProjectMachine, ProjectVisibility, RepoType, StudioApiError, StudioClient, StudioClientOptions, StudioMachineRecord, UpdateMachineInput, VerifyApiKeyResponse, XStateVersion, createStatelyClient };
1
+ import { A as Machine, C as StudioMachineRecord, D as VerifyApiKeyResponse, E as UpdateProjectInput, F as ProjectVisibility, I as VerifyResult, L as XStateVersion, M as Project, N as ProjectMachineSummary, O as createStatelyClient, P as ProjectSummary, R as ResourceErrorCode, S as StudioClientOptions, T as UpdateMachineInput, _ as ProjectMachine, a as CreateMachineTemplate, b as StudioApiErrorOptions, c as EnsureProjectInput, d as ExtractedMachine, f as GetMachineOptions, g as ProjectData, h as LegacyUpdateMachineInput, i as CreateMachineInput, j as MachineVersion, k as ExtractedMachines, l as ExtractMachinesInput, m as LegacyProjectVisibility, n as CreateMachineFromDefinitionInput, o as CreateProjectInput, p as LegacyExtractMachinesOptions, r as CreateMachineFromTemplateInput, s as DEFAULT_STATELY_BASE_URL, t as ConnectedRepo, u as ExtractMachinesResponse, v as RepoType, w as StudioRequestOptions, x as StudioClient, y as StudioApiError } from "./studio-Da5pyxv6.mjs";
2
+ export { ConnectedRepo, CreateMachineFromDefinitionInput, CreateMachineFromTemplateInput, CreateMachineInput, CreateMachineTemplate, CreateProjectInput, DEFAULT_STATELY_BASE_URL, EnsureProjectInput, ExtractMachinesInput, ExtractMachinesResponse, ExtractedMachine, ExtractedMachines, GetMachineOptions, LegacyExtractMachinesOptions, LegacyProjectVisibility, LegacyUpdateMachineInput, Machine, MachineVersion, Project, ProjectData, ProjectMachine, ProjectMachineSummary, ProjectSummary, ProjectVisibility, RepoType, ResourceErrorCode, StudioApiError, StudioApiErrorOptions, StudioClient, StudioClientOptions, StudioMachineRecord, StudioRequestOptions, UpdateMachineInput, UpdateProjectInput, VerifyApiKeyResponse, VerifyResult, XStateVersion, createStatelyClient };
package/dist/studio.mjs CHANGED
@@ -1,172 +1,3 @@
1
- import { createAuthorizationHeader, getCredentialToken } from "./auth.mjs";
1
+ import { n as StudioApiError, r as createStatelyClient, t as DEFAULT_STATELY_BASE_URL } from "./studio-txdyJHD7.mjs";
2
2
 
3
- //#region src/studio.ts
4
- var StudioApiError = class extends Error {
5
- status;
6
- constructor(message, status) {
7
- super(message);
8
- this.name = "StudioApiError";
9
- this.status = status;
10
- }
11
- };
12
- function getFetch(fetchImpl) {
13
- const resolvedFetch = fetchImpl ?? globalThis.fetch;
14
- if (!resolvedFetch) throw new Error("No fetch implementation available. Pass one via createStatelyClient({ fetch }).");
15
- return resolvedFetch;
16
- }
17
- function joinApiUrl(baseUrl, path) {
18
- return `${baseUrl.replace(/\/+$/, "")}/registry/api/v1${path}`;
19
- }
20
- async function parseJson(response) {
21
- if (!response.headers.get("content-type")?.includes("application/json")) return null;
22
- return response.json().catch(() => null);
23
- }
24
- function getErrorMessage(data, status) {
25
- if (typeof data === "object" && data !== null) {
26
- if ("error" in data && typeof data.error === "string") return data.error;
27
- if ("error" in data) {
28
- const error = data.error;
29
- if (typeof error === "object" && error !== null && "json" in error) {
30
- const errorJson = error.json;
31
- if (typeof errorJson === "object" && errorJson !== null && "message" in errorJson && typeof errorJson.message === "string") return errorJson.message;
32
- }
33
- }
34
- }
35
- if (Array.isArray(data)) for (const item of data) {
36
- const message = getErrorMessage(item, status);
37
- if (message !== `HTTP ${status}`) return message;
38
- }
39
- return `HTTP ${status}`;
40
- }
41
- function unwrapResponseData(data) {
42
- if (typeof data === "object" && data !== null && "data" in data) return data.data;
43
- return data;
44
- }
45
- function normalizeProjectMachine(machine) {
46
- if (typeof machine !== "object" || machine === null) return null;
47
- const candidate = machine;
48
- const machineId = typeof candidate.machineId === "string" ? candidate.machineId : typeof candidate.id === "string" ? candidate.id : void 0;
49
- if (!machineId) return null;
50
- return {
51
- machineId,
52
- name: typeof candidate.name === "string" && candidate.name.trim().length > 0 ? candidate.name : typeof candidate.key === "string" && candidate.key.trim().length > 0 ? candidate.key : machineId
53
- };
54
- }
55
- function normalizeProjectData(project) {
56
- const machines = Array.isArray(project.machines) ? project.machines.map((machine) => normalizeProjectMachine(machine)).filter((machine) => machine != null) : [];
57
- if (project.projectVersionId) return {
58
- ...project,
59
- machines
60
- };
61
- if (project.projectId && project.id) return {
62
- ...project,
63
- machines,
64
- projectVersionId: project.id
65
- };
66
- return {
67
- ...project,
68
- machines
69
- };
70
- }
71
- function normalizeRepoUrl(url) {
72
- if (!url) return;
73
- return url.replace(/\.git$/i, "").replace(/\/+$/, "");
74
- }
75
- function connectedReposMatch(left, right) {
76
- if (!left || !right) return false;
77
- const normalizedLeft = normalizeRepoUrl(left.url);
78
- const normalizedRight = normalizeRepoUrl(right.url);
79
- return normalizedLeft != null && normalizedRight != null && normalizedLeft === normalizedRight && left.branch === right.branch || left.owner === right.owner && left.repo === right.repo && left.branch === right.branch;
80
- }
81
- function createStatelyClient(options = {}) {
82
- const baseUrl = options.baseUrl ?? "https://stately.ai";
83
- const fetchImpl = getFetch(options.fetch);
84
- const defaultCredential = options.credential ?? (options.apiKey ? {
85
- type: "api_key",
86
- token: options.apiKey
87
- } : void 0);
88
- const defaultAuthMode = options.authMode ?? "auto";
89
- async function request(path, init = {}, credentialOverride, authModeOverride) {
90
- const headers = new Headers(init.headers);
91
- const authMode = authModeOverride ?? defaultAuthMode;
92
- const credential = credentialOverride ?? defaultCredential;
93
- if (authMode !== "none") {
94
- const token = getCredentialToken(credential);
95
- if (authMode === "bearer" && (!token || !credential)) throw new StudioApiError("No Stately credential configured. Pass createStatelyClient({ credential }) or use authMode: \"auto\" to let the server decide whether authentication is required.", 401);
96
- if (token && credential) headers.set("Authorization", createAuthorizationHeader(credential));
97
- }
98
- const response = await fetchImpl(joinApiUrl(baseUrl, path), {
99
- ...init,
100
- headers
101
- });
102
- const data = await parseJson(response);
103
- if (!response.ok) throw new StudioApiError(getErrorMessage(data, response.status), response.status);
104
- return unwrapResponseData(data);
105
- }
106
- return {
107
- auth: { verify(credential) {
108
- return request("/verify", { method: "GET" }, credential);
109
- } },
110
- projects: {
111
- list() {
112
- return request("/projects", { method: "GET" }).then((projects) => projects.map(normalizeProjectData));
113
- },
114
- create(input) {
115
- return request("/projects/create", {
116
- method: "POST",
117
- headers: { "Content-Type": "application/json" },
118
- body: JSON.stringify(input)
119
- }).then(normalizeProjectData);
120
- },
121
- async ensure(input) {
122
- if (input.repo && input.matchConnectedRepo !== false) {
123
- const existingProject = (await this.list()).find((project) => connectedReposMatch(project.connectedRepo, input.repo));
124
- if (existingProject) return existingProject;
125
- }
126
- return this.create(input);
127
- },
128
- get(projectId) {
129
- return request(`/projects/${encodeURIComponent(projectId)}`, { method: "GET" }).then(normalizeProjectData);
130
- }
131
- },
132
- machines: {
133
- async create(input) {
134
- return request("/machines/create", {
135
- method: "POST",
136
- headers: { "Content-Type": "application/json" },
137
- body: JSON.stringify(input)
138
- });
139
- },
140
- async createMany(input) {
141
- return [await this.create(input)];
142
- },
143
- update(input) {
144
- return request(`/machines/${encodeURIComponent(input.id)}`, {
145
- method: "PATCH",
146
- headers: { "Content-Type": "application/json" },
147
- body: JSON.stringify(input)
148
- });
149
- },
150
- get(machineId, getOptions = {}) {
151
- const search = new URLSearchParams();
152
- if (getOptions.version) search.set("version", getOptions.version);
153
- const suffix = search.size > 0 ? `?${search.toString()}` : "";
154
- return request(`/machines/${encodeURIComponent(machineId)}${suffix}`, { method: "GET" });
155
- }
156
- },
157
- code: { extractMachines(code, extractOptions = {}) {
158
- const credential = extractOptions.credential ?? (extractOptions.apiKey ? {
159
- type: "api_key",
160
- token: extractOptions.apiKey
161
- } : void 0);
162
- return request("/code", {
163
- method: "POST",
164
- headers: { "Content-Type": "application/json" },
165
- body: JSON.stringify({ code })
166
- }, credential, extractOptions.authMode);
167
- } }
168
- };
169
- }
170
-
171
- //#endregion
172
- export { StudioApiError, createStatelyClient };
3
+ export { DEFAULT_STATELY_BASE_URL, StudioApiError, createStatelyClient };
package/dist/sync.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { b as DigraphConfig, i as StatelyGraph } from "./graph-R0sbxnZ7.mjs";
2
- import { CreateProjectInput, ProjectData, StudioClient, StudioMachineRecord, XStateVersion } from "./studio.mjs";
1
+ import { b as DigraphConfig, i as StatelyGraph } from "./graph-DuOeLGvh.mjs";
2
+ import { C as StudioMachineRecord, L as XStateVersion, g as ProjectData, o as CreateProjectInput, x as StudioClient } from "./studio-Da5pyxv6.mjs";
3
3
  import { GraphDiff } from "@statelyai/graph";
4
4
 
5
5
  //#region src/sync.d.ts
package/dist/sync.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { createStatelyClient } from "./studio.mjs";
2
- import { d as xstateSourceToConfig, f as findStatelyPragmaAttachments, i as detectXStateSourceProfile, m as upsertStatelyPragma, p as getStatelyPragma, s as graphToXStateTS, t as INLINE_EXPRESSION_DIRECTIVE_FIELDS, u as serializeJS } from "./dist-C8jVuuHf.mjs";
1
+ import { r as createStatelyClient } from "./studio-txdyJHD7.mjs";
2
+ import { i as INLINE_EXPRESSION_DIRECTIVE_FIELDS, m as xstateSourceToConfig, n as getStatelyPragma, p as serializeJS, r as upsertStatelyPragma, s as detectXStateSourceProfile, t as findStatelyPragmaAttachments, u as graphToXStateTS } from "./statelyPragma-Bm9O4XV6.mjs";
3
3
  import { fromStudioMachine, toStudioMachine } from "./graph.mjs";
4
4
  import * as ts$1 from "typescript";
5
5
  import ts from "typescript";
@@ -65,9 +65,35 @@ function createFileSourceDocumentResolver() {
65
65
  resolveImport(fromDocument, specifier) {
66
66
  const importedFileName = resolveImportPath(fromDocument.fileName, specifier);
67
67
  return importedFileName ? readFileSnapshot(importedFileName) : null;
68
+ },
69
+ resolvePackageJson(fromDocument, packageName) {
70
+ let directory = path$1.dirname(path$1.resolve(fromDocument.fileName));
71
+ while (true) {
72
+ const packageJson = readFileSnapshot(path$1.join(directory, "package.json"));
73
+ if (packageJson && packageJsonDeclares(packageJson.text, packageName)) return packageJson;
74
+ const parent = path$1.dirname(directory);
75
+ if (parent === directory) return null;
76
+ directory = parent;
77
+ }
68
78
  }
69
79
  };
70
80
  }
81
+ function packageJsonDeclares(text, packageName) {
82
+ try {
83
+ const manifest = JSON.parse(text);
84
+ return [
85
+ "dependencies",
86
+ "devDependencies",
87
+ "peerDependencies",
88
+ "optionalDependencies"
89
+ ].some((field) => {
90
+ const dependencies = manifest[field];
91
+ return Boolean(dependencies && typeof dependencies === "object" && Object.prototype.hasOwnProperty.call(dependencies, packageName));
92
+ });
93
+ } catch {
94
+ return false;
95
+ }
96
+ }
71
97
  function resolveImportPath(fromFileName, specifier) {
72
98
  if (!specifier.startsWith(".")) return null;
73
99
  const basePath = path$1.resolve(path$1.dirname(fromFileName), specifier);
@@ -121,20 +147,116 @@ function collectXStateSourceLocations(sourceText, document, options = {}) {
121
147
  const states = [];
122
148
  const statesObjectLocations = [];
123
149
  collectStateLocations(root, [], states, statesObjectLocations, bindings, staticValues, root);
150
+ const packageProfile = detectXStatePackageProfile(options.resolver?.resolvePackageJson?.({
151
+ fileName: document.fileName,
152
+ uri
153
+ }, "xstate"));
124
154
  const rootProfile = detectXStateSourceProfile(sourceText);
125
155
  const referencedStateSymbols = new Set([...states, ...statesObjectLocations].map((state) => state.symbol).filter((symbol) => typeof symbol === "string"));
156
+ const resolvedTransitionFunctions = collectResolvedTransitionFunctions(root, bindings);
157
+ const inferredProfile = rootProfile === "xstate-v6-alpha" || resolvedTransitionFunctions.size > 0 || [...referencedStateSymbols].some((symbol) => detectXStateSourceProfile(bindings.get(symbol)?.sourceFile.text ?? "") === "xstate-v6-alpha") ? "xstate-v6-alpha" : rootProfile;
126
158
  return {
127
159
  version: 1,
128
- profile: rootProfile === "xstate-v6-alpha" || [...referencedStateSymbols].some((symbol) => detectXStateSourceProfile(bindings.get(symbol)?.sourceFile.text ?? "") === "xstate-v6-alpha") ? "xstate-v6-alpha" : rootProfile,
160
+ profile: packageProfile ?? inferredProfile,
129
161
  root: {
130
162
  uri,
131
163
  range: toSourceRange$1(sourceFile, root)
132
164
  },
133
165
  statesObject: statesObjectLocations[0],
134
166
  states,
135
- staticValues: collectStaticValueReferences(sourceFile, uri, root, staticValues)
167
+ staticValues: collectStaticValueReferences(sourceFile, uri, root, staticValues),
168
+ transitionFunctions: [...resolvedTransitionFunctions].flatMap(([symbol, resolved]) => resolved.binding.uri === uri ? [] : [{
169
+ symbol,
170
+ uri: resolved.binding.uri,
171
+ range: toSourceRange$1(resolved.binding.sourceFile, resolved.binding.node),
172
+ sourcePaths: resolved.sourcePaths
173
+ }])
136
174
  };
137
175
  }
176
+ function detectXStatePackageProfile(packageJson) {
177
+ if (!packageJson) return void 0;
178
+ let manifest;
179
+ try {
180
+ manifest = JSON.parse(packageJson.text);
181
+ } catch {
182
+ return;
183
+ }
184
+ const dependencyFields = [
185
+ "dependencies",
186
+ "devDependencies",
187
+ "peerDependencies",
188
+ "optionalDependencies"
189
+ ];
190
+ let range;
191
+ for (const field of dependencyFields) {
192
+ const dependencies = manifest[field];
193
+ if (!dependencies || typeof dependencies !== "object") continue;
194
+ const value = dependencies.xstate;
195
+ if (typeof value === "string") {
196
+ range = value;
197
+ break;
198
+ }
199
+ }
200
+ if (!range) return void 0;
201
+ const clauseProfiles = range.replace(/^(?:workspace:|npm:xstate@)/, "").split("||").map((clause) => detectXStateRangeClauseProfile(clause.trim()));
202
+ const profiles = new Set(clauseProfiles);
203
+ if (profiles.size !== 1 || profiles.has(void 0)) return void 0;
204
+ return clauseProfiles[0];
205
+ }
206
+ function detectXStateRangeClauseProfile(clause) {
207
+ const normalizedClause = clause.replace(/([<>]=?)\s+/g, "$1");
208
+ let lowerRequiresV6 = false;
209
+ let upperRequiresV5 = false;
210
+ let directProfile;
211
+ for (const match of normalizedClause.matchAll(/(?:^|\s)([<>]=?|[~^])?v?(\d+)(?:\.(\d+|x|\*))?(?:\.(\d+|x|\*))?(?:-[0-9A-Za-z.-]+)?(?=\s|$)/g)) {
212
+ const operator = match[1] ?? "";
213
+ const major = Number(match[2]);
214
+ const minor = parseRangePart(match[3]);
215
+ const patch = parseRangePart(match[4]);
216
+ if (operator === ">" || operator === ">=") {
217
+ if (major >= 6) lowerRequiresV6 = true;
218
+ continue;
219
+ }
220
+ if (operator === "<") {
221
+ if (major < 6 || major === 6 && (minor ?? 0) === 0 && (patch ?? 0) === 0) upperRequiresV5 = true;
222
+ continue;
223
+ }
224
+ if (operator === "<=") {
225
+ if (major < 6) upperRequiresV5 = true;
226
+ continue;
227
+ }
228
+ const profile = major >= 6 ? "xstate-v6-alpha" : "xstate-v5";
229
+ if (directProfile && directProfile !== profile) return void 0;
230
+ directProfile = profile;
231
+ }
232
+ if (lowerRequiresV6 && upperRequiresV5) return void 0;
233
+ if (lowerRequiresV6) return "xstate-v6-alpha";
234
+ if (upperRequiresV5) return "xstate-v5";
235
+ return directProfile;
236
+ }
237
+ function parseRangePart(value) {
238
+ return value && /^\d+$/.test(value) ? Number(value) : void 0;
239
+ }
240
+ function collectImportedXStateTransitionSources(sourceText, document, options = {}) {
241
+ if (!options.resolver) return [];
242
+ const sourceFile = ts$1.createSourceFile(document.fileName, sourceText, ts$1.ScriptTarget.Latest, true, getScriptKind$2(document.fileName));
243
+ const uri = document.uri?.toString() ?? document.fileName;
244
+ sourceFileUris.set(sourceFile, uri);
245
+ const bindings = collectBindings(sourceFile, uri, document.fileName, options);
246
+ const root = findMachineConfigObjectLiteral(sourceFile, bindings);
247
+ if (!root) return [];
248
+ return [...collectResolvedTransitionFunctions(root, bindings)].flatMap(([localName, resolved]) => {
249
+ const { binding } = resolved;
250
+ if (binding.uri === uri) return [];
251
+ if (ts$1.isFunctionDeclaration(binding.node)) {
252
+ const name = binding.node.name;
253
+ if (!name) return [];
254
+ const suffix = binding.node.getText(binding.sourceFile).slice(name.getEnd() - binding.node.getStart(binding.sourceFile));
255
+ return [`${binding.node.modifiers?.some((modifier) => modifier.kind === ts$1.SyntaxKind.AsyncKeyword) ? "async " : ""}function ${localName}${suffix}`];
256
+ }
257
+ return [`const ${localName} = ${binding.node.getText(binding.sourceFile)};`];
258
+ });
259
+ }
138
260
  function collectStaticValueBindings(sourceFile) {
139
261
  const bindings = /* @__PURE__ */ new Map();
140
262
  for (const statement of sourceFile.statements) {
@@ -180,9 +302,30 @@ function collectBindings(sourceFile, uri, fileName, options, cache = /* @__PURE_
180
302
  function collectTopLevelBindings(sourceFile, uri) {
181
303
  const bindings = /* @__PURE__ */ new Map();
182
304
  for (const statement of sourceFile.statements) {
305
+ if (ts$1.isFunctionDeclaration(statement) && statement.name) {
306
+ bindings.set(statement.name.text, {
307
+ kind: "transitionFunction",
308
+ node: statement,
309
+ sourceFile,
310
+ uri,
311
+ bindings
312
+ });
313
+ continue;
314
+ }
183
315
  if (!ts$1.isVariableStatement(statement)) continue;
184
316
  for (const declaration of statement.declarationList.declarations) {
185
317
  if (!ts$1.isIdentifier(declaration.name) || !declaration.initializer) continue;
318
+ const initializer = unwrapExpression$1(declaration.initializer);
319
+ if (ts$1.isArrowFunction(initializer) || ts$1.isFunctionExpression(initializer)) {
320
+ bindings.set(declaration.name.text, {
321
+ kind: "transitionFunction",
322
+ node: initializer,
323
+ sourceFile,
324
+ uri,
325
+ bindings
326
+ });
327
+ continue;
328
+ }
186
329
  const objectLiteral = unwrapObjectLiteralExpression(declaration.initializer);
187
330
  if (objectLiteral) {
188
331
  bindings.set(declaration.name.text, {
@@ -228,6 +371,62 @@ function addImportedBindings(bindings, sourceFile, uri, fileName, options, cache
228
371
  }
229
372
  }
230
373
  }
374
+ function collectResolvedTransitionFunctions(root, bindings) {
375
+ const found = /* @__PURE__ */ new Map();
376
+ const visitExpression = (expression, sourcePath) => {
377
+ const current = unwrapExpression$1(expression);
378
+ if (ts$1.isIdentifier(current)) {
379
+ const binding = bindings.get(current.text);
380
+ if (binding?.kind === "transitionFunction") {
381
+ const resolved = found.get(current.text) ?? {
382
+ binding,
383
+ sourcePaths: []
384
+ };
385
+ if (!resolved.sourcePaths.some((existing) => existing.length === sourcePath.length && existing.every((segment, index) => segment === sourcePath[index]))) resolved.sourcePaths.push(sourcePath);
386
+ found.set(current.text, resolved);
387
+ }
388
+ return;
389
+ }
390
+ if (ts$1.isObjectLiteralExpression(current)) {
391
+ for (const property of current.properties) if (ts$1.isPropertyAssignment(property)) visitExpression(property.initializer, sourcePath);
392
+ else if (ts$1.isShorthandPropertyAssignment(property)) visitExpression(property.name, sourcePath);
393
+ else if (ts$1.isSpreadAssignment(property)) visitExpression(property.expression, sourcePath);
394
+ return;
395
+ }
396
+ if (ts$1.isArrayLiteralExpression(current)) {
397
+ for (const element of current.elements) if (ts$1.isExpression(element)) visitExpression(element, sourcePath);
398
+ return;
399
+ }
400
+ ts$1.forEachChild(current, (child) => {
401
+ if (ts$1.isExpression(child)) visitExpression(child, sourcePath);
402
+ });
403
+ };
404
+ const visitState = (state, sourcePath) => {
405
+ for (const propertyName of [
406
+ "on",
407
+ "after",
408
+ "always",
409
+ "onDone",
410
+ "onError",
411
+ "onSnapshot",
412
+ "onTimeout"
413
+ ]) {
414
+ const property = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$1(candidate.name) === propertyName);
415
+ if (property) visitExpression(property.initializer, sourcePath);
416
+ }
417
+ const states = state.properties.find((candidate) => ts$1.isPropertyAssignment(candidate) && getPropertyNameText$1(candidate.name) === "states");
418
+ const statesObject = states && unwrapObjectLiteralExpression(states.initializer);
419
+ if (!statesObject) return;
420
+ for (const property of statesObject.properties) {
421
+ if (!ts$1.isPropertyAssignment(property)) continue;
422
+ const child = unwrapObjectLiteralExpression(property.initializer);
423
+ const key = getPropertyNameText$1(property.name);
424
+ if (child && key) visitState(child, [...sourcePath, key]);
425
+ }
426
+ };
427
+ visitState(root, []);
428
+ return found;
429
+ }
231
430
  function findMachineConfigObjectLiteral(sourceFile, bindings) {
232
431
  let found = null;
233
432
  const visit = (node) => {
@@ -276,7 +475,7 @@ function collectStateLocations(stateObject, parentPath, locations, statesObjectL
276
475
  function resolveStateProperty(property, bindings, staticValues, root) {
277
476
  if (ts$1.isShorthandPropertyAssignment(property)) {
278
477
  const binding = bindings.get(property.name.text);
279
- if (!binding) return null;
478
+ if (!binding || binding.kind === "transitionFunction") return null;
280
479
  return {
281
480
  key: property.name.text,
282
481
  kind: binding.kind,
@@ -306,7 +505,7 @@ function resolveStateProperty(property, bindings, staticValues, root) {
306
505
  };
307
506
  if (ts$1.isIdentifier(property.initializer)) {
308
507
  const binding = bindings.get(property.initializer.text);
309
- if (!binding) return null;
508
+ if (!binding || binding.kind === "transitionFunction") return null;
310
509
  return {
311
510
  key: resolvedKey.key,
312
511
  kind: binding.kind,
@@ -584,10 +783,13 @@ function parseSourceToMachine(text, document, options = {}) {
584
783
  ...statesObjectReplacements,
585
784
  ...importReplacements
586
785
  ].filter(removeOverlappingRanges).sort(compareSourceRangesDescending));
587
- if (sourceLocations.profile === "xstate-v6-alpha") return `import { createMachine } from "xstate";
786
+ if (sourceLocations.profile === "xstate-v6-alpha") {
787
+ const importedTransitionSources = collectImportedXStateTransitionSources(text, document, options);
788
+ return `import { createMachine } from "xstate";
588
789
 
589
- export const machine = createMachine(${serializeJS(xstateSourceToConfig(hydratedText, { profile: "xstate-v6-alpha" }), 0)});
790
+ export const machine = createMachine(${serializeJS(xstateSourceToConfig(importedTransitionSources.length ? `${hydratedText}\n${importedTransitionSources.join("\n")}` : hydratedText, { profile: "xstate-v6-alpha" }), 0)});
590
791
  `;
792
+ }
591
793
  return hydratedText;
592
794
  }
593
795
  function readHydratedStatesObject(uri, range, states, resolver) {
@@ -1254,16 +1456,16 @@ function inferXStateTargetLanguage(targetPath) {
1254
1456
  return /\.(?:c|m)?jsx?$/i.test(targetPath) ? "javascript" : "typescript";
1255
1457
  }
1256
1458
  async function resolveRemoteMachine(machineId, baseUrl, kind, locator, options) {
1257
- const machineResponse = await (options.client ?? createStatelyClient({
1459
+ const digraph = (await (options.client ?? createStatelyClient({
1258
1460
  apiKey: options.apiKey,
1259
1461
  baseUrl,
1260
1462
  fetch: options.fetch
1261
- })).machines.get(machineId);
1463
+ })).machines.get(machineId)).definition;
1262
1464
  return {
1263
1465
  kind,
1264
1466
  locator,
1265
1467
  format: "digraph",
1266
- graph: fromStudioMachine(machineResponse && typeof machineResponse === "object" && "definition" in machineResponse && machineResponse.definition ? machineResponse.definition : machineResponse),
1468
+ graph: fromStudioMachine(digraph),
1267
1469
  remoteMachineId: machineId
1268
1470
  };
1269
1471
  }
@@ -1332,33 +1534,22 @@ function inferDefaultProjectName(sourcePath, repo) {
1332
1534
  return path.basename(sourcePath, path.extname(sourcePath));
1333
1535
  }
1334
1536
  async function resolvePushProject(client, sourcePath, options) {
1335
- async function withResolvedProjectVersionId(project, explicitProjectVersionId) {
1336
- if (project.projectVersionId) return project;
1337
- if (explicitProjectVersionId) return {
1338
- ...project,
1339
- projectVersionId: explicitProjectVersionId
1340
- };
1341
- const matchedProject = (await client.projects.list()).find((candidate) => {
1342
- return candidate.projectId === project.projectId || candidate.id != null && project.id != null && candidate.id === project.id;
1343
- });
1344
- if (matchedProject?.projectVersionId) return {
1345
- ...project,
1346
- projectVersionId: matchedProject.projectVersionId
1347
- };
1348
- return project;
1349
- }
1350
1537
  const explicitProject = options.project;
1351
- if (explicitProject?.projectVersionId) return withResolvedProjectVersionId(await client.projects.get(explicitProject.projectVersionId), explicitProject.projectVersionId);
1352
- if (explicitProject?.projectId) return withResolvedProjectVersionId(await client.projects.get(explicitProject.projectId));
1538
+ if (explicitProject?.projectId) return client.projects.get(explicitProject.projectId);
1539
+ if (explicitProject?.projectVersionId) {
1540
+ const matchedProject = (await client.projects.list()).find((candidate) => candidate.projectVersionId === explicitProject.projectVersionId);
1541
+ if (!matchedProject) throw new Error(`No project found for projectVersionId "${explicitProject.projectVersionId}".`);
1542
+ return client.projects.get(matchedProject.projectId);
1543
+ }
1353
1544
  const inferredRepo = explicitProject?.repo ?? await inferConnectedRepo(sourcePath, options.cwd);
1354
1545
  const projectInput = {
1355
1546
  name: explicitProject?.name ?? inferDefaultProjectName(sourcePath, inferredRepo),
1356
- visibility: explicitProject?.visibility ?? "Private",
1547
+ visibility: explicitProject?.visibility ?? "private",
1357
1548
  ...explicitProject?.description ? { description: explicitProject.description } : {},
1358
1549
  ...explicitProject?.keywords ? { keywords: explicitProject.keywords } : {},
1359
1550
  ...inferredRepo ? { repo: inferredRepo } : {}
1360
1551
  };
1361
- return withResolvedProjectVersionId(await client.projects.ensure(projectInput));
1552
+ return client.projects.ensure(projectInput);
1362
1553
  }
1363
1554
  async function pushSync(options) {
1364
1555
  const client = options.client ?? createStatelyClient({