@oomol-lab/open-flow 0.1.0-beta.77 → 0.1.0-beta.78

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 (58) hide show
  1. package/README.md +2 -0
  2. package/dist/browser/{ContentIcon-VZQO8VZU.js → ContentIcon-CMn0c-kl.js} +93 -3
  3. package/dist/browser/{FlowCanvas-BNGDMaWr.js → FlowCanvas-BQGBcfoL.js} +1675 -591
  4. package/dist/browser/{createResourceDialog-BmtakfVg.js → createResourceDialog-DCGxfKFM.js} +3 -3
  5. package/dist/browser/{dialog-BcFBfRB1.js → dialog-WzR4CRFH.js} +11 -81
  6. package/dist/browser/{exportSvg-CG8hEUNk.js → exportSvg-CYwyYiuH.js} +2 -2
  7. package/dist/browser/{flowChanges-BGo_4Ypo.js → flowChanges-Bz4dbDN_.js} +1204 -387
  8. package/dist/browser/{flowWorkspace-BFHGev7s.js → flowWorkspace-BI6L6a4r.js} +557 -597
  9. package/dist/browser/licenses.md +1 -1
  10. package/dist/browser/preview.css +512 -462
  11. package/dist/browser/preview.js +8457 -6732
  12. package/dist/browser/{tooltip-BAWSUexx.js → tooltip-BDcVTNpu.js} +65 -2
  13. package/dist/browser/ui.css +5 -24
  14. package/dist/browser/workbench.css +512 -462
  15. package/dist/browser/workbench.d.ts +2 -3
  16. package/dist/browser/workbench.js +65 -690
  17. package/dist/browser/{workbenchSelect-CjK-xdm3.js → workbenchSelect-DtAd0zc4.js} +2 -2
  18. package/dist/command/index.js +25 -25
  19. package/dist/common/authoring.d.ts +3 -3
  20. package/dist/common/authoringExamples.d.ts +3 -3
  21. package/dist/common/authoringSchema.d.ts +14 -22
  22. package/dist/common/control-api-conformance.js +11 -18
  23. package/dist/common/control-api.d.ts +5 -1
  24. package/dist/common/control-api.js +11 -18
  25. package/dist/common/control-requests.d.ts +4 -3
  26. package/dist/common/control-requests.js +26 -37
  27. package/dist/common/flow-authoring.js +6 -14
  28. package/dist/common/flow-change.d.ts +1 -1
  29. package/dist/common/flow-change.js +6 -14
  30. package/dist/common/flow-encoding.js +5 -13
  31. package/dist/common/flow-semantics.js +15 -21
  32. package/dist/common/flow-state.d.ts +16 -39
  33. package/dist/common/flow-state.js +47 -105
  34. package/dist/common/mcp.d.ts +3 -3
  35. package/dist/common/mcp.js +11 -18
  36. package/dist/common/run-events.js +19 -9
  37. package/dist/common/runtime-contract.js +6 -12
  38. package/dist/common/runtime-nodejs-compat.js +11 -12
  39. package/dist/common/scheduler.d.ts +2 -1
  40. package/dist/common/scheduler.js +56 -50
  41. package/dist/common/state-conformance.d.ts +3 -3
  42. package/package.json +1 -1
  43. package/src/control/common/api.ts +20 -3
  44. package/src/control/common/authoring.ts +6 -5
  45. package/src/control/common/authoringExamples.ts +6 -5
  46. package/src/control/common/authoringSchema.ts +7 -7
  47. package/src/control/common/requests.ts +7 -1
  48. package/src/execution/common/events.ts +22 -10
  49. package/src/execution/common/node-execution.ts +1 -1
  50. package/src/execution/common/scheduler.ts +28 -14
  51. package/src/flow/common/change.ts +1 -1
  52. package/src/flow/common/changeSchema.ts +4 -4
  53. package/src/flow/common/errorHandling.ts +1 -1
  54. package/src/flow/common/semantics.ts +12 -6
  55. package/src/runtime/common/nodejsGuest.generated.json +11 -12
  56. package/src/runtime/common/runtime.ts +6 -7
  57. package/src/state/common/conformance.ts +16 -21
  58. package/src/state/common/state.ts +44 -72
@@ -1,9 +1,9 @@
1
- import { C as DropdownMenuContent, N as DropdownMenuTrigger, T as DropdownMenuItem, d as PopoverContent, g as PopoverTrigger, h as PopoverTitle, it as providerIconAppearance, k as DropdownMenuSeparator, st as IconThemeContext, u as Popover, x as DropdownMenu } from "./ContentIcon-VZQO8VZU.js";
1
+ import { A as DropdownMenuSeparator, E as DropdownMenuItem, P as DropdownMenuTrigger, S as DropdownMenu, _ as PopoverTrigger, d as Popover, f as PopoverContent, g as PopoverTitle, ut as IconThemeContext, w as DropdownMenuContent } from "./ContentIcon-CMn0c-kl.js";
2
2
  import { a as derive, i as compute, l as val } from "./dist-bO8nvHFH.js";
3
3
  import { c as useLang, l as useTranslate, o as I18nProvider, u as useVal } from "./dist-BFmpkX4P.js";
4
- import { i as TooltipTrigger, n as TooltipContent, t as Tooltip, xr as cn, yr as Button } from "./tooltip-BAWSUexx.js";
5
- import { C as upgradeManualTrigger, It as dequal, M as mapConditionSources, N as nodeInputMappings, S as resourceNameIssue, _ as applyFlowChanges, a as DialogFooter, d as Field, g as FlowChangeError, h as FieldLabel, i as DialogDescription, l as Icon, m as FieldGroup, nn as Input, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner, v as isTriggerNode, w as upgradeRevisionContent } from "./dialog-BcFBfRB1.js";
6
- import { $ as connectorActionPorts, At as setConnectorConnection, Bn as triggerOutputDefinitions, Bt as FlowTagChips, C as updateValue, Ct as setComment, Dn as normalizeFlowQuery, Dt as repairNodeNames, En as WorkbenchClient, Et as setNodePositions, Ft as dequal$1, Gn as parseWorkflowFile, Hn as connection, It as WorkflowExportMenuItem, J as scopedValue, K as combineSources, Kn as workflowFileName, Lt as IdTooltip, Mt as setServiceConnections, Nt as updateStartInputDefs, On as randomId, Ot as resetInputValues, Pt as updateTriggerSchedule, Q as resourceValue, Rn as normalizeTriggerOutputs, S as updateTriggerConfig, Sn as createI18n, St as restoreCanvasPresentation, Tn as errorNotice, Tt as setNodeContentHidden, U as addNodeIntent, Un as connectorActionMetadata, Vt as TagPicker, W as deriveAddNodeOptions, Wn as encodeWorkflowFile, Y as CacheResource, Z as resourceData, _ as updateOutputPorts, _n as EmptyTitle, _t as connectionCatalog, a as nameCreatedNodes, at as RunStore, b as updateTaskAdditionalInputs, bt as flowPresentation, c as setInputVariable, cn as followWorkbenchLink, ct as revisionView, d as updateCondition, dn as InputGroupInput, dr as invalidResponse, dt as deriveInspectorDiagnostics, et as designerGraph, f as updateHttpParameters, fn as Empty, fr as jsonValue, ft as diagnosticItems, g as updateNodeSettings, gn as EmptyMedia, gr as controlErrorCode, gt as actionWithConnections, h as updateNodeName, hn as EmptyHeader, hr as ApiError, i as deleteSelection, it as providerIcon, jn as decodeTriggerCatalog, jt as setInputSources, kn as allConnectorConnectionsQuery, kt as setCodeActions, l as setTriggerConnection, ln as InputGroup, lt as flowResourceReferences, m as updateNodeIcon, mn as EmptyDescription, mr as string, o as selectWebhookResponse, p as updateNodeDescription, pn as EmptyContent, pr as record, qn as workflowNameFromFile, r as applyFlowChanges$1, s as setInputValue, sn as useFlowQuery, sr as workflowCandidate, t as addNode, u as setTriggerEventSource, un as InputGroupAddon, ut as Latest, v as updateResolution, vn as Badge, vt as canvasPresentationChange, w as updateWebhook, wt as setFlowViewport, x as updateTaskPorts, xt as removeComments, y as updateTask, yn as EventSourcesPage, yt as commentIds, zn as sampleErrorOutputs, zt as FlowSettingsDialog } from "./flowChanges-BGo_4Ypo.js";
4
+ import { Cr as cn, i as TooltipTrigger, n as TooltipContent, t as Tooltip, xr as Button } from "./tooltip-BDcVTNpu.js";
5
+ import { C as upgradeManualTrigger, It as dequal, M as mapConditionSources, N as nodeInputMappings, S as resourceNameIssue, _ as applyFlowChanges, a as DialogFooter, d as Field, g as FlowChangeError, h as FieldLabel, i as DialogDescription, l as Icon, m as FieldGroup, nn as Input, o as DialogHeader, p as FieldError, r as DialogContent, s as DialogTitle, t as Dialog, u as Spinner, v as isTriggerNode, w as upgradeRevisionContent } from "./dialog-WzR4CRFH.js";
6
+ import { $ as action, $n as triggerOutputDefinitions, $t as FlowTagChips, An as EmptyTitle, At as commentIds, Bn as normalizeFlowQuery, Bt as repairNodeNames, C as updateValue, Cn as InputGroupAddon, Ct as diagnosticItems, Dn as EmptyDescription, Dr as controlErrorCode, Dt as actionWithConnections, En as EmptyContent, Er as ApiError, Fn as createI18n, Ft as setComment, Gt as setServiceConnections, Hn as allConnectorConnectionsQuery, Ht as setCodeActions, It as setFlowViewport, J as scopedValue, Jt as dequal$1, K as combineSources, Kt as updateStartInputDefs, Lt as setNodeContentHidden, Mn as EventSourcesPage, Mt as removeComments, Nt as restoreCanvasPresentation, On as EmptyHeader, Ot as connectionCatalog, Pt as setCanvasLayout, Q as resourceValue, Qn as sampleErrorOutputs, Qt as FlowSettingsDialog, Rn as errorNotice, Rt as setNodePositions, S as updateTriggerConfig, Sn as InputGroup, St as deriveInspectorDiagnostics, Tn as Empty, Tr as record, U as addNodeIntent, Ut as setConnectorConnection, Vn as randomId, Vt as resetInputValues, W as deriveAddNodeOptions, Wn as decodeTriggerCatalog, Wt as setInputSources, Xt as IdTooltip, Y as CacheResource, Yt as WorkflowExportMenuItem, Z as resourceData, Zn as normalizeTriggerOutputs, _ as updateOutputPorts, a as nameCreatedNodes, ar as workflowFileName, b as updateTaskAdditionalInputs, bn as useFlowQuery, br as workflowCandidate, bt as flowResourceReferences, c as setInputVariable, ct as createPersistentCache, d as updateCondition, dt as designerGraph, en as TagPicker, et as provider, f as updateHttpParameters, g as updateNodeSettings, gt as RunStore, h as updateNodeName, ht as providerIcon, i as deleteSelection, ir as parseWorkflowFile, it as getActionsCache, jn as Badge, jt as flowPresentation, kn as EmptyMedia, kt as canvasPresentationChange, l as setTriggerConnection, lt as createSessionCache, m as updateNodeIcon, nr as connectorActionMetadata, nt as validateAction, o as selectWebhookResponse, or as workflowNameFromFile, ot as getConnectionsCache, p as updateNodeDescription, qt as updateTriggerSchedule, r as applyFlowChanges$1, rr as encodeWorkflowFile, s as setInputValue, st as getProvidersCache, t as addNode, tr as connection, tt as proxyResponse, u as setTriggerEventSource, v as updateResolution, w as updateWebhook, wn as InputGroupInput, wr as invalidResponse, x as updateTaskPorts, xn as followWorkbenchLink, xt as Latest, y as updateTask, yt as revisionView, zn as WorkbenchClient, zt as setVerticalNodeWidth } from "./flowChanges-Bz4dbDN_.js";
7
7
  import { a as uiLanguages, i as uiLanguageNames, n as isUiLanguage, r as resolveUiLanguage, t as importedWorkflowName } from "./languages-gYzoQqCi.js";
8
8
  import { i as objectValue, n as isJsonValue } from "./value-BbFQZZ_V.js";
9
9
  import { Suspense, forwardRef, lazy, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
@@ -517,7 +517,7 @@ function FlowDeletionDialog({ flow, workspace, container, busy, finalFocus, onCl
517
517
  }
518
518
  //#endregion
519
519
  //#region src/workbench/browser/runtime/shell/resourceBrowser.tsx
520
- var CreateResourceDialog = lazy(() => import("./createResourceDialog-BmtakfVg.js"));
520
+ var CreateResourceDialog = lazy(() => import("./createResourceDialog-DCGxfKFM.js"));
521
521
  var flowIdTooltipAlignOffset = 44;
522
522
  var renamePopoverAlignOffset = -12;
523
523
  function compactFlowId(flowId) {
@@ -2368,6 +2368,21 @@ var ActorStore = class {
2368
2368
  }
2369
2369
  };
2370
2370
  //#endregion
2371
+ //#region src/workbench/browser/runtime/stores/canvasDirection.ts
2372
+ var canvasDirectionPreferenceKey = "open-flow:canvas-direction";
2373
+ function readCanvasDirection(preferences) {
2374
+ try {
2375
+ return preferences.getItem("open-flow:canvas-direction") === "horizontal" ? "horizontal" : "vertical";
2376
+ } catch {
2377
+ return "vertical";
2378
+ }
2379
+ }
2380
+ function writeCanvasDirection(preferences, direction) {
2381
+ try {
2382
+ preferences.setItem(canvasDirectionPreferenceKey, direction);
2383
+ } catch {}
2384
+ }
2385
+ //#endregion
2371
2386
  //#region src/workbench/browser/runtime/stores/canvasInteractiveMode.ts
2372
2387
  var canvasInteractiveModePreferenceKey = "open-flow:canvas-interactive-mode";
2373
2388
  function readCanvasInteractiveMode(preferences) {
@@ -2384,676 +2399,6 @@ function writeCanvasInteractiveMode(preferences, mode) {
2384
2399
  } catch {}
2385
2400
  }
2386
2401
  //#endregion
2387
- //#region ../../node_modules/.bun/idb-keyval@6.3.0/node_modules/idb-keyval/dist/index.js
2388
- function promisifyRequest(request) {
2389
- return new Promise((resolve, reject) => {
2390
- request.oncomplete = request.onsuccess = () => resolve(request.result);
2391
- request.onabort = request.onerror = () => reject(request.error);
2392
- });
2393
- }
2394
- function createStore(dbName, storeName) {
2395
- let dbp;
2396
- const getDB = () => {
2397
- if (dbp) return dbp;
2398
- const request = indexedDB.open(dbName);
2399
- request.onupgradeneeded = () => request.result.createObjectStore(storeName);
2400
- dbp = promisifyRequest(request);
2401
- dbp.then((db) => {
2402
- db.onclose = () => dbp = void 0;
2403
- }, () => {
2404
- dbp = void 0;
2405
- });
2406
- return dbp;
2407
- };
2408
- return (txMode, callback) => getDB().then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
2409
- }
2410
- //#endregion
2411
- //#region ../../node_modules/.bun/@oomol-lab+resource-cache@0.1.4/node_modules/@oomol-lab/resource-cache/dist/src-bwD0r9NQ.mjs
2412
- function abortError() {
2413
- return new DOMException("Cache operation aborted", "AbortError");
2414
- }
2415
- function wait(promise, lifetime, caller) {
2416
- const signals = caller ? [lifetime, caller] : [lifetime];
2417
- return new Promise((resolve, reject) => {
2418
- const cleanup = () => {
2419
- for (const signal of signals) signal.removeEventListener("abort", abort);
2420
- };
2421
- const abort = () => {
2422
- cleanup();
2423
- reject(abortError());
2424
- };
2425
- for (const signal of signals) signal.addEventListener("abort", abort, { once: true });
2426
- promise.then((value) => {
2427
- cleanup();
2428
- resolve(value);
2429
- }, (error) => {
2430
- cleanup();
2431
- reject(error);
2432
- });
2433
- });
2434
- }
2435
- /** @internal */
2436
- function validateOptions(options) {
2437
- if (typeof options.namespace !== "string" || !options.namespace.trim()) throw new TypeError("namespace must be nonempty");
2438
- if (!Number.isSafeInteger(options.schemaVersion) || options.schemaVersion <= 0) throw new TypeError("schemaVersion must be a positive safe integer");
2439
- if (!Number.isFinite(options.maxAge) || options.maxAge < 0) throw new TypeError("maxAge must be finite and nonnegative");
2440
- for (const name of [
2441
- "key",
2442
- "decode",
2443
- "load"
2444
- ]) if (typeof options[name] !== "function") throw new TypeError(`${name} must be a function`);
2445
- }
2446
- /** @internal */
2447
- function createCache(options, backend, session) {
2448
- const states = /* @__PURE__ */ new Map();
2449
- let disposed = false;
2450
- let scopeBlocked = false;
2451
- let disposal;
2452
- let io = Promise.resolve();
2453
- function storage(action) {
2454
- const result = io.then(action);
2455
- io = result.catch(() => {});
2456
- return result;
2457
- }
2458
- function checkOpen() {
2459
- if (disposed) throw new Error("Cache is disposed");
2460
- }
2461
- function identity(query) {
2462
- checkOpen();
2463
- const key = options.key(query);
2464
- if (typeof key !== "string") throw new TypeError("key must return a string");
2465
- return key;
2466
- }
2467
- function stateFor(key) {
2468
- let state = states.get(key);
2469
- if (!state) {
2470
- state = {
2471
- controller: new AbortController(),
2472
- blocked: scopeBlocked
2473
- };
2474
- states.set(key, state);
2475
- }
2476
- return state;
2477
- }
2478
- function checkState(state) {
2479
- if (state.controller.signal.aborted) throw abortError();
2480
- }
2481
- function fresh(entry) {
2482
- const now = Date.now();
2483
- return !entry.invalidated && entry.validatedAt <= now && now - entry.validatedAt < options.maxAge;
2484
- }
2485
- function restore(value, previous) {
2486
- return {
2487
- ...value.meta,
2488
- data: value.body ? options.decode(value.body.data) : previous.data
2489
- };
2490
- }
2491
- async function read(key, state) {
2492
- if (state.entry && fresh(state.entry)) return state.entry;
2493
- const entry = await storage(async () => {
2494
- checkState(state);
2495
- if (state.blocked) return state.entry;
2496
- try {
2497
- const value = await backend.read(key, state.entry?.version);
2498
- return value ? restore(value, state.entry) : state.entry;
2499
- } catch {
2500
- return state.entry;
2501
- }
2502
- });
2503
- checkState(state);
2504
- state.entry = entry;
2505
- return entry;
2506
- }
2507
- function schedule(key, query, state, force) {
2508
- const job = {
2509
- started: false,
2510
- force
2511
- };
2512
- job.promise = (async () => {
2513
- const previous = await read(key, state);
2514
- checkState(state);
2515
- if (!job.force && previous && fresh(previous)) return previous.data;
2516
- job.started = true;
2517
- const result = await options.load(query, {
2518
- etag: previous?.etag ?? null,
2519
- signal: state.controller.signal
2520
- });
2521
- checkState(state);
2522
- let entry;
2523
- if (result.modified) entry = {
2524
- data: result.data,
2525
- etag: result.etag,
2526
- version: crypto.getRandomValues(/* @__PURE__ */ new Uint32Array(4)).join("-"),
2527
- validatedAt: Date.now(),
2528
- invalidated: false
2529
- };
2530
- else {
2531
- if (!previous) throw new Error("Load protocol error: unmodified response without cached data");
2532
- entry = {
2533
- ...previous,
2534
- etag: result.etag === void 0 ? previous.etag : result.etag,
2535
- validatedAt: Date.now(),
2536
- invalidated: false
2537
- };
2538
- }
2539
- await storage(async () => {
2540
- checkState(state);
2541
- try {
2542
- if (await backend.write(key, entry, result.modified)) state.blocked = false;
2543
- } catch {
2544
- state.blocked = true;
2545
- }
2546
- checkState(state);
2547
- state.entry = entry;
2548
- });
2549
- checkState(state);
2550
- return entry.data;
2551
- })();
2552
- state.job = job;
2553
- const release = () => {
2554
- state.job = void 0;
2555
- };
2556
- job.promise.then(release, release);
2557
- return job;
2558
- }
2559
- function refresh(key, query, state, force) {
2560
- const active = state.job;
2561
- if (!active) return schedule(key, query, state, force).promise;
2562
- if (!force) return active.promise;
2563
- if (!active.started) {
2564
- active.force = true;
2565
- return active.promise;
2566
- }
2567
- if (!state.queued) {
2568
- const start = () => {
2569
- checkState(state);
2570
- state.queued = void 0;
2571
- return schedule(key, query, state, true).promise;
2572
- };
2573
- state.queued = active.promise.then(start, start);
2574
- }
2575
- return state.queued;
2576
- }
2577
- function reset(key, keep) {
2578
- const old = states.get(key);
2579
- const state = {
2580
- controller: new AbortController(),
2581
- blocked: true
2582
- };
2583
- if (keep && old?.entry) state.entry = {
2584
- ...old.entry,
2585
- invalidated: true
2586
- };
2587
- states.set(key, state);
2588
- return {
2589
- state,
2590
- cancel: () => old?.controller.abort()
2591
- };
2592
- }
2593
- function resetAll() {
2594
- const old = [...states.values()];
2595
- states.clear();
2596
- const barrier = {};
2597
- scopeBlocked = barrier;
2598
- return {
2599
- barrier,
2600
- cancel() {
2601
- for (const state of old) state.controller.abort();
2602
- }
2603
- };
2604
- }
2605
- return {
2606
- async get(query, getOptions = {}) {
2607
- const key = identity(query);
2608
- if (getOptions.signal?.aborted) throw abortError();
2609
- const state = stateFor(key);
2610
- if (!getOptions.revalidate && state.entry && fresh(state.entry)) return state.entry.data;
2611
- return wait(refresh(key, query, state, getOptions.revalidate === true), state.controller.signal, getOptions.signal);
2612
- },
2613
- async peek(query) {
2614
- const key = identity(query);
2615
- const state = stateFor(key);
2616
- const entry = await wait(read(key, state), state.controller.signal);
2617
- return entry ? {
2618
- data: entry.data,
2619
- etag: entry.etag,
2620
- validatedAt: entry.validatedAt,
2621
- fresh: fresh(entry)
2622
- } : void 0;
2623
- },
2624
- async invalidate(query) {
2625
- const key = identity(query);
2626
- const canRestore = !(states.get(key)?.blocked ?? scopeBlocked);
2627
- const { state, cancel } = reset(key, true);
2628
- const cleanup = storage(async () => {
2629
- const value = await backend.invalidate(key);
2630
- if (canRestore) state.blocked = false;
2631
- if (canRestore && !state.controller.signal.aborted && !state.entry && value) try {
2632
- state.entry = restore(value);
2633
- } catch {}
2634
- });
2635
- cancel();
2636
- await cleanup;
2637
- },
2638
- async remove(query) {
2639
- const key = identity(query);
2640
- const { state, cancel } = reset(key, false);
2641
- const cleanup = storage(async () => {
2642
- await backend.remove(key);
2643
- state.blocked = false;
2644
- });
2645
- cancel();
2646
- await cleanup;
2647
- },
2648
- async clear() {
2649
- checkOpen();
2650
- const { barrier, cancel } = resetAll();
2651
- const cleanup = storage(async () => {
2652
- await backend.clear(false);
2653
- if (scopeBlocked === barrier) scopeBlocked = false;
2654
- for (const state of states.values()) if (state.blocked === barrier) state.blocked = false;
2655
- });
2656
- cancel();
2657
- await cleanup;
2658
- },
2659
- dispose() {
2660
- if (!disposal) {
2661
- disposed = true;
2662
- const { cancel } = resetAll();
2663
- disposal = storage(async () => {
2664
- if (session) await backend.clear(true);
2665
- });
2666
- disposal = disposal.catch((error) => {
2667
- disposal = void 0;
2668
- throw error;
2669
- });
2670
- cancel();
2671
- }
2672
- return disposal;
2673
- }
2674
- };
2675
- }
2676
- function object(value) {
2677
- return typeof value === "object" && value !== null;
2678
- }
2679
- function metadata(value) {
2680
- if (!object(value) || typeof value.version !== "string" || !value.version || !(value.etag === null || typeof value.etag === "string") || typeof value.invalidated !== "boolean") return void 0;
2681
- const validTime = typeof value.validatedAt === "number" && Number.isFinite(value.validatedAt) && value.validatedAt >= 0;
2682
- return {
2683
- version: value.version,
2684
- etag: value.etag,
2685
- validatedAt: validTime ? value.validatedAt : 0,
2686
- invalidated: !validTime || value.invalidated === true
2687
- };
2688
- }
2689
- function stored(meta, body) {
2690
- if (!object(body) || body.version !== meta.version || !Object.hasOwn(body, "data")) return void 0;
2691
- return {
2692
- meta,
2693
- body: { data: body.data }
2694
- };
2695
- }
2696
- var storagePrefix = "@oomol-lab/resource-cache:";
2697
- /** Delimit identity fields without ambiguous string concatenation. @internal */
2698
- function scope(namespace) {
2699
- return storagePrefix + JSON.stringify(namespace);
2700
- }
2701
- /** @internal */
2702
- function sessionScope(namespace, sessionId) {
2703
- return storagePrefix + JSON.stringify([namespace, sessionId]);
2704
- }
2705
- /** @internal */
2706
- function persistentStorage(namespace, schemaVersion) {
2707
- const useStore = createStore("@oomol-lab/resource-cache", "records");
2708
- const prefix = `${scope(namespace)}:${schemaVersion}:`;
2709
- const identity = (key, part) => prefix + JSON.stringify([key, part]);
2710
- function transaction(mode, work) {
2711
- return useStore(mode, (store) => new Promise((resolve, reject) => {
2712
- const tx = store.transaction;
2713
- let value;
2714
- let failure;
2715
- tx.oncomplete = () => resolve(value);
2716
- tx.onabort = () => reject(failure ?? tx.error);
2717
- const guard = (fn) => {
2718
- try {
2719
- fn();
2720
- } catch (error) {
2721
- failure = error;
2722
- tx.abort();
2723
- }
2724
- };
2725
- const read = (request, fn) => {
2726
- request.onsuccess = () => guard(() => fn(request.result));
2727
- };
2728
- guard(() => work(store, read, (result) => {
2729
- value = result;
2730
- }));
2731
- }));
2732
- }
2733
- return {
2734
- read(key, version) {
2735
- return transaction("readonly", (store, read, result) => {
2736
- read(store.get(identity(key, "meta")), (raw) => {
2737
- const meta = metadata(raw);
2738
- if (!meta) return;
2739
- if (meta.version === version) {
2740
- result({ meta });
2741
- return;
2742
- }
2743
- read(store.get(identity(key, "body")), (body) => result(stored(meta, body)));
2744
- });
2745
- });
2746
- },
2747
- write(key, entry, modified) {
2748
- return transaction("readwrite", (store, read, result) => {
2749
- const { data, ...meta } = entry;
2750
- if (modified) {
2751
- store.put(meta, identity(key, "meta"));
2752
- store.put({
2753
- version: meta.version,
2754
- data
2755
- }, identity(key, "body"));
2756
- result(true);
2757
- } else read(store.get(identity(key, "meta")), (raw) => {
2758
- const matches = metadata(raw)?.version === meta.version;
2759
- if (matches) store.put(meta, identity(key, "meta"));
2760
- result(matches);
2761
- });
2762
- });
2763
- },
2764
- invalidate(key) {
2765
- return transaction("readwrite", (store, read, result) => {
2766
- read(store.get(identity(key, "meta")), (raw) => {
2767
- const meta = metadata(raw);
2768
- if (!meta) return;
2769
- meta.invalidated = true;
2770
- store.put(meta, identity(key, "meta"));
2771
- read(store.get(identity(key, "body")), (body) => result(stored(meta, body)));
2772
- });
2773
- });
2774
- },
2775
- remove(key) {
2776
- return transaction("readwrite", (store) => {
2777
- store.delete(identity(key, "meta"));
2778
- store.delete(identity(key, "body"));
2779
- });
2780
- },
2781
- clear() {
2782
- return transaction("readwrite", (store, read) => {
2783
- read(store.getAllKeys(), (keys) => {
2784
- for (const key of keys) if (typeof key === "string" && key.startsWith(prefix)) store.delete(key);
2785
- });
2786
- });
2787
- }
2788
- };
2789
- }
2790
- /** @internal */
2791
- function sessionStorageBackend(namespace, schemaVersion, sessionId) {
2792
- const base = `${sessionScope(namespace, sessionId)}:`;
2793
- const prefix = `${base}${schemaVersion}:`;
2794
- const identity = (key) => prefix + JSON.stringify(key);
2795
- const record = (key) => {
2796
- const text = globalThis.sessionStorage.getItem(identity(key));
2797
- if (text === null) return void 0;
2798
- const raw = JSON.parse(text);
2799
- const meta = metadata(raw);
2800
- return meta ? stored(meta, raw) : void 0;
2801
- };
2802
- return {
2803
- async read(key, version) {
2804
- const value = record(key);
2805
- if (value && value.meta.version === version) return { meta: value.meta };
2806
- return value;
2807
- },
2808
- async write(key, entry, modified) {
2809
- if (modified) {
2810
- globalThis.sessionStorage.setItem(identity(key), JSON.stringify(entry));
2811
- return true;
2812
- } else {
2813
- const value = record(key);
2814
- if (value?.meta.version === entry.version) {
2815
- const { data: _data, ...meta } = entry;
2816
- globalThis.sessionStorage.setItem(identity(key), JSON.stringify({
2817
- ...meta,
2818
- data: value.body.data
2819
- }));
2820
- return true;
2821
- }
2822
- return false;
2823
- }
2824
- },
2825
- async invalidate(key) {
2826
- const value = record(key);
2827
- if (value) {
2828
- value.meta.invalidated = true;
2829
- globalThis.sessionStorage.setItem(identity(key), JSON.stringify({
2830
- ...value.meta,
2831
- ...value.body
2832
- }));
2833
- }
2834
- return value;
2835
- },
2836
- async remove(key) {
2837
- globalThis.sessionStorage.removeItem(identity(key));
2838
- },
2839
- async clear(allVersions) {
2840
- const storage = globalThis.sessionStorage;
2841
- const matches = [];
2842
- for (let i = 0; i < storage.length; i++) {
2843
- const key = storage.key(i);
2844
- if (key.startsWith(allVersions ? base : prefix)) matches.push(key);
2845
- }
2846
- for (const key of matches) storage.removeItem(key);
2847
- }
2848
- };
2849
- }
2850
- /** Create an IndexedDB cache. Storage failures preserve successful network results. */
2851
- function createPersistentCache(options) {
2852
- validateOptions(options);
2853
- return createCache({ ...options }, persistentStorage(options.namespace, options.schemaVersion), false);
2854
- }
2855
- /** Create a login-scoped sessionStorage cache. Data must survive JSON serialization and decoding. */
2856
- function createSessionCache(options) {
2857
- validateOptions(options);
2858
- if (typeof options.sessionId !== "string" || !options.sessionId.trim()) throw new TypeError("sessionId must be nonempty");
2859
- return createCache({ ...options }, sessionStorageBackend(options.namespace, options.schemaVersion, options.sessionId), true);
2860
- }
2861
- //#endregion
2862
- //#region ../../node_modules/.bun/@oomol-lab+resource-cache@0.1.4/node_modules/@oomol-lab/resource-cache/dist/oomol.mjs
2863
- /** Namespaces reserved for the OOMOL response factories. */
2864
- var oomolNamespaces = {
2865
- providers: "oomol:providers",
2866
- actions: "oomol:actions",
2867
- appCatalog: "oomol:app-catalog",
2868
- connections: "oomol:connections"
2869
- };
2870
- /** Join identity fields without nesting JSON in the storage key. */
2871
- function readableKey(...parts) {
2872
- return parts.map((part) => encodeURIComponent(String(part)).replaceAll("%3A", ":")).join("/");
2873
- }
2874
- var singletonRegistrySymbol = Symbol.for("oomol-lab.resource-cache.oomol-singletons");
2875
- var singletonCaches = Reflect.get(globalThis, singletonRegistrySymbol) ?? (() => {
2876
- const registry = /* @__PURE__ */ new Map();
2877
- Reflect.set(globalThis, singletonRegistrySymbol, registry);
2878
- return registry;
2879
- })();
2880
- function createOomolCache(resource, options, query) {
2881
- const environment = validateOomolOptions(options);
2882
- const { load } = options;
2883
- const key = readableKey(query.locale);
2884
- return createPersistentCache({
2885
- namespace: readableKey(resource, environment),
2886
- schemaVersion: options.schemaVersion,
2887
- maxAge: options.maxAge,
2888
- key: () => key,
2889
- decode: options.decode,
2890
- load: (_query, validation) => load({ ...query }, validation)
2891
- });
2892
- }
2893
- function createConnectionsCacheInternal(options, validated) {
2894
- const { environment, ownerId } = validated;
2895
- const { load } = options;
2896
- const key = readableKey(ownerId);
2897
- return createSessionCache({
2898
- namespace: readableKey(oomolNamespaces.connections, environment),
2899
- schemaVersion: options.schemaVersion,
2900
- maxAge: options.maxAge,
2901
- sessionId: options.sessionId,
2902
- key: () => key,
2903
- decode: options.decode,
2904
- load: (_query, validation) => load({ ownerId }, validation)
2905
- });
2906
- }
2907
- function validateOomolOptions(options) {
2908
- const environment = normalizeEnvironment(options.environment);
2909
- if (typeof options.locale !== "string" || !options.locale.trim()) throw new TypeError("locale must be nonempty");
2910
- if (typeof options.load !== "function") throw new TypeError("load must be a function");
2911
- return environment;
2912
- }
2913
- function normalizeEnvironment(value) {
2914
- const environment = value === void 0 ? "production" : value;
2915
- if (typeof environment !== "string" || !environment.trim()) throw new TypeError("environment must be nonempty");
2916
- return environment;
2917
- }
2918
- function normalizeOwnerId(value) {
2919
- if (typeof value !== "string" || !value.trim()) throw new TypeError("ownerId must be nonempty");
2920
- return value;
2921
- }
2922
- function validateConnectionsOptions(options) {
2923
- const environment = normalizeEnvironment(options.environment);
2924
- if (typeof options.sessionId !== "string" || !options.sessionId.trim()) throw new TypeError("sessionId must be nonempty");
2925
- const ownerId = normalizeOwnerId(options.ownerId);
2926
- if (typeof options.load !== "function") throw new TypeError("load must be a function");
2927
- return {
2928
- environment,
2929
- ownerId
2930
- };
2931
- }
2932
- /** Create an IndexedDB cache for the account-independent GET /v1/providers response, keyed by environment and locale. */
2933
- function createProvidersCacheInternal(options) {
2934
- return createOomolCache(oomolNamespaces.providers, options, { locale: options.locale });
2935
- }
2936
- /** Create an IndexedDB cache for account-independent GET /v1/actions?service=…, keyed by environment, locale and service. */
2937
- function createActionsCacheInternal(options) {
2938
- const environment = validateOomolOptions(options);
2939
- const { locale, load } = options;
2940
- return createPersistentCache({
2941
- namespace: readableKey(oomolNamespaces.actions, environment),
2942
- schemaVersion: options.schemaVersion,
2943
- maxAge: options.maxAge,
2944
- key: (service) => {
2945
- if (typeof service !== "string" || !service.trim()) throw new TypeError("service must be nonempty");
2946
- return readableKey(locale, service);
2947
- },
2948
- decode: options.decode,
2949
- load: (service, validation) => load({
2950
- locale,
2951
- service
2952
- }, validation)
2953
- });
2954
- }
2955
- function singletonKey(resource, options, query, sessionId) {
2956
- const environment = normalizeEnvironment(options.environment);
2957
- return sessionId === void 0 ? readableKey(resource, environment, options.schemaVersion, ...query) : readableKey(resource, environment, options.schemaVersion, sessionId, ...query);
2958
- }
2959
- function getSingleton(key, create) {
2960
- const existing = singletonCaches.get(key);
2961
- if (existing) return existing;
2962
- const cache = create();
2963
- let disposal;
2964
- const singleton = {
2965
- ...cache,
2966
- dispose() {
2967
- if (!disposal) disposal = cache.dispose().then(() => {
2968
- singletonCaches.delete(key);
2969
- }, (error) => {
2970
- disposal = void 0;
2971
- throw error;
2972
- });
2973
- return disposal;
2974
- }
2975
- };
2976
- singletonCaches.set(key, singleton);
2977
- return singleton;
2978
- }
2979
- /** Return the shared Providers cache for one environment, locale and schema version. */
2980
- function getProvidersCache(options) {
2981
- const query = { locale: options.locale };
2982
- return getSingleton(singletonKey(oomolNamespaces.providers, options, [query.locale]), () => createProvidersCacheInternal(options));
2983
- }
2984
- /** Return the shared Actions cache for one environment, locale and schema version. */
2985
- function getActionsCache(options) {
2986
- const query = { locale: options.locale };
2987
- return getSingleton(singletonKey(oomolNamespaces.actions, options, [query.locale]), () => createActionsCacheInternal(options));
2988
- }
2989
- /** Return the shared sessionStorage cache for one login session and owner scope. */
2990
- function getConnectionsCache(options) {
2991
- const validated = validateConnectionsOptions(options);
2992
- const query = { ownerId: validated.ownerId };
2993
- return getSingleton(singletonKey(oomolNamespaces.connections, options, [query.ownerId], options.sessionId), () => createConnectionsCacheInternal(options, validated));
2994
- }
2995
- //#endregion
2996
- //#region src/workbench/browser/runtime/stores/proxyCatalog.ts
2997
- /** Validate the fields we consume without discarding upstream representation fields. */
2998
- function proxyResponse(value, validate) {
2999
- const source = record(value);
3000
- if (source.success === false) throw new ApiError(502, typeof source.errorCode == "string" ? source.errorCode : "connector.unavailable", typeof source.message == "string" ? source.message : "Connector request failed.");
3001
- if (source.success !== true || !Array.isArray(source.data)) return invalidResponse();
3002
- if (validate != null) for (const item of source.data) validate(record(item));
3003
- return source;
3004
- }
3005
- function provider(source, metadata) {
3006
- if (!Array.isArray(source.authTypes) || source.authTypes.some((item) => typeof item != "string")) return invalidResponse();
3007
- return {
3008
- ...providerIconAppearance(metadata, source.iconSpritePosition),
3009
- serviceId: string(source.service),
3010
- serviceName: string(source.displayName),
3011
- noSetup: source.authTypes.length == 1 && source.authTypes[0] == "no_auth",
3012
- ...source.iconUrl == null || source.iconUrl === "" ? {} : { icon: string(source.iconUrl) },
3013
- ...source.homepageUrl == null || source.homepageUrl === "" ? {} : { homepageUrl: string(source.homepageUrl) }
3014
- };
3015
- }
3016
- function validateAction(source) {
3017
- string(source.id);
3018
- string(source.service);
3019
- string(source.name);
3020
- if (typeof source.description != "string") return invalidResponse();
3021
- connectorActionPorts(source.inputSchema, source.outputSchema);
3022
- }
3023
- function port(item) {
3024
- return {
3025
- nullable: item.nullable,
3026
- jsonSchema: jsonValue(item.json_schema),
3027
- ...item.description == null ? {} : { description: item.description },
3028
- ...item.value === void 0 ? {} : { value: jsonValue(item.value) }
3029
- };
3030
- }
3031
- function action(source, providers) {
3032
- const owner = providers.data.find((item) => item.service == source.service);
3033
- if (owner == null) return invalidResponse();
3034
- const display = provider(owner, providers.meta?.iconSprite);
3035
- const ports = connectorActionPorts(source.inputSchema, source.outputSchema);
3036
- return {
3037
- ...display.iconSprite == null ? {} : {
3038
- iconSprite: display.iconSprite,
3039
- iconSpritePosition: display.iconSpritePosition
3040
- },
3041
- serviceId: display.serviceId,
3042
- serviceName: display.serviceName,
3043
- ...display.icon == null ? {} : { icon: display.icon },
3044
- ...display.homepageUrl == null ? {} : { homepageUrl: display.homepageUrl },
3045
- actionId: string(source.id),
3046
- ...source.operationType == null ? {} : { operationType: string(source.operationType) },
3047
- name: string(source.name),
3048
- description: source.description,
3049
- authenticated: !owner.authTypes.includes("no_auth"),
3050
- inputSchema: jsonValue(source.inputSchema),
3051
- outputSchema: jsonValue(source.outputSchema),
3052
- inputs: Object.fromEntries(ports.inputs.map((item) => [item.handle, port(item)])),
3053
- outputs: Object.fromEntries(ports.outputs.map((item) => [item.handle, port(item)]))
3054
- };
3055
- }
3056
- //#endregion
3057
2402
  //#region src/workbench/browser/runtime/stores/catalogStores.ts
3058
2403
  var catalogMaxAge = {
3059
2404
  providers: 3e5,
@@ -4423,8 +3768,11 @@ var FlowCatalog = class {
4423
3768
  this.#pending.delete(flow.flowId);
4424
3769
  }
4425
3770
  }
4426
- create(name, create, tagIds) {
4427
- return this.#create(async () => create == null ? tagIds == null ? this.#client.createFlow(name) : this.#client.createFlow(name, void 0, void 0, tagIds) : this.#client.getFlow(await (tagIds == null ? create(name) : create(name, { tagIds }))));
3771
+ create(name, create, tagIds, presentation) {
3772
+ return this.#create(async () => create == null ? this.#client.createFlow(name, void 0, void 0, tagIds, presentation) : this.#client.getFlow(await (tagIds == null && presentation == null ? create(name) : create(name, {
3773
+ ...tagIds == null ? {} : { tagIds },
3774
+ ...presentation == null ? {} : { presentation }
3775
+ }))));
4428
3776
  }
4429
3777
  import(file, name, key, importer, tagIds) {
4430
3778
  return this.#create(async () => importer == null ? this.#client.importFlow(file, {
@@ -4691,11 +4039,11 @@ function target(selection) {
4691
4039
  triggerId: selection.id
4692
4040
  };
4693
4041
  }
4694
- function option(definition, i18n, display) {
4042
+ function option(definition, i18n, display, provider) {
4695
4043
  return {
4696
4044
  description: display?.description ?? definition.description,
4697
4045
  group: i18n.t("addNode.integrationTriggers"),
4698
- icon: providerIcon({
4046
+ icon: providerIcon(provider ?? {
4699
4047
  serviceId: definition.provider,
4700
4048
  serviceName: definition.provider
4701
4049
  }),
@@ -4787,6 +4135,7 @@ var TriggerStore = class {
4787
4135
  return scopedValue(signal, (get) => {
4788
4136
  const state = get(source);
4789
4137
  get(this.#i18n.t$);
4138
+ const providers = get(this.#workspace.catalogs.providers.get(void 0, this.#i18n.lang)).data;
4790
4139
  const enabled = get(this.#workspace.$.flowId) != null && get(this.#workspace.$.draft) != null;
4791
4140
  const catalog = state.data;
4792
4141
  const definitions = catalog?.definitions.filter((item) => !query || [
@@ -4801,7 +4150,7 @@ var TriggerStore = class {
4801
4150
  ].some((value) => value?.toLowerCase().includes(query)));
4802
4151
  return {
4803
4152
  ...state,
4804
- data: !enabled ? [] : definitions?.map((definition) => option(definition, this.#i18n, catalog.display[definition.key]))
4153
+ data: !enabled ? [] : definitions?.map((definition) => option(definition, this.#i18n, catalog.display[definition.key], providers?.find((provider) => provider.serviceId == definition.provider)))
4805
4154
  };
4806
4155
  });
4807
4156
  }
@@ -5048,6 +4397,7 @@ var CanvasClipboard = class {
5048
4397
  copy(revision, graph, nodeIds) {
5049
4398
  const selected = new Set(nodeIds);
5050
4399
  this.#value = {
4400
+ verticalNodeWidths: Object.fromEntries(graph.nodes.flatMap((node) => node.kind === "condition" && node.verticalWidth != null && selected.has(node.id) ? [[node.id, node.verticalWidth]] : [])),
5051
4401
  hiddenNodeIds: graph.nodes.flatMap((node) => node.contentHidden && selected.has(node.id) ? [node.id] : []),
5052
4402
  comments: graph.nodes.flatMap((node) => node.kind == "comment" && selected.has(node.id) ? [{
5053
4403
  content: node.content,
@@ -5064,6 +4414,7 @@ var CanvasClipboard = class {
5064
4414
  }) {
5065
4415
  if (this.#value == null) return;
5066
4416
  const hiddenNodeIds = new Set(this.#value.hiddenNodeIds);
4417
+ const verticalNodeWidths = this.#value.verticalNodeWidths;
5067
4418
  const pasted = pasteNodes(revision, this.#value.nodes, this.identity);
5068
4419
  const comments = this.#value.comments.map((comment) => ({
5069
4420
  ...comment,
@@ -5091,7 +4442,10 @@ var CanvasClipboard = class {
5091
4442
  nodeIds: [...pasted.nodeIds, ...comments.map((comment) => comment.nodeId)],
5092
4443
  update: (value) => {
5093
4444
  let next = setNodePositions(value, positions);
5094
- for (const [index, sourceId] of pasted.sourceIds.entries()) if (hiddenNodeIds.has(sourceId)) next = setNodeContentHidden(next, pasted.nodeIds[index], true);
4445
+ for (const [index, sourceId] of pasted.sourceIds.entries()) {
4446
+ if (hiddenNodeIds.has(sourceId)) next = setNodeContentHidden(next, pasted.nodeIds[index], true);
4447
+ if (verticalNodeWidths[sourceId] != null) next = setVerticalNodeWidth(next, pasted.nodeIds[index], verticalNodeWidths[sourceId]);
4448
+ }
5095
4449
  for (const comment of comments) {
5096
4450
  if (hiddenNodeIds.has(comment.sourceId)) next = setNodeContentHidden(next, comment.nodeId, true);
5097
4451
  next = setComment(next, comment.nodeId, {
@@ -6237,7 +5591,7 @@ var EditSession = class {
6237
5591
  if (draft == null || presentation == null) return false;
6238
5592
  const next = update?.(presentation.value) ?? presentation.value;
6239
5593
  const presentationChange = canvasPresentationChange(presentation.value, next);
6240
- if (dequal(applyFlowChanges$1(draft, changes).content, draft.content) && presentationChange.nodeIds.length == 0) return true;
5594
+ if (dequal(applyFlowChanges$1(draft, changes).content, draft.content) && presentationChange.nodeIds.length == 0 && !presentationChange.directionChanged) return true;
6241
5595
  const generation = this.#history.generation;
6242
5596
  const inverse = inverseFlowChanges(draft.content, changes);
6243
5597
  this.#history.beginChange();
@@ -6941,8 +6295,8 @@ var WorkspaceStore = class {
6941
6295
  this.#edits.set({ busy: void 0 });
6942
6296
  }
6943
6297
  }
6944
- createFlow(name, create, tagIds) {
6945
- return this.#createFlow(() => this.#flows.create(name, create, tagIds));
6298
+ createFlow(name, create, tagIds, presentation) {
6299
+ return this.#createFlow(() => this.#flows.create(name, create, tagIds, presentation));
6946
6300
  }
6947
6301
  importFlow(file, name, key, importer, tagIds) {
6948
6302
  return this.#createFlow(() => this.#flows.import(file, name, key, importer, tagIds));
@@ -7071,7 +6425,10 @@ var WorkspaceStore = class {
7071
6425
  const changes = deleteSelection(revision, this.#model.value.selectedNodeIds);
7072
6426
  await this.#edits.canvasChange("delete", this.#model.value.selectedNodeIds.length, changes, (value) => {
7073
6427
  let next = commentNodes.size == 0 ? value : removeComments(value, commentNodes);
7074
- for (const nodeId of selectedNodeIds) next = setNodeContentHidden(next, nodeId, false);
6428
+ for (const nodeId of selectedNodeIds) {
6429
+ next = setNodeContentHidden(next, nodeId, false);
6430
+ next = setVerticalNodeWidth(next, nodeId, void 0);
6431
+ }
7075
6432
  return next;
7076
6433
  }, []);
7077
6434
  }
@@ -7096,6 +6453,13 @@ var WorkspaceStore = class {
7096
6453
  if (node == null || node.kind == "condition") return;
7097
6454
  await this.#edits.canvasChange("edit", 1, [], (value) => setNodeContentHidden(value, nodeId, hidden));
7098
6455
  }
6456
+ async saveNodeWidth(nodeId, width, position) {
6457
+ if (this.#model.value.draft == null || !this.#designer().nodes.some((node) => node.id === nodeId && node.kind === "condition")) return false;
6458
+ return await this.#edits.canvasChange("edit", 1, [], (value) => {
6459
+ const next = setVerticalNodeWidth(value, nodeId, width);
6460
+ return position == null ? next : setNodePositions(next, { [nodeId]: position });
6461
+ });
6462
+ }
7099
6463
  async saveComment(nodeId, comment) {
7100
6464
  if (this.#model.value.draft == null) return;
7101
6465
  const position = this.#designer().nodes.find((node) => node.id == nodeId)?.position;
@@ -7153,6 +6517,9 @@ var WorkspaceStore = class {
7153
6517
  saveModuleEditor() {
7154
6518
  return this.#edits.saveModuleEditor();
7155
6519
  }
6520
+ async changeDirection(direction, positions) {
6521
+ return await this.#edits.canvasChange("move", Object.keys(positions).length, [], (value) => setCanvasLayout(value, direction, positions));
6522
+ }
7156
6523
  async moveNodes(positions) {
7157
6524
  if (this.#model.value.draft == null) return;
7158
6525
  await this.#edits.canvasChange("move", Object.keys(positions).length, [], (value) => setNodePositions(value, positions));
@@ -7264,6 +6631,7 @@ var WorkbenchStore = class {
7264
6631
  #openingCreatedFlow;
7265
6632
  #stopAccessReaction;
7266
6633
  #accessLoading;
6634
+ #defaultDirection;
7267
6635
  constructor(client, preferences, identity = randomId, i18n = createI18n(), host = blockedExternalPages, variables = true, cacheSessionId = crypto.randomUUID()) {
7268
6636
  this.#externalRuns = new Latest();
7269
6637
  this.#notice = val();
@@ -7284,6 +6652,7 @@ var WorkbenchStore = class {
7284
6652
  this.provideAddNodeOptionChoices = (optionId, signal) => this.connectors.provideAddNodeOptionChoices(optionId, signal);
7285
6653
  this.actors = new ActorStore(host.resolveActor);
7286
6654
  this.preferences = preferences;
6655
+ this.#defaultDirection = readCanvasDirection(preferences);
7287
6656
  this.interactiveMode$ = val(readCanvasInteractiveMode(preferences));
7288
6657
  this.interactiveMode$.reaction((mode) => writeCanvasInteractiveMode(preferences, mode), true);
7289
6658
  this.#client = client;
@@ -7449,7 +6818,7 @@ var WorkbenchStore = class {
7449
6818
  const model = this.$.designer.value;
7450
6819
  const title = this.workspace.$.flow.value?.name ?? this.workspace.$.flowId.value ?? "Workflow";
7451
6820
  try {
7452
- const { downloadFlowSvg } = await import("./exportSvg-CG8hEUNk.js");
6821
+ const { downloadFlowSvg } = await import("./exportSvg-CYwyYiuH.js");
7453
6822
  await downloadFlowSvg(model, title, language, options);
7454
6823
  if (!this.#disposed) this.#notice.set({
7455
6824
  kind: "success",
@@ -7516,7 +6885,13 @@ var WorkbenchStore = class {
7516
6885
  return await this.#openNewFlow(await this.workspace.importFlow(file, name, key, importer, tagIds), "notice.flowImported");
7517
6886
  }
7518
6887
  async createFlow(name, create, tagIds) {
7519
- return await this.#openNewFlow(await this.workspace.createFlow(name, create, tagIds));
6888
+ return await this.#openNewFlow(await this.workspace.createFlow(name, create, tagIds, setCanvasLayout({}, this.#defaultDirection)));
6889
+ }
6890
+ async changeDirection(direction, positions) {
6891
+ if (!await this.workspace.changeDirection(direction, positions)) return false;
6892
+ this.#defaultDirection = direction;
6893
+ writeCanvasDirection(this.preferences, direction);
6894
+ return true;
7520
6895
  }
7521
6896
  async #openNewFlow(created, notice) {
7522
6897
  if (this.#disposed || created == null) return false;
@@ -7703,7 +7078,7 @@ var WorkbenchStore = class {
7703
7078
  };
7704
7079
  //#endregion
7705
7080
  //#region src/workbench/browser/runtime/openFlowWorkbench.tsx
7706
- var FlowWorkspace = lazy(() => import("./flowWorkspace-BFHGev7s.js"));
7081
+ var FlowWorkspace = lazy(() => import("./flowWorkspace-BI6L6a4r.js"));
7707
7082
  function OpenFlowSessionGate({ action, description, error, onSubmit, onTokenChange, pending = false, title, token, tokenLabel }) {
7708
7083
  const hasToken = token != null && tokenLabel != null && onTokenChange != null;
7709
7084
  const tokenValue = token ?? "";
@@ -7809,8 +7184,7 @@ function FlowNameBridge({ store, onChange }) {
7809
7184
  useEffect(() => () => onChange(void 0), [onChange]);
7810
7185
  return null;
7811
7186
  }
7812
- function Workbench({ importRef, catalogWidth, createFlow, importFlow, createFlowDisabled, createFlowField, connectionHref, hrefFor, initializing, language, navigation, onConfigureConnector, onManageConnectorAccess, onLanguageChange, store, theme }) {
7813
- const flowId = useVal(store.workspace.$.flowId);
7187
+ function Workbench({ importRef, catalogWidth, createFlow, importFlow, createFlowDisabled, createFlowField, connectionHref, hrefFor, flowId, initializing, language, navigation, onConfigureConnector, onManageConnectorAccess, onLanguageChange, store, theme }) {
7814
7188
  return /* @__PURE__ */ jsx("div", {
7815
7189
  className: "app-shell",
7816
7190
  children: flowId == null ? /* @__PURE__ */ jsx(FlowBrowser, {
@@ -7920,6 +7294,7 @@ var Session = forwardRef(function Session({ catalogWidth, createFlow, importFlow
7920
7294
  createFlowField,
7921
7295
  connectionHref,
7922
7296
  hrefFor,
7297
+ flowId: location.flowId,
7923
7298
  initializing: !started,
7924
7299
  language,
7925
7300
  navigation,