statelyai 0.7.11 → 0.8.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/README.md +8 -0
- package/dist/bin.mjs +1 -1
- package/dist/{cli-Duxz6wQc.mjs → cli-Dc8HDZ6q.mjs} +62 -22
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
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
|
@@ -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.
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
|
2208
|
+
const client = options.client ?? createStatelyClient({
|
|
2171
2209
|
apiKey,
|
|
2172
|
-
baseUrl: studioUrl
|
|
2173
|
-
})
|
|
2174
|
-
const
|
|
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
|
|
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,
|
|
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 (
|
|
2389
|
+
if (machines.length > 0 && !config.newMachinesDir) {
|
|
2350
2390
|
this.log(formatSectionLabel("Skipped:", "warning"));
|
|
2351
2391
|
this.log(formatMissingNewMachineDirMessage({
|
|
2352
2392
|
config,
|
|
2353
|
-
remoteMachineCount:
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
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-
|
|
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.
|
|
3
|
+
"version": "0.8.0",
|
|
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.
|
|
24
|
+
"@statelyai/sdk": "0.15.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"tsdown": "0.21.0-beta.2",
|