statelyai 0.7.12 → 0.8.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/README.md CHANGED
@@ -173,6 +173,14 @@ the credential so a later command can retry.
173
173
  Project-wide discovery identifies configured JavaScript and TypeScript files
174
174
  that import XState and call `createMachine(...)` or `.createMachine(...)`.
175
175
 
176
+ <!-- resolveApiBaseUrl and DEFAULT_STATELY_API_BASE_URL from src/projectConfig.ts -->
177
+
178
+ Remote commands call the server-owned `/api/v1` resource contract on the editor
179
+ API server. Existing configs need no change: a `studioUrl` pointing at hosted
180
+ Stately (`stately.ai` or `www.stately.ai`) resolves to
181
+ `https://editor.stately.ai` at request time, and the file is never rewritten for
182
+ this. Any other `studioUrl`, such as a self-hosted origin, is used as-is.
183
+
176
184
  Mutating project commands rewrite legacy configs with one `sources` entry to
177
185
  the current top-level shape. `status` and `push --dry-run` normalize legacy
178
186
  config in memory without writing it. Multiple legacy entries cannot be merged
package/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { S as run } from "./cli-Duxz6wQc.mjs";
2
+ import { S as run } from "./cli-Dc8HDZ6q.mjs";
3
3
 
4
4
  //#region src/bin.ts
5
5
  run();
@@ -1048,6 +1048,42 @@ function describeCredentialBackend(backend, location) {
1048
1048
  const STATELY_CONFIG_FILE = "statelyai.json";
1049
1049
  const STATELY_CONFIG_SCHEMA_URL = "https://stately.ai/schemas/statelyai.json";
1050
1050
  const STATELY_CONFIG_VERSION = "1.0.0";
1051
+ /**
1052
+ * Base URL of the deployment that hosts the owned resource contract
1053
+ * (`/api/v1/*`). Matches the SDK default.
1054
+ */
1055
+ const DEFAULT_STATELY_API_BASE_URL = "https://editor.stately.ai";
1056
+ /**
1057
+ * Hosts of the legacy hosted Studio. `statelyai.json#studioUrl` values that
1058
+ * point at them predate the editor-hosted API and must be redirected.
1059
+ */
1060
+ const HOSTED_STUDIO_HOSTNAMES = new Set(["stately.ai", "www.stately.ai"]);
1061
+ /**
1062
+ * Maps a configured `statelyai.json#studioUrl` (or a `--base-url` flag) to the
1063
+ * base URL of the editor API that serves our owned contract.
1064
+ *
1065
+ * Hosted legacy values (`https://stately.ai`, `http://www.stately.ai/`, ...)
1066
+ * resolve to {@link DEFAULT_STATELY_API_BASE_URL}. Anything else is used as-is
1067
+ * (minus trailing slashes): self-hosted editor deployments already point at the
1068
+ * server that hosts `/api/v1`.
1069
+ *
1070
+ * This is a read-only compatibility shim: the CLI never rewrites
1071
+ * `statelyai.json` because of it.
1072
+ */
1073
+ function resolveApiBaseUrl(studioUrl) {
1074
+ const trimmed = studioUrl?.trim();
1075
+ if (!trimmed) return DEFAULT_STATELY_API_BASE_URL;
1076
+ const parsed = tryParseUrl(trimmed) ?? tryParseUrl(`https://${trimmed}`);
1077
+ if (parsed && HOSTED_STUDIO_HOSTNAMES.has(parsed.hostname.toLowerCase())) return DEFAULT_STATELY_API_BASE_URL;
1078
+ return trimmed.replace(/\/+$/, "");
1079
+ }
1080
+ function tryParseUrl(value) {
1081
+ try {
1082
+ return new URL(value);
1083
+ } catch {
1084
+ return;
1085
+ }
1086
+ }
1051
1087
  const DEFAULT_SOURCE_EXCLUDES = ["**/*.test.*", "**/*.spec.*"];
1052
1088
  const CODE_SOURCE_EXTENSIONS = new Set([
1053
1089
  ".ts",
@@ -1861,7 +1897,7 @@ async function discoverRemoteProjectMachineTargets(options) {
1861
1897
  if (!newMachineDir) return [];
1862
1898
  const targets = [];
1863
1899
  const reservedRelativePaths = /* @__PURE__ */ new Set();
1864
- for (const machine of options.project.machines) {
1900
+ for (const machine of options.machines) {
1865
1901
  const candidate = machine;
1866
1902
  const machineId = typeof candidate.machineId === "string" ? candidate.machineId : typeof candidate.id === "string" ? candidate.id : void 0;
1867
1903
  if (!machineId || options.linkedMachineIds.has(machineId)) continue;
@@ -1899,6 +1935,7 @@ async function discoverRemoteProjectMachineTargets(options) {
1899
1935
  async function initProject(options) {
1900
1936
  const cwd = path.resolve(options.cwd ?? process.cwd());
1901
1937
  const studioUrl = getResolvedStudioUrl(options.baseUrl);
1938
+ const apiBaseUrl = resolveApiBaseUrl(studioUrl);
1902
1939
  const configPath = path.resolve(cwd, options.configPath ?? STATELY_CONFIG_FILE);
1903
1940
  const defaultXStateVersion = Math.max(5, options.defaultXStateVersion ?? 5);
1904
1941
  const existingConfig = !options.force ? await readStatelyProjectConfig({
@@ -1915,7 +1952,7 @@ async function initProject(options) {
1915
1952
  if (existingConfig.config.projectId) {
1916
1953
  const client = options.client ?? createStatelyClient({
1917
1954
  apiKey: options.apiKey,
1918
- baseUrl: studioUrl
1955
+ baseUrl: apiBaseUrl
1919
1956
  });
1920
1957
  return {
1921
1958
  config: existingConfig.config,
@@ -1936,7 +1973,7 @@ async function initProject(options) {
1936
1973
  }
1937
1974
  const client = options.client ?? createStatelyClient({
1938
1975
  apiKey: options.apiKey,
1939
- baseUrl: studioUrl
1976
+ baseUrl: apiBaseUrl
1940
1977
  });
1941
1978
  const inferredRepo = options.project?.repo ?? await inferConnectedRepoFromCwd(cwd);
1942
1979
  const projectInput = {
@@ -2060,11 +2097,10 @@ async function resolveConfiguredProject(options) {
2060
2097
  rewriteIfNeeded: options.rewriteIfNeeded ?? true
2061
2098
  });
2062
2099
  if (!config.projectId) throw new Error("This is a local-only project. Run `statelyai init` to connect it to Stately Studio.");
2063
- const studioUrl = options.baseUrl ?? config.studioUrl;
2064
2100
  return {
2065
2101
  client: options.client ?? createStatelyClient({
2066
2102
  apiKey: options.apiKey,
2067
- baseUrl: studioUrl
2103
+ baseUrl: resolveApiBaseUrl(options.baseUrl ?? config.studioUrl)
2068
2104
  }),
2069
2105
  config,
2070
2106
  configPath,
@@ -2080,13 +2116,14 @@ async function resolveConfiguredPullTargets(options) {
2080
2116
  const linkedTargets = await discoverLinkedPullTargets(files);
2081
2117
  const linkedMachineIds = new Set(linkedTargets.map((linkedTarget) => linkedTarget.machineId));
2082
2118
  const project = await client.projects.get(config.projectId);
2119
+ const machines = await client.projects.listMachines(config.projectId);
2083
2120
  const skipped = [];
2084
2121
  let remoteOnlyTargets = [];
2085
2122
  try {
2086
2123
  remoteOnlyTargets = await discoverRemoteProjectMachineTargets({
2087
2124
  rootDir: path.dirname(configPath),
2088
2125
  config,
2089
- project,
2126
+ machines,
2090
2127
  linkedMachineIds,
2091
2128
  client
2092
2129
  });
@@ -2098,6 +2135,7 @@ async function resolveConfiguredPullTargets(options) {
2098
2135
  config,
2099
2136
  configPath,
2100
2137
  linkedTargets,
2138
+ machines,
2101
2139
  project,
2102
2140
  remoteOnlyTargets,
2103
2141
  skipped,
@@ -2167,11 +2205,13 @@ async function resolveProjectStatus(options = {}) {
2167
2205
  };
2168
2206
  }
2169
2207
  const apiKey = options.apiKey ?? (options.client ? void 0 : (await resolveApiKey()).apiKey);
2170
- const project = await (options.client ?? createStatelyClient({
2208
+ const client = options.client ?? createStatelyClient({
2171
2209
  apiKey,
2172
- baseUrl: studioUrl
2173
- })).projects.get(config.projectId);
2174
- const remoteById = new Map(project.machines.flatMap((machine) => {
2210
+ baseUrl: resolveApiBaseUrl(studioUrl)
2211
+ });
2212
+ const project = await client.projects.get(config.projectId);
2213
+ const remoteMachines = await client.projects.listMachines(config.projectId);
2214
+ const remoteById = new Map(remoteMachines.flatMap((machine) => {
2175
2215
  const id = getProjectMachineId(machine);
2176
2216
  return id ? [[id, machine]] : [];
2177
2217
  }));
@@ -2195,7 +2235,7 @@ async function resolveProjectStatus(options = {}) {
2195
2235
  url: buildMachineEditorUrl(studioUrl, config.projectId, machine.id)
2196
2236
  };
2197
2237
  });
2198
- for (const remote of project.machines) {
2238
+ for (const remote of remoteMachines) {
2199
2239
  const id = getProjectMachineId(remote);
2200
2240
  if (!id || linkedIds.has(id)) continue;
2201
2241
  machines.push({
@@ -2287,7 +2327,7 @@ async function createSemanticDiff(source, target, baseUrl) {
2287
2327
  source,
2288
2328
  target,
2289
2329
  apiKey: (await resolveApiKey()).apiKey,
2290
- baseUrl: baseUrl ?? getDefaultBaseUrl()
2330
+ baseUrl: resolveApiBaseUrl(baseUrl ?? getDefaultBaseUrl())
2291
2331
  });
2292
2332
  }
2293
2333
  var PlanCommand = class PlanCommand extends ParsedSyncCommand {
@@ -2339,29 +2379,29 @@ var PullCommand = class PullCommand extends ParsedSyncCommand {
2339
2379
  const apiKey = (await resolveApiKey()).apiKey;
2340
2380
  if (!args.source) {
2341
2381
  this.log(colorize("Resolving configured project and linked source files...", ANSI_CYAN));
2342
- const { config, linkedTargets, project, remoteOnlyTargets, skipped, rewriteStatus } = await resolveConfiguredPullTargets({
2382
+ const { config, linkedTargets, machines, remoteOnlyTargets, skipped, rewriteStatus } = await resolveConfiguredPullTargets({
2343
2383
  apiKey,
2344
2384
  baseUrl: flags["base-url"],
2345
2385
  configPath: flags.config
2346
2386
  });
2347
2387
  if (rewriteStatus.reason === "multiple-legacy-sources") this.log("Legacy statelyai.json detected with multiple sources entries. It cannot be rewritten automatically without losing information, so please update it manually.");
2348
2388
  if (linkedTargets.length === 0 && remoteOnlyTargets.length === 0) {
2349
- if (project.machines.length > 0 && !config.newMachinesDir) {
2389
+ if (machines.length > 0 && !config.newMachinesDir) {
2350
2390
  this.log(formatSectionLabel("Skipped:", "warning"));
2351
2391
  this.log(formatMissingNewMachineDirMessage({
2352
2392
  config,
2353
- remoteMachineCount: project.machines.length
2393
+ remoteMachineCount: machines.length
2354
2394
  }));
2355
2395
  return;
2356
2396
  }
2357
2397
  this.log("No linked local machine files or remote-only project machines were discovered.");
2358
2398
  return;
2359
2399
  }
2360
- if (project.machines.length > linkedTargets.length && !config.newMachinesDir) {
2400
+ if (machines.length > linkedTargets.length && !config.newMachinesDir) {
2361
2401
  this.log(formatSectionLabel("Skipped:", "warning"));
2362
2402
  this.log(formatMissingNewMachineDirMessage({
2363
2403
  config,
2364
- remoteMachineCount: project.machines.length - linkedTargets.length
2404
+ remoteMachineCount: machines.length - linkedTargets.length
2365
2405
  }));
2366
2406
  }
2367
2407
  this.log(colorize(`Processing ${linkedTargets.length} ${pluralize(linkedTargets.length, "linked file")}${remoteOnlyTargets.length > 0 ? ` and ${remoteOnlyTargets.length} ${pluralize(remoteOnlyTargets.length, "new remote machine")}` : ""}...`, ANSI_CYAN));
@@ -2379,7 +2419,7 @@ var PullCommand = class PullCommand extends ParsedSyncCommand {
2379
2419
  source: linkedTarget.machineId,
2380
2420
  target: targetPath,
2381
2421
  apiKey,
2382
- baseUrl: flags["base-url"] ?? config.studioUrl
2422
+ baseUrl: resolveApiBaseUrl(flags["base-url"] ?? config.studioUrl)
2383
2423
  });
2384
2424
  pulled.push(`${linkedTarget.file.relativePath}: ${formatSecondaryText(result.source.locator)}`);
2385
2425
  } catch (error) {
@@ -2394,7 +2434,7 @@ var PullCommand = class PullCommand extends ParsedSyncCommand {
2394
2434
  source: remoteTarget.machineId,
2395
2435
  target: remoteTarget.filePath,
2396
2436
  apiKey,
2397
- baseUrl: flags["base-url"] ?? config.studioUrl
2437
+ baseUrl: resolveApiBaseUrl(flags["base-url"] ?? config.studioUrl)
2398
2438
  });
2399
2439
  created.push(`${remoteTarget.relativePath}: ${formatSecondaryText(result.source.locator)}`);
2400
2440
  } catch (error) {
@@ -2422,7 +2462,7 @@ var PullCommand = class PullCommand extends ParsedSyncCommand {
2422
2462
  source,
2423
2463
  target,
2424
2464
  apiKey,
2425
- baseUrl: flags["base-url"] ?? getDefaultBaseUrl()
2465
+ baseUrl: resolveApiBaseUrl(flags["base-url"] ?? getDefaultBaseUrl())
2426
2466
  });
2427
2467
  this.log(`${formatSectionLabel("Pulled:", "success")} ${formatSecondaryText(result.source.locator)} -> ${result.outputPath}\nTarget: ${result.target.kind} (${result.target.format})`);
2428
2468
  }
@@ -2515,7 +2555,7 @@ var PushCommand = class PushCommand extends Command {
2515
2555
  result = await pushLocalMachineLinks({
2516
2556
  source: file.filePath,
2517
2557
  apiKey: resolvedApiKey.apiKey,
2518
- baseUrl: flags["base-url"] ?? config.studioUrl,
2558
+ baseUrl: resolveApiBaseUrl(flags["base-url"] ?? config.studioUrl),
2519
2559
  client,
2520
2560
  project: { projectId: config.projectId },
2521
2561
  xstateVersion: Math.max(5, file.source.xstateVersion ?? config.defaultXStateVersion)
@@ -2534,7 +2574,7 @@ var PushCommand = class PushCommand extends Command {
2534
2574
  result = await pushLocalMachineLinks({
2535
2575
  source: file.filePath,
2536
2576
  apiKey: resolvedApiKey.apiKey,
2537
- baseUrl: flags["base-url"] ?? config.studioUrl,
2577
+ baseUrl: resolveApiBaseUrl(flags["base-url"] ?? config.studioUrl),
2538
2578
  client,
2539
2579
  project: { projectId: config.projectId },
2540
2580
  xstateVersion: Math.max(5, file.source.xstateVersion ?? config.defaultXStateVersion),
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Command } from "@oclif/core";
2
- import { ConnectedRepo, CreateProjectInput, OAuthAuthorizationServerMetadata, OAuthProtectedResourceMetadata, ProjectData, StudioClient } from "@statelyai/sdk";
2
+ import { ConnectedRepo, CreateProjectInput, OAuthAuthorizationServerMetadata, OAuthProtectedResourceMetadata, ProjectData, ProjectMachineSummary, StudioClient } from "@statelyai/sdk";
3
3
  import { SyncPlan } from "@statelyai/sdk/sync";
4
4
  import * as _oclif_core_interfaces0 from "@oclif/core/interfaces";
5
5
 
@@ -100,6 +100,8 @@ interface ResolvedConfiguredPullTargets {
100
100
  config: StatelyProjectConfig;
101
101
  configPath: string;
102
102
  linkedTargets: LinkedPullTarget[];
103
+ /** Remote project machines, including names when the server supplies them. */
104
+ machines: ProjectMachineSummary[];
103
105
  project: ProjectData;
104
106
  remoteOnlyTargets: RemoteProjectMachineTarget[];
105
107
  skipped: string[];
@@ -195,7 +197,7 @@ declare function discoverLinkedPullTargets(files: DiscoveredSourceFile[]): Promi
195
197
  declare function discoverRemoteProjectMachineTargets(options: {
196
198
  rootDir: string;
197
199
  config: StatelyProjectConfig;
198
- project: ProjectData;
200
+ machines: ProjectMachineSummary[];
199
201
  linkedMachineIds: Set<string>;
200
202
  client?: Pick<StudioClient, 'machines'>;
201
203
  }): Promise<RemoteProjectMachineTarget[]>;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { C as scanProjectMachines, S as run, T as createStatelyProjectConfig, _ as isFileGitDirty, a as discoverMachinesInSource, b as resolveCredentialStatus, c as formatDiscoveredMachines, d as formatProjectStatus, f as formatStoredCredentialSource, g as initProject, h as inferInitProjectName, i as discoverLinkedPullTargets, l as formatMissingNewMachineDirMessage, m as getEnvCredential, n as buildOAuthLoginStart, o as discoverOAuthLogin, p as getEnvApiKey, r as classifyPushCandidates, s as discoverRemoteProjectMachineTargets, t as COMMANDS, u as formatPlanSummary, v as resolveApiKey, w as scanProjectSources, x as resolveProjectStatus, y as resolveConfiguredPullTargets } from "./cli-Duxz6wQc.mjs";
1
+ import { C as scanProjectMachines, S as run, T as createStatelyProjectConfig, _ as isFileGitDirty, a as discoverMachinesInSource, b as resolveCredentialStatus, c as formatDiscoveredMachines, d as formatProjectStatus, f as formatStoredCredentialSource, g as initProject, h as inferInitProjectName, i as discoverLinkedPullTargets, l as formatMissingNewMachineDirMessage, m as getEnvCredential, n as buildOAuthLoginStart, o as discoverOAuthLogin, p as getEnvApiKey, r as classifyPushCandidates, s as discoverRemoteProjectMachineTargets, t as COMMANDS, u as formatPlanSummary, v as resolveApiKey, w as scanProjectSources, x as resolveProjectStatus, y as resolveConfiguredPullTargets } from "./cli-Dc8HDZ6q.mjs";
2
2
 
3
3
  export { COMMANDS, buildOAuthLoginStart, classifyPushCandidates, createStatelyProjectConfig, discoverLinkedPullTargets, discoverMachinesInSource, discoverOAuthLogin, discoverRemoteProjectMachineTargets, formatDiscoveredMachines, formatMissingNewMachineDirMessage, formatPlanSummary, formatProjectStatus, formatStoredCredentialSource, getEnvApiKey, getEnvCredential, inferInitProjectName, initProject, isFileGitDirty, resolveApiKey, resolveConfiguredPullTargets, resolveCredentialStatus, resolveProjectStatus, run, scanProjectMachines, scanProjectSources };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "statelyai",
3
- "version": "0.7.12",
3
+ "version": "0.8.1",
4
4
  "description": "Command-line tools for Stately",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@oclif/core": "^4.10.3",
24
- "@statelyai/sdk": "0.14.2"
24
+ "@statelyai/sdk": "0.16.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "tsdown": "0.21.0-beta.2",