@statelyai/sdk 0.34.1 → 0.35.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.
Files changed (40) hide show
  1. package/README.md +32 -26
  2. package/dist/assetStorage.d.mts +1 -1
  3. package/dist/auth.d.mts +14 -1
  4. package/dist/bin.mjs +1 -3
  5. package/dist/editor-sync-types-DNFk7Xtj.d.mts +53 -0
  6. package/dist/editorHostProtocol.d.mts +197 -0
  7. package/dist/{editorHostProtocol-B2_t3Le7.mjs → editorHostProtocol.mjs} +1 -1
  8. package/dist/embed.d.mts +3 -3
  9. package/dist/embed.mjs +2 -2
  10. package/dist/{graph-Ciocekxl.d.mts → graph-B6xUxqR5.d.mts} +1 -1
  11. package/dist/graph.d.mts +1 -1
  12. package/dist/{index-DZivqh0u.d.mts → index-CoxF4Saw.d.mts} +36 -252
  13. package/dist/index.d.mts +8 -31
  14. package/dist/index.mjs +5 -9
  15. package/dist/{inspect-BbvfH0Q1.d.mts → inspect-DCdu0ST3.d.mts} +1 -1
  16. package/dist/{inspect-DW30GMge.mjs → inspect-GSXRhzOx.mjs} +48 -32
  17. package/dist/inspect.d.mts +2 -2
  18. package/dist/inspect.mjs +2 -2
  19. package/dist/patchTypes.d.mts +1 -1
  20. package/dist/{protocol-B7q2lWj_.d.mts → protocol-nOWsz3UV.d.mts} +3 -3
  21. package/dist/protocol.d.mts +1 -1
  22. package/dist/relay.d.mts +1 -1
  23. package/dist/relay.mjs +40 -1
  24. package/dist/{studio-CKdEPGKY.d.mts → studio-3ujfe2z0.d.mts} +2 -2
  25. package/dist/{openapi-BTDjYWXd.mjs → studio-Bn3alVku.mjs} +637 -1
  26. package/dist/studio.d.mts +1 -1
  27. package/dist/studio.mjs +2 -2
  28. package/dist/{version-BEfUEyPL.mjs → version-DECst76A.mjs} +1 -1
  29. package/package.json +21 -17
  30. package/dist/auth-CVFc85uF.d.mts +0 -15
  31. package/dist/dist-NJFkDQjK.mjs +0 -8134
  32. package/dist/editor-sync-types-D7YYz6fb.d.mts +0 -98
  33. package/dist/editorHostSession-Bj5YcijC.mjs +0 -912
  34. package/dist/editorHostSession-DBLSyHJs.d.mts +0 -325
  35. package/dist/editorHostSession.d.mts +0 -2
  36. package/dist/editorHostSession.mjs +0 -6
  37. package/dist/statelyPragma-YtVaBuIe.mjs +0 -102
  38. package/dist/studio-BZP6DaIO.mjs +0 -638
  39. package/dist/sync.d.mts +0 -86
  40. package/dist/sync.mjs +0 -4646
@@ -1,912 +0,0 @@
1
- import { c as object, f as unknown, i as custom, l as record, n as array, o as literal, r as boolean, s as number, t as _enum, u as string } from "./openapi-BTDjYWXd.mjs";
2
- import { t as EDITOR_PROTOCOL_VERSION } from "./editorHostProtocol-B2_t3Le7.mjs";
3
- import { p as graphChangeToPatchesResult } from "./dist-NJFkDQjK.mjs";
4
- import * as ts$1 from "typescript";
5
-
6
- //#region ../api-contract/dist/editor-sync.mjs
7
- const EDITOR_SYNC_PROTOCOL_VERSION = 1;
8
- const EDITOR_SYNC_PROTOCOL_HEADER = "X-Stately-Editor-Sync-Version";
9
- const editorSyncErrorResponseSchema = object({
10
- error: string(),
11
- code: string().optional()
12
- }).passthrough();
13
- const editorCapabilitiesSchema = object({
14
- edit: boolean().optional(),
15
- export: boolean().optional(),
16
- ai: boolean().optional(),
17
- simulate: boolean().optional(),
18
- inspect: boolean().optional(),
19
- maxDepth: number().optional(),
20
- panels: array(string()).optional(),
21
- commands: array(string()).optional()
22
- }).passthrough();
23
- const editorSyncAccessSchema = object({
24
- level: _enum(["full", "restricted"]),
25
- readOnly: boolean(),
26
- readOnlyReason: _enum(["free-plan", "access-unverified"]).optional(),
27
- capabilities: editorCapabilitiesSchema
28
- }).passthrough();
29
- const editorSyncSourceRangeSchema = object({
30
- startLine: number(),
31
- startChar: number(),
32
- endLine: number(),
33
- endChar: number()
34
- });
35
- const editorSyncSourceLocationSchema = object({
36
- uri: string(),
37
- range: editorSyncSourceRangeSchema
38
- });
39
- const editorSyncStateSourceLocationSchema = editorSyncSourceLocationSchema.extend({
40
- path: array(string()),
41
- kind: _enum([
42
- "inline",
43
- "objectReference",
44
- "createStateConfig"
45
- ]),
46
- symbol: string().optional(),
47
- keyRange: editorSyncSourceRangeSchema.optional(),
48
- referenceRange: editorSyncSourceRangeSchema.optional(),
49
- keySource: object({
50
- kind: _enum([
51
- "const",
52
- "enumMember",
53
- "computedLiteral"
54
- ]),
55
- symbol: string().optional(),
56
- valueRange: editorSyncSourceRangeSchema.optional(),
57
- machineLocal: boolean().optional()
58
- }).optional(),
59
- keyReplacementText: string().optional()
60
- });
61
- const machineSourceLocationsSchema = object({
62
- version: literal(1),
63
- profile: _enum(["xstate-v5", "xstate-v6-alpha"]).optional(),
64
- profileRef: custom((value) => typeof value === "string" && value.startsWith("@statelyai/xstate@")).optional(),
65
- root: editorSyncSourceLocationSchema.optional(),
66
- statesObject: editorSyncStateSourceLocationSchema.optional(),
67
- states: array(editorSyncStateSourceLocationSchema),
68
- staticValues: array(editorSyncSourceLocationSchema.extend({ value: string() })).optional(),
69
- transitionFunctions: array(editorSyncSourceLocationSchema.extend({
70
- symbol: string(),
71
- sourcePaths: array(array(string()))
72
- })).optional()
73
- }).passthrough();
74
- const editorSyncSourceDocumentSchema = object({
75
- uri: string(),
76
- fileName: string(),
77
- text: string()
78
- });
79
- const editorSyncDocumentContextSchema = object({
80
- rootUri: string(),
81
- rootFileName: string(),
82
- rootDir: string(),
83
- documents: array(editorSyncSourceDocumentSchema)
84
- });
85
- const editorSyncParseRequestSchema = editorSyncDocumentContextSchema.extend({ machineIndex: number().int().nonnegative().optional() });
86
- const editorSyncParseResponseSchema = object({
87
- machine: unknown(),
88
- format: string(),
89
- sourceLocations: machineSourceLocationsSchema.optional(),
90
- access: editorSyncAccessSchema.optional()
91
- }).passthrough();
92
- const editorSyncApplyRequestSchema = editorSyncParseRequestSchema.extend({
93
- machineConfig: unknown().optional(),
94
- patches: array(unknown()).optional(),
95
- prevGraph: unknown().optional(),
96
- nextGraph: unknown().optional(),
97
- sourceLocations: machineSourceLocationsSchema.optional(),
98
- serialized: record(string(), string()).optional(),
99
- preserveStatelyMetadata: boolean().optional(),
100
- sourceUpdateStrategy: _enum(["preserve", "rewrite"]).optional()
101
- }).passthrough();
102
- const editorSyncTextReplacementSchema = object({
103
- uri: string().optional(),
104
- range: editorSyncSourceRangeSchema,
105
- newText: string()
106
- });
107
- const editorSyncApplyResponseSchema = object({ replacements: array(editorSyncTextReplacementSchema) });
108
- const editorSyncAccessResponseSchema = object({ access: editorSyncAccessSchema });
109
-
110
- //#endregion
111
- //#region src/editorHostSession.ts
112
- let diagnosticSequence = 0;
113
- function createDiagnostic(code, phase, details) {
114
- return {
115
- id: `stately-${Date.now().toString(36)}-${(++diagnosticSequence).toString(36)}`,
116
- code,
117
- phase,
118
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
119
- ...details ? { details } : {}
120
- };
121
- }
122
- var EditorSyncError = class extends Error {
123
- status;
124
- code;
125
- constructor(message, status, code) {
126
- super(message);
127
- this.name = "EditorSyncError";
128
- this.status = status;
129
- this.code = code;
130
- }
131
- };
132
- function createRemoteEditorSyncBackend(options) {
133
- const fetchImpl = options.fetch ?? globalThis.fetch;
134
- async function post(pathname, body) {
135
- const url = new URL(pathname, `${options.editorUrl.replace(/\/+$/, "")}/`);
136
- const headers = {
137
- "Content-Type": "application/json",
138
- [EDITOR_SYNC_PROTOCOL_HEADER]: String(EDITOR_SYNC_PROTOCOL_VERSION)
139
- };
140
- if (options.apiKey) headers.Authorization = `Bearer ${options.apiKey}`;
141
- const response = await fetchImpl(url, {
142
- method: "POST",
143
- headers,
144
- body: JSON.stringify(body)
145
- });
146
- assertEditorSyncResponseProtocol(response);
147
- const data = await response.json().catch(() => null);
148
- if (!response.ok) throwEditorSyncError(response.status, data);
149
- return data;
150
- }
151
- return {
152
- async parse(request) {
153
- return editorSyncParseResponseSchema.parse(await post("/api/editor-sync/parse", request));
154
- },
155
- async apply(request) {
156
- return editorSyncApplyResponseSchema.parse(await post("/api/editor-sync/apply", request));
157
- }
158
- };
159
- }
160
- async function fetchEditorSyncAccess(options) {
161
- const fetchImpl = options.fetch ?? globalThis.fetch;
162
- const url = new URL("/api/editor-sync/access", `${options.editorUrl.replace(/\/+$/, "")}/`);
163
- const headers = { [EDITOR_SYNC_PROTOCOL_HEADER]: String(EDITOR_SYNC_PROTOCOL_VERSION) };
164
- if (options.apiKey) headers.Authorization = `Bearer ${options.apiKey}`;
165
- const response = await fetchImpl(url, {
166
- method: "GET",
167
- headers
168
- });
169
- assertEditorSyncResponseProtocol(response);
170
- const data = await response.json().catch(() => null);
171
- if (!response.ok) throwEditorSyncError(response.status, data);
172
- return editorSyncAccessResponseSchema.parse(data).access;
173
- }
174
- function throwEditorSyncError(status, data) {
175
- const parsed = editorSyncErrorResponseSchema.safeParse(data);
176
- const error = parsed.success ? parsed.data : void 0;
177
- throw new EditorSyncError(error?.error ?? `HTTP ${status}`, status, error?.code);
178
- }
179
- function assertEditorSyncResponseProtocol(response) {
180
- const selectedVersion = response.headers.get(EDITOR_SYNC_PROTOCOL_HEADER);
181
- if (selectedVersion === null || selectedVersion === String(EDITOR_SYNC_PROTOCOL_VERSION)) return;
182
- throw new Error(`Editor Sync protocol ${selectedVersion} is unsupported; this client supports ${EDITOR_SYNC_PROTOCOL_VERSION}.`);
183
- }
184
- const SOURCE_SAVE_REMINDER_ID = "source-save-reminder";
185
- var EditorHostSession = class {
186
- editorProtocolState = "awaiting";
187
- currentGraph;
188
- lastPersistedGraph;
189
- currentFormat;
190
- currentSourceLocations;
191
- access;
192
- watchedSourceUris = /* @__PURE__ */ new Set();
193
- watcher;
194
- changeWatcher;
195
- retrieveRequestCount = 0;
196
- pendingRetrievals = /* @__PURE__ */ new Map();
197
- constructor(options, saveReminderState = { shown: false }, selfEditState = { count: 0 }) {
198
- this.options = options;
199
- this.saveReminderState = saveReminderState;
200
- this.selfEditState = selfEditState;
201
- this.watcher = options.source.watchSavedDocuments?.((uri) => this.handleSavedDocument(uri));
202
- this.changeWatcher = options.source.watchChangedDocuments?.((uri) => {
203
- if (!this.isExternalSourceDocument(uri)) return;
204
- if (this.saveReminderState.shown) return;
205
- this.saveReminderState.shown = true;
206
- this.options.send({
207
- type: "@statelyai.toast",
208
- id: SOURCE_SAVE_REMINDER_ID,
209
- message: "Save code to see changes.",
210
- toastType: "warning"
211
- });
212
- });
213
- }
214
- dispose() {
215
- this.watcher?.dispose();
216
- this.changeWatcher?.dispose();
217
- for (const pending of this.pendingRetrievals.values()) pending.reject(/* @__PURE__ */ new Error("Editor session disposed before export completed."));
218
- this.pendingRetrievals.clear();
219
- }
220
- notifySavedDocument(uri = this.options.source.rootUri) {
221
- return this.handleSavedDocument(uri);
222
- }
223
- async receive(message) {
224
- if (message.type !== "@statelyai.ready" && this.editorProtocolState !== "compatible") return;
225
- switch (message.type) {
226
- case "@statelyai.ready":
227
- if (this.editorProtocolState === "incompatible") break;
228
- if (message.protocolVersion !== void 0 && message.protocolVersion !== EDITOR_PROTOCOL_VERSION) {
229
- this.editorProtocolState = "incompatible";
230
- this.options.send({
231
- type: "@statelyai.error",
232
- code: "unsupported_protocol",
233
- message: `Editor protocol ${message.protocolVersion} is unsupported; this client supports ${EDITOR_PROTOCOL_VERSION}.`
234
- });
235
- break;
236
- }
237
- this.editorProtocolState = "compatible";
238
- try {
239
- if (message.protocolVersion !== void 0) this.options.send({
240
- type: "@statelyai.handshake",
241
- protocolVersion: EDITOR_PROTOCOL_VERSION,
242
- client: this.options.client
243
- });
244
- await this.initialize();
245
- } catch (error) {
246
- const message = formatError(error, "Failed to initialize the visual editor.");
247
- this.options.send({
248
- type: "@statelyai.error",
249
- code: "initialization_failed",
250
- message
251
- });
252
- this.options.showError?.(message);
253
- }
254
- break;
255
- case "@statelyai.loaded":
256
- this.currentGraph = message.graph;
257
- this.lastPersistedGraph = message.graph;
258
- this.currentSourceLocations = mergeSourceLocations(this.currentSourceLocations, message.sourceLocations);
259
- break;
260
- case "@statelyai.change":
261
- this.currentGraph = message.graph;
262
- this.currentSourceLocations = mergeSourceLocations(this.currentSourceLocations, message.sourceLocations);
263
- break;
264
- case "@statelyai.save":
265
- try {
266
- await this.save(message);
267
- } catch (error) {
268
- const text = formatError(error, "Failed to apply Viz changes.");
269
- this.reportSourceSyncError(text, "save", {
270
- errorName: error instanceof Error ? error.name : void 0,
271
- sourceUpdateStrategy: message.sourceUpdateStrategy ?? this.options.sourceUpdateStrategy ?? "preserve",
272
- canRewrite: (message.sourceUpdateStrategy ?? this.options.sourceUpdateStrategy ?? "preserve") === "preserve"
273
- }, message.requestId);
274
- }
275
- break;
276
- case "@statelyai.refresh":
277
- await this.handleSavedDocument(this.options.source.rootUri);
278
- break;
279
- case "@statelyai.retrieved":
280
- this.resolveRetrieved(message.requestId, message.data);
281
- break;
282
- case "@statelyai.error":
283
- if (message.requestId) {
284
- const pending = this.pendingRetrievals.get(message.requestId);
285
- if (pending) {
286
- this.pendingRetrievals.delete(message.requestId);
287
- pending.reject(new Error(message.message));
288
- break;
289
- }
290
- }
291
- this.options.showError?.(message.diagnostic ? `${message.message} (diagnostic ${message.diagnostic.id})` : message.message);
292
- break;
293
- case "@statelyai.clipboardRead": {
294
- let text = "";
295
- try {
296
- text = await this.options.readClipboard?.() ?? "";
297
- } catch {}
298
- this.options.send({
299
- type: "@statelyai.clipboardReadResponse",
300
- requestId: message.requestId,
301
- text
302
- });
303
- break;
304
- }
305
- case "@statelyai.clipboardWrite": {
306
- let ok = false;
307
- try {
308
- await this.options.writeClipboard?.(message.text);
309
- ok = Boolean(this.options.writeClipboard);
310
- } catch {}
311
- this.options.send({
312
- type: "@statelyai.clipboardWriteResponse",
313
- requestId: message.requestId,
314
- ok
315
- });
316
- break;
317
- }
318
- }
319
- }
320
- async initialize() {
321
- const documents = await this.options.source.collectDocuments();
322
- const update = await this.options.sync.parse({
323
- rootUri: this.options.source.rootUri,
324
- rootFileName: this.options.source.rootFileName,
325
- rootDir: this.options.source.rootDir,
326
- ...this.options.source.machineIndex !== void 0 ? { machineIndex: this.options.source.machineIndex } : {},
327
- documents
328
- });
329
- this.currentFormat = update.format;
330
- this.currentSourceLocations = update.sourceLocations;
331
- this.access = update.access ?? this.options.access;
332
- this.updateWatchedSourceUris(update.sourceLocations);
333
- if (this.options.apiKey) this.options.send({
334
- type: "@statelyai.setApiKey",
335
- apiKey: this.options.apiKey
336
- });
337
- this.options.send({
338
- type: "@statelyai.init",
339
- machine: update.machine,
340
- format: update.format,
341
- sourceLocations: update.sourceLocations,
342
- mode: this.access?.readOnly ? "viewing" : "editing",
343
- readOnly: this.access?.readOnly,
344
- readOnlyReason: this.access?.readOnlyReason,
345
- capabilities: this.access?.capabilities,
346
- theme: this.options.getTheme?.() ?? "light",
347
- unsavedIndicator: this.options.init?.unsavedIndicator ?? { enabled: true },
348
- settings: this.options.init?.settings,
349
- panels: this.options.init?.panels,
350
- ...this.options.init?.panels === void 0 && {
351
- leftPanels: this.options.init?.leftPanels ?? [],
352
- rightPanels: this.options.init?.rightPanels ?? [],
353
- activePanels: this.options.init?.activePanels ?? []
354
- }
355
- });
356
- }
357
- async save(message) {
358
- this.currentSourceLocations = mergeSourceLocations(this.currentSourceLocations, message.sourceLocations);
359
- this.updateWatchedSourceUris(this.currentSourceLocations);
360
- if (this.access?.readOnly) {
361
- const text = "Your Stately plan allows read-only editor sync.";
362
- this.options.send({
363
- type: "@statelyai.toast",
364
- message: text,
365
- toastType: "error"
366
- });
367
- this.options.showError?.(text);
368
- return;
369
- }
370
- const validationErrors = (message.validations ?? []).filter((validation) => validation.level === "error");
371
- if (validationErrors.length > 0) {
372
- const text = formatValidationErrorMessage(validationErrors);
373
- this.options.send({
374
- type: "@statelyai.toast",
375
- message: text,
376
- toastType: "error"
377
- });
378
- this.options.showError?.(text);
379
- return;
380
- }
381
- const previousGraph = this.lastPersistedGraph ?? this.currentGraph;
382
- let patches = message.patches;
383
- if (!patches?.length && previousGraph !== void 0) try {
384
- const semanticChange = graphChangeToPatchesResult(previousGraph, message.graph);
385
- if (semanticChange.patches.length === 0 && semanticChange.unsupportedChanges.length === 0) {
386
- this.currentGraph = message.graph;
387
- this.lastPersistedGraph = message.graph;
388
- this.options.send({
389
- type: "@statelyai.saved",
390
- ...message.requestId ? { requestId: message.requestId } : {},
391
- graph: message.graph
392
- });
393
- return;
394
- }
395
- patches = semanticChange.patches;
396
- } catch {}
397
- if (!patches?.length && graphsEqual(previousGraph, message.graph)) {
398
- this.currentGraph = message.graph;
399
- this.lastPersistedGraph = message.graph;
400
- this.options.send({
401
- type: "@statelyai.saved",
402
- ...message.requestId ? { requestId: message.requestId } : {},
403
- graph: message.graph
404
- });
405
- return;
406
- }
407
- const documents = await this.options.source.collectDocuments(sourceLocationUris(this.currentSourceLocations));
408
- const serialized = await this.getSerializedPayload();
409
- const sourceUpdateStrategy = message.sourceUpdateStrategy ?? this.options.sourceUpdateStrategy ?? "preserve";
410
- const response = await this.options.sync.apply({
411
- rootUri: this.options.source.rootUri,
412
- rootFileName: this.options.source.rootFileName,
413
- rootDir: this.options.source.rootDir,
414
- ...this.options.source.machineIndex !== void 0 ? { machineIndex: this.options.source.machineIndex } : {},
415
- documents,
416
- machineConfig: message.machineConfig,
417
- patches,
418
- prevGraph: previousGraph,
419
- nextGraph: message.graph,
420
- sourceLocations: this.currentSourceLocations,
421
- serialized,
422
- preserveStatelyMetadata: this.options.source.getPreserveStatelyMetadata?.(this.options.source.rootUri) ?? true,
423
- sourceUpdateStrategy
424
- });
425
- assertSyntacticallyValidSourceUpdates(documents, response.replacements, this.options.source.rootUri);
426
- if (response.replacements.length === 0) {
427
- this.reportSourceSyncError("Could not write visual changes to the source file. Your visual edits are still unsaved.", "save", {
428
- reason: "no_replacements",
429
- patchCount: patches?.length ?? 0,
430
- profile: this.currentSourceLocations?.profileRef ?? this.currentSourceLocations?.profile,
431
- sourceFile: this.options.source.rootFileName.split(/[\\/]/).pop(),
432
- sourceUpdateStrategy,
433
- canRewrite: sourceUpdateStrategy === "preserve"
434
- }, message.requestId);
435
- return;
436
- }
437
- this.selfEditState.count++;
438
- try {
439
- const touchedUris = await this.options.source.applyReplacements(response.replacements, this.options.source.rootUri);
440
- await this.options.source.saveDocuments?.(touchedUris);
441
- } finally {
442
- this.selfEditState.count--;
443
- }
444
- this.currentGraph = message.graph;
445
- this.lastPersistedGraph = message.graph;
446
- this.options.send({
447
- type: "@statelyai.saved",
448
- ...message.requestId ? { requestId: message.requestId } : {},
449
- graph: message.graph
450
- });
451
- }
452
- isExternalSourceDocument(uri) {
453
- return (uri === this.options.source.rootUri || this.watchedSourceUris.has(uri)) && this.selfEditState.count === 0;
454
- }
455
- async handleSavedDocument(uri) {
456
- if (!this.isExternalSourceDocument(uri)) return;
457
- if (this.saveReminderState.shown) this.options.send({
458
- type: "@statelyai.toast.dismiss",
459
- id: SOURCE_SAVE_REMINDER_ID
460
- });
461
- this.saveReminderState.shown = false;
462
- if (this.editorProtocolState !== "compatible") return;
463
- try {
464
- const documents = await this.options.source.collectDocuments(sourceLocationUris(this.currentSourceLocations));
465
- const update = await this.options.sync.parse({
466
- rootUri: this.options.source.rootUri,
467
- rootFileName: this.options.source.rootFileName,
468
- rootDir: this.options.source.rootDir,
469
- ...this.options.source.machineIndex !== void 0 ? { machineIndex: this.options.source.machineIndex } : {},
470
- documents
471
- });
472
- this.currentFormat = update.format;
473
- this.currentSourceLocations = update.sourceLocations;
474
- this.access = update.access ?? this.access;
475
- this.updateWatchedSourceUris(update.sourceLocations);
476
- this.options.send({
477
- type: "@statelyai.update",
478
- machine: update.machine,
479
- format: update.format,
480
- sourceLocations: update.sourceLocations
481
- });
482
- } catch (error) {
483
- this.reportSourceSyncError(formatError(error, "Failed to read the saved document."), "update", {
484
- errorName: error instanceof Error ? error.name : void 0,
485
- sourceFile: this.options.source.rootFileName.split(/[\\/]/).pop()
486
- });
487
- }
488
- }
489
- reportSourceSyncError(message, phase, details, requestId) {
490
- const diagnostic = createDiagnostic(phase === "save" ? "source_sync_failed" : "source_update_failed", phase, {
491
- protocolVersion: EDITOR_PROTOCOL_VERSION,
492
- client: this.options.client,
493
- ...details
494
- });
495
- this.options.send({
496
- type: "@statelyai.error",
497
- code: diagnostic.code,
498
- message,
499
- diagnostic,
500
- ...requestId ? { requestId } : {}
501
- });
502
- this.options.send({
503
- type: "@statelyai.toast",
504
- message: phase === "save" ? "Visual changes were not written to the source file." : "The source file could not be applied to the visual editor.",
505
- toastType: "error"
506
- });
507
- this.options.showError?.(`${message} (diagnostic ${diagnostic.id})`);
508
- }
509
- updateWatchedSourceUris(sourceLocations) {
510
- this.watchedSourceUris.clear();
511
- for (const uri of stateSourceLocationUris(sourceLocations)) if (uri !== this.options.source.rootUri) this.watchedSourceUris.add(uri);
512
- }
513
- async getSerializedPayload() {
514
- const format = this.currentFormat;
515
- if (!format || format === "xstate") return void 0;
516
- try {
517
- return { [format]: await this.requestSerialized(format) };
518
- } catch {
519
- return;
520
- }
521
- }
522
- requestSerialized(format) {
523
- const requestId = `retrieve-${++this.retrieveRequestCount}`;
524
- return new Promise((resolve, reject) => {
525
- this.pendingRetrievals.set(requestId, {
526
- resolve,
527
- reject
528
- });
529
- this.options.send({
530
- type: "@statelyai.retrieve",
531
- requestId,
532
- format
533
- });
534
- });
535
- }
536
- resolveRetrieved(requestId, data) {
537
- const pending = this.pendingRetrievals.get(requestId);
538
- if (!pending) return;
539
- this.pendingRetrievals.delete(requestId);
540
- pending.resolve(typeof data === "string" ? data : JSON.stringify(data, null, 2));
541
- }
542
- };
543
- /**
544
- * Runs one source-sync session per discovered machine while presenting the
545
- * editor's project/workspace protocol as a single surface.
546
- */
547
- var EditorHostWorkspaceSession = class {
548
- children = /* @__PURE__ */ new Map();
549
- machineDefinitions = /* @__PURE__ */ new Map();
550
- initialMessages = /* @__PURE__ */ new Map();
551
- selectedMachineId;
552
- sentHandshake = false;
553
- sentApiKey = false;
554
- initialized = false;
555
- projectWorkspaceOpen;
556
- retrieveRequestCount = 0;
557
- pendingRetrievals = /* @__PURE__ */ new Map();
558
- saveReminderStates = /* @__PURE__ */ new Map();
559
- selfEditStates = /* @__PURE__ */ new Map();
560
- constructor(options) {
561
- this.options = options;
562
- if (options.machines.length === 0) throw new Error("A visual editor workspace needs at least one machine.");
563
- this.selectedMachineId = options.currentMachineId && options.machines.some((machine) => machine.id === options.currentMachineId) ? options.currentMachineId : options.machines[0].id;
564
- this.projectWorkspaceOpen = options.projectWorkspaceOpen ?? false;
565
- for (const machine of options.machines) {
566
- const saveReminderState = this.saveReminderStates.get(machine.source.rootUri) ?? { shown: false };
567
- this.saveReminderStates.set(machine.source.rootUri, saveReminderState);
568
- const selfEditState = this.selfEditStates.get(machine.source.rootUri) ?? { count: 0 };
569
- this.selfEditStates.set(machine.source.rootUri, selfEditState);
570
- this.children.set(machine.id, new EditorHostSession({
571
- ...options,
572
- source: machine.source,
573
- send: (message) => this.handleChildMessage(machine, message)
574
- }, saveReminderState, selfEditState));
575
- }
576
- }
577
- async receive(message) {
578
- if (message.type === "@statelyai.ready") {
579
- await Promise.all([...this.children.values()].map((session) => session.receive(message)));
580
- this.flushProjectInit();
581
- return;
582
- }
583
- if (message.type === "@statelyai.project.machineSelected") {
584
- if (this.children.has(message.machineId)) this.selectedMachineId = message.machineId;
585
- return;
586
- }
587
- if (message.type === "@statelyai.project.workspaceOpenChanged") {
588
- this.projectWorkspaceOpen = message.open;
589
- return;
590
- }
591
- if (message.type === "@statelyai.project.workspaceAction") return;
592
- if ((message.type === "@statelyai.retrieved" || message.type === "@statelyai.error") && message.requestId) {
593
- const pending = this.pendingRetrievals.get(message.requestId);
594
- if (pending) {
595
- this.pendingRetrievals.delete(message.requestId);
596
- await this.children.get(pending.machineId)?.receive({
597
- ...message,
598
- requestId: pending.childRequestId,
599
- machineId: pending.machineId
600
- });
601
- return;
602
- }
603
- }
604
- const routedMessage = message.type === "@statelyai.save" ? normalizeWorkspaceSaveMessage(message, this.options.machines) : message;
605
- const machineId = ("machineId" in routedMessage ? routedMessage.machineId : void 0) ?? this.selectedMachineId;
606
- const child = this.children.get(machineId);
607
- if (child) await child.receive(routedMessage);
608
- }
609
- selectMachine(machineId) {
610
- if (!this.children.has(machineId)) return;
611
- this.selectedMachineId = machineId;
612
- this.options.send({
613
- type: "@statelyai.project.selectMachine",
614
- machineId
615
- });
616
- }
617
- dispose() {
618
- for (const child of this.children.values()) child.dispose();
619
- this.children.clear();
620
- this.pendingRetrievals.clear();
621
- }
622
- handleChildMessage(machine, message) {
623
- switch (message.type) {
624
- case "@statelyai.init":
625
- this.initialMessages.set(machine.id, message);
626
- this.machineDefinitions.set(machine.id, {
627
- id: machine.id,
628
- name: machine.name,
629
- sourceReference: machine.sourceReference,
630
- sourceUri: machine.source.rootUri,
631
- machine: message.machine,
632
- format: message.format,
633
- sourceLocations: message.sourceLocations
634
- });
635
- if (this.initialMessages.size === this.children.size) this.flushProjectInit();
636
- return;
637
- case "@statelyai.update": {
638
- const previous = this.machineDefinitions.get(machine.id);
639
- this.machineDefinitions.set(machine.id, {
640
- id: machine.id,
641
- name: machine.name,
642
- sourceReference: machine.sourceReference,
643
- sourceUri: machine.source.rootUri,
644
- machine: message.machine,
645
- format: message.format,
646
- sourceLocations: message.sourceLocations,
647
- ...previous?.projectId ? { projectId: previous.projectId } : {}
648
- });
649
- if (this.initialized) this.options.send({
650
- type: "@statelyai.project.update",
651
- machines: this.getProjectMachines(),
652
- source: "external",
653
- currentMachineId: this.selectedMachineId,
654
- projectWorkspace: this.getProjectWorkspace(),
655
- projectWorkspaceOpen: this.projectWorkspaceOpen
656
- });
657
- return;
658
- }
659
- case "@statelyai.handshake":
660
- if (this.sentHandshake) return;
661
- this.sentHandshake = true;
662
- this.options.send(message);
663
- return;
664
- case "@statelyai.setApiKey":
665
- if (this.sentApiKey) return;
666
- this.sentApiKey = true;
667
- this.options.send(message);
668
- return;
669
- case "@statelyai.retrieve": {
670
- const requestId = `workspace-retrieve-${++this.retrieveRequestCount}`;
671
- this.pendingRetrievals.set(requestId, {
672
- machineId: machine.id,
673
- childRequestId: message.requestId
674
- });
675
- this.options.send({
676
- ...message,
677
- requestId,
678
- machineId: machine.id
679
- });
680
- return;
681
- }
682
- case "@statelyai.saved":
683
- case "@statelyai.toast":
684
- case "@statelyai.toast.dismiss":
685
- case "@statelyai.error":
686
- this.options.send({
687
- ...message,
688
- machineId: machine.id
689
- });
690
- return;
691
- default: this.options.send(message);
692
- }
693
- }
694
- flushProjectInit() {
695
- if (this.initialized || this.initialMessages.size === 0) return;
696
- const first = this.initialMessages.values().next().value;
697
- if (!first) return;
698
- if (!this.machineDefinitions.has(this.selectedMachineId)) {
699
- const firstAvailableMachineId = this.machineDefinitions.keys().next().value;
700
- if (!firstAvailableMachineId) return;
701
- this.selectedMachineId = firstAvailableMachineId;
702
- }
703
- this.initialized = true;
704
- this.options.send({
705
- type: "@statelyai.project.init",
706
- machines: this.getProjectMachines(),
707
- chrome: this.options.showHeader ? { header: true } : void 0,
708
- currentMachineId: this.selectedMachineId,
709
- mode: first.mode,
710
- theme: first.theme,
711
- readOnly: first.readOnly,
712
- readOnlyReason: first.readOnlyReason,
713
- capabilities: first.capabilities,
714
- settings: first.settings,
715
- panels: first.panels,
716
- unsavedIndicator: first.unsavedIndicator,
717
- projectWorkspace: this.getProjectWorkspace(),
718
- projectWorkspaceOpen: this.projectWorkspaceOpen
719
- });
720
- }
721
- getProjectMachines() {
722
- return this.options.machines.flatMap((machine) => {
723
- const definition = this.machineDefinitions.get(machine.id);
724
- return definition ? [definition] : [];
725
- });
726
- }
727
- getProjectWorkspace() {
728
- return { project: {
729
- id: "source-workspace",
730
- name: this.options.workspaceName ?? "Source workspace",
731
- machines: this.options.machines.flatMap((machine) => this.machineDefinitions.has(machine.id) ? [{
732
- id: machine.id,
733
- name: machine.name
734
- }] : [])
735
- } };
736
- }
737
- };
738
- function normalizeWorkspaceSaveMessage(message, machines) {
739
- const sourceReferences = new Map(machines.flatMap((machine) => machine.sourceReference ? [[machine.id, machine.sourceReference]] : []));
740
- if (sourceReferences.size === 0) return message;
741
- try {
742
- const usedReferences = /* @__PURE__ */ new Set();
743
- const graph = structuredClone(message.graph);
744
- const machineConfig = structuredClone(message.machineConfig);
745
- normalizeInvokeSources(graph, sourceReferences, usedReferences);
746
- normalizeInvokeSources(machineConfig, sourceReferences, usedReferences);
747
- if (usedReferences.size === 0) return message;
748
- addWorkspaceActorImplementations(graph, usedReferences);
749
- const patches = message.patches ? structuredClone(message.patches) : void 0;
750
- if (patches) {
751
- normalizeInvokeSources(patches, sourceReferences, usedReferences);
752
- for (const sourceReference of usedReferences) {
753
- if (patches.some((patch) => isRecord(patch) && patch.op === "createImplementation" && patch.sourceType === "actor" && isRecord(patch.implementation) && patch.implementation.id === sourceReference)) continue;
754
- patches.push({
755
- op: "createImplementation",
756
- sourceType: "actor",
757
- implementation: {
758
- id: sourceReference,
759
- name: sourceReference,
760
- code: sourceReference
761
- }
762
- });
763
- }
764
- }
765
- return {
766
- ...message,
767
- graph,
768
- machineConfig,
769
- ...patches ? { patches } : {}
770
- };
771
- } catch {
772
- return message;
773
- }
774
- }
775
- function normalizeInvokeSources(value, sourceReferences, usedReferences) {
776
- if (Array.isArray(value)) {
777
- for (const item of value) normalizeInvokeSources(item, sourceReferences, usedReferences);
778
- return;
779
- }
780
- if (!isRecord(value)) return;
781
- if (typeof value.src === "string") {
782
- const sourceReference = sourceReferences.get(value.src);
783
- if (sourceReference) {
784
- value.src = sourceReference;
785
- usedReferences.add(sourceReference);
786
- }
787
- }
788
- for (const child of Object.values(value)) normalizeInvokeSources(child, sourceReferences, usedReferences);
789
- }
790
- function addWorkspaceActorImplementations(graph, sourceReferences) {
791
- if (!isRecord(graph) || !isRecord(graph.data)) return;
792
- if (!isRecord(graph.data.implementations)) graph.data.implementations = {};
793
- const implementations = graph.data.implementations;
794
- if (!isRecord(implementations)) return;
795
- const actors = Array.isArray(implementations.actors) ? implementations.actors : implementations.actors = [];
796
- for (const sourceReference of sourceReferences) {
797
- if (actors.some((actor) => isRecord(actor) && actor.id === sourceReference)) continue;
798
- actors.push({
799
- id: sourceReference,
800
- name: sourceReference,
801
- description: null,
802
- inputSchema: null,
803
- outputSchema: null,
804
- code: {
805
- body: sourceReference,
806
- lang: "ts",
807
- deps: {}
808
- }
809
- });
810
- }
811
- }
812
- function isRecord(value) {
813
- return typeof value === "object" && value !== null && !Array.isArray(value);
814
- }
815
- function assertSyntacticallyValidSourceUpdates(documents, replacements, rootUri) {
816
- const documentsByIdentifier = /* @__PURE__ */ new Map();
817
- for (const document of documents) {
818
- documentsByIdentifier.set(document.uri, document);
819
- documentsByIdentifier.set(document.fileName, document);
820
- }
821
- const replacementsByUri = /* @__PURE__ */ new Map();
822
- for (const replacement of replacements) {
823
- const uri = replacement.uri ?? rootUri;
824
- const current = replacementsByUri.get(uri) ?? [];
825
- current.push(replacement);
826
- replacementsByUri.set(uri, current);
827
- }
828
- for (const [uri, documentReplacements] of replacementsByUri) {
829
- const document = documentsByIdentifier.get(uri);
830
- if (!document || !/\.[cm]?[jt]sx?$/i.test(document.fileName)) continue;
831
- const candidate = applySourceReplacements(document.text, documentReplacements);
832
- const diagnostics = getIntroducedSyntacticDiagnostics(document.fileName, document.text, candidate);
833
- if (diagnostics.length) {
834
- const detail = ts$1.flattenDiagnosticMessageText(diagnostics[0].messageText, "\n");
835
- throw new Error(`Stately refused to write invalid source to ${document.fileName}: ${detail}`);
836
- }
837
- }
838
- }
839
- function getIntroducedSyntacticDiagnostics(fileName, original, candidate) {
840
- const getDiagnostics = (text) => ts$1.transpileModule(text, {
841
- fileName,
842
- reportDiagnostics: true,
843
- compilerOptions: {
844
- allowJs: true,
845
- jsx: ts$1.JsxEmit.Preserve,
846
- target: ts$1.ScriptTarget.Latest
847
- }
848
- }).diagnostics ?? [];
849
- const originalCounts = /* @__PURE__ */ new Map();
850
- for (const diagnostic of getDiagnostics(original)) {
851
- const key = diagnosticKey(diagnostic);
852
- originalCounts.set(key, (originalCounts.get(key) ?? 0) + 1);
853
- }
854
- return getDiagnostics(candidate).filter((diagnostic) => {
855
- const key = diagnosticKey(diagnostic);
856
- const remaining = originalCounts.get(key) ?? 0;
857
- if (remaining === 0) return true;
858
- originalCounts.set(key, remaining - 1);
859
- return false;
860
- });
861
- }
862
- function diagnosticKey(diagnostic) {
863
- return `${diagnostic.code}:${ts$1.flattenDiagnosticMessageText(diagnostic.messageText, "\n")}`;
864
- }
865
- function applySourceReplacements(source, replacements) {
866
- const lineStarts = [0];
867
- for (let index = 0; index < source.length; index++) if (source.charCodeAt(index) === 10) lineStarts.push(index + 1);
868
- const offsetAt = (line, character) => (lineStarts[Math.min(Math.max(line, 0), lineStarts.length - 1)] ?? 0) + character;
869
- return [...replacements].sort((left, right) => offsetAt(right.range.startLine, right.range.startChar) - offsetAt(left.range.startLine, left.range.startChar)).reduce((text, replacement) => {
870
- const start = offsetAt(replacement.range.startLine, replacement.range.startChar);
871
- const end = offsetAt(replacement.range.endLine, replacement.range.endChar);
872
- return `${text.slice(0, start)}${replacement.newText}${text.slice(end)}`;
873
- }, source);
874
- }
875
- function graphsEqual(left, right) {
876
- if (left === void 0 || right === void 0) return false;
877
- try {
878
- return JSON.stringify(left) === JSON.stringify(right);
879
- } catch {
880
- return false;
881
- }
882
- }
883
- function mergeSourceLocations(previous, next) {
884
- if (!next) return previous;
885
- if (!next.profile && previous?.profile) return {
886
- ...next,
887
- profile: previous.profile
888
- };
889
- return next;
890
- }
891
- function formatError(error, fallback) {
892
- return error instanceof Error ? error.message : fallback;
893
- }
894
- function formatValidationErrorMessage(errors) {
895
- const first = errors[0];
896
- if (errors.length === 1 && first) return `Cannot save Viz changes: ${first.message}`;
897
- return `Cannot save Viz changes: ${errors.length} validation errors. First: ${first?.message ?? "Unknown validation error"}`;
898
- }
899
- function sourceLocationUris(sourceLocations) {
900
- return [...new Set([
901
- sourceLocations?.root?.uri,
902
- ...(sourceLocations?.states ?? []).map((location) => location.uri),
903
- ...(sourceLocations?.staticValues ?? []).map((location) => location.uri),
904
- ...(sourceLocations?.transitionFunctions ?? []).map((location) => location.uri)
905
- ].filter((uri) => Boolean(uri)))];
906
- }
907
- function stateSourceLocationUris(sourceLocations) {
908
- return [...new Set((sourceLocations?.states ?? []).map((location) => location.uri).filter(Boolean))];
909
- }
910
-
911
- //#endregion
912
- export { fetchEditorSyncAccess as a, createRemoteEditorSyncBackend as i, EditorHostWorkspaceSession as n, EditorSyncError as r, EditorHostSession as t };