@flowdrop/flowdrop 1.14.0 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +475 -0
- package/MIGRATION-2.0.md +472 -0
- package/README.md +23 -23
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +14 -8
- package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
- package/dist/chat/batchFeedback.d.ts +39 -0
- package/dist/chat/batchFeedback.js +51 -0
- package/dist/commands/executor.js +15 -1
- package/dist/commands/storeIntegration.svelte.d.ts +4 -1
- package/dist/commands/storeIntegration.svelte.js +26 -21
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/App.svelte +162 -192
- package/dist/components/App.svelte.d.ts +47 -8
- package/dist/components/ConfigForm.svelte +110 -66
- package/dist/components/ConfigModal.svelte +7 -2
- package/dist/components/ConnectionLine.svelte +4 -2
- package/dist/components/Navbar.svelte +61 -1
- package/dist/components/NodeSidebar.svelte +27 -45
- package/dist/components/NodeStatusOverlay.svelte +94 -6
- package/dist/components/NodeSwapPicker.svelte +10 -8
- package/dist/components/PipelineStatus.svelte +16 -67
- package/dist/components/PortCoordinateTracker.svelte +5 -6
- package/dist/components/SchemaForm.stories.svelte +1 -3
- package/dist/components/SchemaForm.svelte +45 -40
- package/dist/components/SchemaForm.svelte.d.ts +0 -8
- package/dist/components/SettingsModal.svelte +8 -3
- package/dist/components/SettingsPanel.svelte +20 -4
- package/dist/components/SwapMappingEditor.svelte +67 -49
- package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
- package/dist/components/UniversalNode.svelte +9 -7
- package/dist/components/WorkflowEditor.svelte +118 -111
- package/dist/components/WorkflowEditor.svelte.d.ts +18 -10
- package/dist/components/chat/AIChatPanel.svelte +93 -89
- package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
- package/dist/components/chat/CommandPreview.svelte +2 -1
- package/dist/components/console/CommandConsole.svelte +7 -5
- package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
- package/dist/components/console/ConsoleInput.svelte +15 -6
- package/dist/components/console/ConsoleOutput.svelte +2 -1
- package/dist/components/form/FormArray.svelte +5 -9
- package/dist/components/form/FormArray.svelte.d.ts +2 -1
- package/dist/components/form/FormAutocomplete.svelte +29 -13
- package/dist/components/form/FormField.svelte +4 -2
- package/dist/components/form/FormFieldLight.svelte +4 -2
- package/dist/components/form/FormMarkdownEditor.svelte +9 -4
- package/dist/components/form/FormRangeField.svelte +1 -0
- package/dist/components/form/FormTemplateEditor.svelte +11 -3
- package/dist/components/form/FormToggle.svelte +5 -12
- package/dist/components/form/FormToggle.svelte.d.ts +4 -2
- package/dist/components/form/templateAutocomplete.js +1 -5
- package/dist/components/form/types.d.ts +1 -14
- package/dist/components/interrupt/FormPrompt.svelte +3 -2
- package/dist/components/interrupt/InterruptBubble.svelte +16 -17
- package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
- package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
- package/dist/components/layouts/MainLayout.svelte +20 -13
- package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
- package/dist/components/nodes/AtomNode.svelte +292 -0
- package/dist/components/nodes/AtomNode.svelte.d.ts +26 -0
- package/dist/components/nodes/GatewayNode.svelte +19 -10
- package/dist/components/nodes/IdeaNode.svelte +7 -0
- package/dist/components/nodes/SimpleNode.svelte +11 -6
- package/dist/components/nodes/SquareNode.svelte +15 -8
- package/dist/components/nodes/TerminalNode.svelte +9 -4
- package/dist/components/nodes/ToolNode.svelte +7 -1
- package/dist/components/nodes/WorkflowNode.svelte +16 -7
- package/dist/components/playground/ChatInput.svelte +11 -14
- package/dist/components/playground/ChatPanel.svelte +6 -49
- package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
- package/dist/components/playground/ControlPanel.svelte +134 -123
- package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
- package/dist/components/playground/ExecutionLogs.svelte +11 -9
- package/dist/components/playground/InputCollector.svelte +11 -9
- package/dist/components/playground/MessageStream.svelte +17 -23
- package/dist/components/playground/PipelineKanbanView.svelte +65 -6
- package/dist/components/playground/PipelinePanel.svelte +11 -5
- package/dist/components/playground/PipelineTableView.svelte +186 -44
- package/dist/components/playground/Playground.svelte +95 -92
- package/dist/components/playground/Playground.svelte.d.ts +2 -0
- package/dist/components/playground/PlaygroundApp.svelte +6 -1
- package/dist/components/playground/PlaygroundApp.svelte.d.ts +3 -0
- package/dist/components/playground/PlaygroundModal.svelte +13 -3
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -0
- package/dist/components/playground/PlaygroundStudio.svelte +34 -32
- package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -0
- package/dist/components/playground/SessionManager.svelte +9 -12
- package/dist/components/playground/pipelineViewUtils.svelte.d.ts +28 -0
- package/dist/components/playground/pipelineViewUtils.svelte.js +38 -1
- package/dist/config/endpoints.d.ts +0 -7
- package/dist/config/endpoints.js +2 -10
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +6 -6
- package/dist/display/index.d.ts +0 -2
- package/dist/display/index.js +0 -6
- package/dist/editor/index.d.ts +19 -20
- package/dist/editor/index.js +25 -35
- package/dist/form/code.d.ts +25 -15
- package/dist/form/code.js +44 -41
- package/dist/form/fieldRegistry.d.ts +17 -13
- package/dist/form/fieldRegistry.js +32 -12
- package/dist/form/full.d.ts +17 -13
- package/dist/form/full.js +22 -27
- package/dist/form/index.d.ts +3 -3
- package/dist/form/index.js +3 -3
- package/dist/form/markdown.d.ts +13 -8
- package/dist/form/markdown.js +22 -23
- package/dist/helpers/proximityConnect.d.ts +7 -3
- package/dist/helpers/proximityConnect.js +19 -6
- package/dist/helpers/workflowEditorHelper.d.ts +12 -5
- package/dist/helpers/workflowEditorHelper.js +27 -25
- package/dist/index.d.ts +28 -24
- package/dist/index.js +27 -50
- package/dist/messages/defaults.d.ts +2 -5
- package/dist/messages/defaults.js +3 -6
- package/dist/messages/index.d.ts +0 -1
- package/dist/messages/index.js +0 -1
- package/dist/mocks/app-forms.d.ts +6 -2
- package/dist/mocks/app-forms.js +11 -4
- package/dist/openapi/v1/openapi.yaml +227 -164
- package/dist/playground/index.d.ts +2 -3
- package/dist/playground/index.js +2 -30
- package/dist/playground/mount.d.ts +15 -0
- package/dist/playground/mount.js +46 -20
- package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
- package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
- package/dist/registry/builtinFormats.d.ts +9 -18
- package/dist/registry/builtinFormats.js +9 -39
- package/dist/registry/builtinNodes.d.ts +1 -26
- package/dist/registry/builtinNodes.js +14 -50
- package/dist/registry/index.d.ts +3 -4
- package/dist/registry/index.js +4 -6
- package/dist/registry/nodeComponentRegistry.d.ts +182 -15
- package/dist/registry/nodeComponentRegistry.js +235 -17
- package/dist/registry/workflowFormatRegistry.d.ts +14 -9
- package/dist/registry/workflowFormatRegistry.js +24 -8
- package/dist/{schema → schemas}/index.d.ts +2 -2
- package/dist/{schema → schemas}/index.js +2 -2
- package/dist/schemas/v1/workflow.schema.json +53 -6
- package/dist/services/agentSpecExecutionService.js +0 -1
- package/dist/services/apiVariableService.d.ts +2 -1
- package/dist/services/apiVariableService.js +5 -22
- package/dist/services/autoSaveService.d.ts +7 -0
- package/dist/services/autoSaveService.js +6 -4
- package/dist/services/chatService.d.ts +8 -4
- package/dist/services/chatService.js +15 -15
- package/dist/services/draftStorage.d.ts +129 -13
- package/dist/services/draftStorage.js +185 -37
- package/dist/services/dynamicSchemaService.d.ts +2 -1
- package/dist/services/dynamicSchemaService.js +5 -22
- package/dist/services/globalSave.d.ts +13 -12
- package/dist/services/globalSave.js +29 -51
- package/dist/services/historyService.d.ts +9 -3
- package/dist/services/historyService.js +9 -3
- package/dist/services/interruptService.d.ts +14 -9
- package/dist/services/interruptService.js +27 -27
- package/dist/services/nodeExecutionService.d.ts +18 -3
- package/dist/services/nodeExecutionService.js +71 -45
- package/dist/services/playgroundService.d.ts +14 -9
- package/dist/services/playgroundService.js +31 -30
- package/dist/services/variableService.d.ts +2 -1
- package/dist/services/variableService.js +2 -2
- package/dist/services/workflowStorage.js +6 -6
- package/dist/stores/apiContext.d.ts +45 -0
- package/dist/stores/apiContext.js +65 -0
- package/dist/stores/categoriesStore.svelte.d.ts +28 -23
- package/dist/stores/categoriesStore.svelte.js +70 -64
- package/dist/stores/getInstance.svelte.d.ts +39 -0
- package/dist/stores/getInstance.svelte.js +65 -0
- package/dist/stores/historyStore.svelte.d.ts +77 -93
- package/dist/stores/historyStore.svelte.js +134 -160
- package/dist/stores/instanceContainer.svelte.d.ts +111 -0
- package/dist/stores/instanceContainer.svelte.js +114 -0
- package/dist/stores/interruptStore.svelte.d.ts +112 -82
- package/dist/stores/interruptStore.svelte.js +253 -226
- package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
- package/dist/stores/pipelinePanelStore.svelte.js +61 -14
- package/dist/stores/playgroundStore.svelte.d.ts +169 -216
- package/dist/stores/playgroundStore.svelte.js +515 -572
- package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
- package/dist/stores/portCoordinateStore.svelte.js +109 -98
- package/dist/stores/settingsStore.svelte.d.ts +4 -1
- package/dist/stores/settingsStore.svelte.js +47 -12
- package/dist/stores/workflowStore.svelte.d.ts +178 -213
- package/dist/stores/workflowStore.svelte.js +449 -501
- package/dist/stories/EdgeDecorator.svelte +5 -2
- package/dist/stories/NodeDecorator.svelte +5 -3
- package/dist/svelte-app.d.ts +60 -10
- package/dist/svelte-app.js +157 -53
- package/dist/types/events.d.ts +6 -3
- package/dist/types/index.d.ts +71 -6
- package/dist/types/navbar.d.ts +7 -0
- package/dist/types/playground.d.ts +18 -3
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.js +1 -0
- package/dist/utils/colors.d.ts +47 -21
- package/dist/utils/colors.js +69 -68
- package/dist/utils/connections.d.ts +9 -15
- package/dist/utils/connections.js +13 -32
- package/dist/utils/duration.d.ts +13 -0
- package/dist/utils/duration.js +45 -0
- package/dist/utils/formMerge.d.ts +36 -0
- package/dist/utils/formMerge.js +70 -0
- package/dist/utils/icons.d.ts +5 -2
- package/dist/utils/icons.js +6 -5
- package/dist/utils/nodeSwap.d.ts +6 -2
- package/dist/utils/nodeSwap.js +62 -126
- package/dist/utils/nodeTypes.d.ts +17 -8
- package/dist/utils/nodeTypes.js +27 -19
- package/dist/utils/performanceUtils.js +7 -0
- package/package.json +6 -5
- package/dist/messages/deprecation.d.ts +0 -20
- package/dist/messages/deprecation.js +0 -33
- package/dist/registry/plugin.d.ts +0 -215
- package/dist/registry/plugin.js +0 -249
- package/dist/services/api.d.ts +0 -129
- package/dist/services/api.js +0 -217
|
@@ -1,12 +1,82 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Draft Storage Service for FlowDrop
|
|
3
3
|
*
|
|
4
|
-
* Handles saving and loading workflow drafts to/from
|
|
4
|
+
* Handles saving and loading workflow drafts to/from browser storage
|
|
5
|
+
* (localStorage by default, configurable via {@link setDraftStorage}).
|
|
5
6
|
* Provides interval-based auto-save functionality.
|
|
6
7
|
*
|
|
7
8
|
* @module services/draftStorage
|
|
8
9
|
*/
|
|
9
10
|
import type { Workflow } from '../types/index.js';
|
|
11
|
+
/**
|
|
12
|
+
* Minimal storage adapter used for draft persistence.
|
|
13
|
+
*
|
|
14
|
+
* Implement this to back drafts with anything other than the built-in
|
|
15
|
+
* `localStorage` / `sessionStorage` options — e.g. an in-memory store, a
|
|
16
|
+
* key-prefixed wrapper, or a synchronous write-through cache.
|
|
17
|
+
*
|
|
18
|
+
* Note the interface is deliberately **synchronous**. Async backends
|
|
19
|
+
* (IndexedDB, network storage, WebCrypto-encrypted stores) cannot implement
|
|
20
|
+
* it directly — put a synchronous in-memory cache in front and flush to the
|
|
21
|
+
* async backend out of band. An `async` method assigned here will type-check
|
|
22
|
+
* (a Promise is assignable to `void`) but its errors are silently swallowed.
|
|
23
|
+
*/
|
|
24
|
+
export interface DraftStorageAdapter {
|
|
25
|
+
/** Read a value, or null when absent */
|
|
26
|
+
getItem(key: string): string | null;
|
|
27
|
+
/** Write a value */
|
|
28
|
+
setItem(key: string, value: string): void;
|
|
29
|
+
/** Remove a value */
|
|
30
|
+
removeItem(key: string): void;
|
|
31
|
+
/** List all keys currently held by the adapter */
|
|
32
|
+
keys(): string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Built-in storage backends
|
|
36
|
+
* - 'local': localStorage — drafts persist on the device even after the tab
|
|
37
|
+
* or browser is closed, until saved or cleared
|
|
38
|
+
* - 'session': sessionStorage — drafts are scoped to the tab and removed
|
|
39
|
+
* when it closes (they do not survive crash-and-reopen)
|
|
40
|
+
*/
|
|
41
|
+
export type DraftStorageType = 'local' | 'session';
|
|
42
|
+
/** Accepted values for the `draftStorage` mount option */
|
|
43
|
+
export type DraftStorageOption = DraftStorageType | DraftStorageAdapter;
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a {@link DraftStorageOption} to a concrete adapter.
|
|
46
|
+
*
|
|
47
|
+
* `'local'` / `'session'` map to the built-in Web Storage adapters, a custom
|
|
48
|
+
* adapter is returned as-is, and `undefined` resolves to the current
|
|
49
|
+
* module-level default (see {@link setDraftStorage}).
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveDraftStorage(option?: DraftStorageOption): DraftStorageAdapter;
|
|
52
|
+
/**
|
|
53
|
+
* Configure the module-level default for where workflow drafts are persisted.
|
|
54
|
+
*
|
|
55
|
+
* - `'local'` (default): `localStorage` — drafts survive reloads and browser
|
|
56
|
+
* restarts, and remain stored on the device even after the tab is closed,
|
|
57
|
+
* until saved or cleared.
|
|
58
|
+
* - `'session'`: `sessionStorage` — drafts are scoped to the current tab and
|
|
59
|
+
* removed when it closes. Note this also means drafts do not survive a
|
|
60
|
+
* crash-and-reopen.
|
|
61
|
+
* - A custom {@link DraftStorageAdapter} for anything else.
|
|
62
|
+
*
|
|
63
|
+
* This sets the default used by the standalone helpers and by managers
|
|
64
|
+
* constructed without an explicit `storage` option. Mounted apps capture
|
|
65
|
+
* their own adapter at mount time, so calling this does not retarget
|
|
66
|
+
* already-running instances. With multiple mounts the most recent mount's
|
|
67
|
+
* backend wins *for the standalone helpers only*.
|
|
68
|
+
*
|
|
69
|
+
* Security note: neither built-in backend protects against same-origin
|
|
70
|
+
* script access (XSS) — both are readable by any script on the page. If
|
|
71
|
+
* workflows may contain secrets in node configs, disable drafts via
|
|
72
|
+
* `features.autoSaveDraft: false` or keep them off-disk with a custom
|
|
73
|
+
* in-memory adapter.
|
|
74
|
+
*/
|
|
75
|
+
export declare function setDraftStorage(option: DraftStorageOption): void;
|
|
76
|
+
/**
|
|
77
|
+
* Get the current module-level default draft storage adapter
|
|
78
|
+
*/
|
|
79
|
+
export declare function getDraftStorage(): DraftStorageAdapter;
|
|
10
80
|
/**
|
|
11
81
|
* Draft metadata stored alongside the workflow
|
|
12
82
|
*/
|
|
@@ -19,7 +89,7 @@ interface DraftMetadata {
|
|
|
19
89
|
workflowName?: string;
|
|
20
90
|
}
|
|
21
91
|
/**
|
|
22
|
-
* Complete draft data stored in
|
|
92
|
+
* Complete draft data stored in draft storage
|
|
23
93
|
*/
|
|
24
94
|
interface StoredDraft {
|
|
25
95
|
/** The workflow data */
|
|
@@ -27,6 +97,14 @@ interface StoredDraft {
|
|
|
27
97
|
/** Draft metadata */
|
|
28
98
|
metadata: DraftMetadata;
|
|
29
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Storage prefix of the page-default instance (`flowdrop:draft:default`).
|
|
102
|
+
*
|
|
103
|
+
* Every instance — including the default — uses an id-scoped prefix since
|
|
104
|
+
* v2.0. Standalone helper callers that don't pass a prefix get this one, so
|
|
105
|
+
* they keep addressing the default editor's drafts.
|
|
106
|
+
*/
|
|
107
|
+
export declare const DEFAULT_INSTANCE_DRAFT_PREFIX = "flowdrop:draft:default";
|
|
30
108
|
/**
|
|
31
109
|
* Generate a storage key for a workflow
|
|
32
110
|
*
|
|
@@ -35,48 +113,70 @@ interface StoredDraft {
|
|
|
35
113
|
*
|
|
36
114
|
* @param workflowId - The workflow ID (optional)
|
|
37
115
|
* @param customKey - Custom storage key provided by enterprise (optional)
|
|
116
|
+
* @param prefix - Key namespace; pass a FlowDrop instance's `storagePrefix`
|
|
117
|
+
* to scope drafts per instance. Defaults to the page-default instance's
|
|
118
|
+
* prefix.
|
|
38
119
|
* @returns The storage key to use
|
|
39
120
|
*/
|
|
40
|
-
export declare function getDraftStorageKey(workflowId?: string, customKey?: string): string;
|
|
121
|
+
export declare function getDraftStorageKey(workflowId?: string, customKey?: string, prefix?: string): string;
|
|
122
|
+
/**
|
|
123
|
+
* One-time migration of a 1.x draft key to its 2.0 scoped equivalent.
|
|
124
|
+
*
|
|
125
|
+
* In 1.x the page-default instance stored drafts under the bare
|
|
126
|
+
* `flowdrop:draft:<workflowId>` key; since 2.0 it uses
|
|
127
|
+
* `flowdrop:draft:default:<workflowId>`. When the scoped key is empty and the
|
|
128
|
+
* legacy key holds a draft, the draft is moved (copied, then the legacy key
|
|
129
|
+
* removed) so users upgrading mid-edit don't lose work.
|
|
130
|
+
*
|
|
131
|
+
* @param legacyKey - The 1.x bare-prefix key
|
|
132
|
+
* @param scopedKey - The 2.0 instance-scoped key
|
|
133
|
+
* @param storage - Adapter to migrate within (defaults to the module-level default)
|
|
134
|
+
*/
|
|
135
|
+
export declare function migrateLegacyDraftKey(legacyKey: string, scopedKey: string, storage?: DraftStorageAdapter): void;
|
|
41
136
|
/**
|
|
42
|
-
* Save a workflow draft to
|
|
137
|
+
* Save a workflow draft to draft storage
|
|
43
138
|
*
|
|
44
139
|
* @param workflow - The workflow to save
|
|
45
140
|
* @param storageKey - The storage key to use
|
|
141
|
+
* @param storage - Adapter to write to (defaults to the module-level default)
|
|
46
142
|
* @returns true if saved successfully, false otherwise
|
|
47
143
|
*/
|
|
48
|
-
export declare function saveDraft(workflow: Workflow, storageKey: string): boolean;
|
|
144
|
+
export declare function saveDraft(workflow: Workflow, storageKey: string, storage?: DraftStorageAdapter): boolean;
|
|
49
145
|
/**
|
|
50
|
-
* Load a workflow draft from
|
|
146
|
+
* Load a workflow draft from draft storage
|
|
51
147
|
*
|
|
52
148
|
* @param storageKey - The storage key to load from
|
|
149
|
+
* @param storage - Adapter to read from (defaults to the module-level default)
|
|
53
150
|
* @returns The stored draft, or null if not found
|
|
54
151
|
*/
|
|
55
|
-
export declare function loadDraft(storageKey: string): StoredDraft | null;
|
|
152
|
+
export declare function loadDraft(storageKey: string, storage?: DraftStorageAdapter): StoredDraft | null;
|
|
56
153
|
/**
|
|
57
|
-
* Delete a workflow draft from
|
|
154
|
+
* Delete a workflow draft from draft storage
|
|
58
155
|
*
|
|
59
156
|
* @param storageKey - The storage key to delete
|
|
157
|
+
* @param storage - Adapter to delete from (defaults to the module-level default)
|
|
60
158
|
*/
|
|
61
|
-
export declare function deleteDraft(storageKey: string): void;
|
|
159
|
+
export declare function deleteDraft(storageKey: string, storage?: DraftStorageAdapter): void;
|
|
62
160
|
/**
|
|
63
161
|
* Check if a draft exists for a given storage key
|
|
64
162
|
*
|
|
65
163
|
* @param storageKey - The storage key to check
|
|
164
|
+
* @param storage - Adapter to check (defaults to the module-level default)
|
|
66
165
|
* @returns true if a draft exists
|
|
67
166
|
*/
|
|
68
|
-
export declare function hasDraft(storageKey: string): boolean;
|
|
167
|
+
export declare function hasDraft(storageKey: string, storage?: DraftStorageAdapter): boolean;
|
|
69
168
|
/**
|
|
70
169
|
* Get draft metadata without loading the full workflow
|
|
71
170
|
*
|
|
72
171
|
* Useful for displaying draft information without parsing the entire workflow.
|
|
73
172
|
*
|
|
74
173
|
* @param storageKey - The storage key to check
|
|
174
|
+
* @param storage - Adapter to read from (defaults to the module-level default)
|
|
75
175
|
* @returns Draft metadata, or null if not found
|
|
76
176
|
*/
|
|
77
|
-
export declare function getDraftMetadata(storageKey: string): DraftMetadata | null;
|
|
177
|
+
export declare function getDraftMetadata(storageKey: string, storage?: DraftStorageAdapter): DraftMetadata | null;
|
|
78
178
|
/**
|
|
79
|
-
* Clear all FlowDrop drafts from
|
|
179
|
+
* Clear all FlowDrop drafts from draft storage
|
|
80
180
|
*
|
|
81
181
|
* Removes every key beginning with `flowdrop:draft:`. Intended to be called
|
|
82
182
|
* from a host application's logout handler so workflow drafts do not persist
|
|
@@ -85,9 +185,10 @@ export declare function getDraftMetadata(storageKey: string): DraftMetadata | nu
|
|
|
85
185
|
* @param extraKeys - Additional explicit keys to remove. Pass any custom
|
|
86
186
|
* `draftStorageKey` values configured at mount time so they are cleared
|
|
87
187
|
* alongside the default-prefixed keys.
|
|
188
|
+
* @param storage - Adapter to clear (defaults to the module-level default)
|
|
88
189
|
* @returns The number of entries removed.
|
|
89
190
|
*/
|
|
90
|
-
export declare function clearAllDrafts(extraKeys?: readonly string[]): number;
|
|
191
|
+
export declare function clearAllDrafts(extraKeys?: readonly string[], storage?: DraftStorageAdapter): number;
|
|
91
192
|
/**
|
|
92
193
|
* Draft auto-save manager
|
|
93
194
|
*
|
|
@@ -107,6 +208,17 @@ export declare class DraftAutoSaveManager {
|
|
|
107
208
|
private getWorkflow;
|
|
108
209
|
/** Function to check if workflow is dirty */
|
|
109
210
|
private isDirty;
|
|
211
|
+
/**
|
|
212
|
+
* Runtime gate for draft persistence (e.g. a user-facing opt-out setting).
|
|
213
|
+
* Checked on every save, so it can change after construction.
|
|
214
|
+
*/
|
|
215
|
+
private isPersistenceAllowed;
|
|
216
|
+
/**
|
|
217
|
+
* Storage adapter this instance writes to.
|
|
218
|
+
* Captured at construction, so a later `setDraftStorage()` call (e.g. from
|
|
219
|
+
* another FlowDrop mount on the same page) cannot retarget this manager.
|
|
220
|
+
*/
|
|
221
|
+
private storage;
|
|
110
222
|
/** Last saved workflow hash (for change detection) */
|
|
111
223
|
private lastSavedHash;
|
|
112
224
|
/**
|
|
@@ -120,6 +232,10 @@ export declare class DraftAutoSaveManager {
|
|
|
120
232
|
enabled: boolean;
|
|
121
233
|
getWorkflow: () => Workflow | null;
|
|
122
234
|
isDirty: () => boolean;
|
|
235
|
+
/** Optional runtime gate — return false to suppress draft writes (default: always allowed) */
|
|
236
|
+
isPersistenceAllowed?: () => boolean;
|
|
237
|
+
/** Storage backend for this instance (default: the module-level default at construction time) */
|
|
238
|
+
storage?: DraftStorageOption;
|
|
123
239
|
});
|
|
124
240
|
/**
|
|
125
241
|
* Start auto-save interval
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Draft Storage Service for FlowDrop
|
|
3
3
|
*
|
|
4
|
-
* Handles saving and loading workflow drafts to/from
|
|
4
|
+
* Handles saving and loading workflow drafts to/from browser storage
|
|
5
|
+
* (localStorage by default, configurable via {@link setDraftStorage}).
|
|
5
6
|
* Provides interval-based auto-save functionality.
|
|
6
7
|
*
|
|
7
8
|
* @module services/draftStorage
|
|
@@ -11,6 +12,96 @@ import { logger } from '../utils/logger.js';
|
|
|
11
12
|
* Default storage key prefix
|
|
12
13
|
*/
|
|
13
14
|
const STORAGE_KEY_PREFIX = 'flowdrop:draft';
|
|
15
|
+
/**
|
|
16
|
+
* Wrap a Web Storage object (localStorage/sessionStorage) as a DraftStorageAdapter.
|
|
17
|
+
* The storage global is resolved lazily so SSR and test environments that
|
|
18
|
+
* replace the globals keep working.
|
|
19
|
+
*/
|
|
20
|
+
function createWebStorageAdapter(getStorage) {
|
|
21
|
+
return {
|
|
22
|
+
getItem: (key) => getStorage().getItem(key),
|
|
23
|
+
setItem: (key, value) => getStorage().setItem(key, value),
|
|
24
|
+
removeItem: (key) => getStorage().removeItem(key),
|
|
25
|
+
keys: () => {
|
|
26
|
+
const storage = getStorage();
|
|
27
|
+
const keys = [];
|
|
28
|
+
for (let i = 0; i < storage.length; i++) {
|
|
29
|
+
const key = storage.key(i);
|
|
30
|
+
if (key !== null) {
|
|
31
|
+
keys.push(key);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return keys;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const WEB_STORAGE_ADAPTERS = {
|
|
39
|
+
local: createWebStorageAdapter(() => localStorage),
|
|
40
|
+
session: createWebStorageAdapter(() => sessionStorage)
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Module-level default adapter (localStorage by default).
|
|
44
|
+
*
|
|
45
|
+
* Used by the standalone helpers (`saveDraft`, `clearAllDrafts`, ...) when no
|
|
46
|
+
* explicit adapter is passed, and as the fallback for managers constructed
|
|
47
|
+
* without a `storage` option. Per-instance code (each `DraftAutoSaveManager`,
|
|
48
|
+
* each mounted app) captures its own resolved adapter instead, so multiple
|
|
49
|
+
* FlowDrop instances with different backends do not interfere.
|
|
50
|
+
*/
|
|
51
|
+
let activeAdapter = WEB_STORAGE_ADAPTERS.local;
|
|
52
|
+
/**
|
|
53
|
+
* Resolve a {@link DraftStorageOption} to a concrete adapter.
|
|
54
|
+
*
|
|
55
|
+
* `'local'` / `'session'` map to the built-in Web Storage adapters, a custom
|
|
56
|
+
* adapter is returned as-is, and `undefined` resolves to the current
|
|
57
|
+
* module-level default (see {@link setDraftStorage}).
|
|
58
|
+
*/
|
|
59
|
+
export function resolveDraftStorage(option) {
|
|
60
|
+
if (option === undefined) {
|
|
61
|
+
return activeAdapter;
|
|
62
|
+
}
|
|
63
|
+
return typeof option === 'string' ? WEB_STORAGE_ADAPTERS[option] : option;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Configure the module-level default for where workflow drafts are persisted.
|
|
67
|
+
*
|
|
68
|
+
* - `'local'` (default): `localStorage` — drafts survive reloads and browser
|
|
69
|
+
* restarts, and remain stored on the device even after the tab is closed,
|
|
70
|
+
* until saved or cleared.
|
|
71
|
+
* - `'session'`: `sessionStorage` — drafts are scoped to the current tab and
|
|
72
|
+
* removed when it closes. Note this also means drafts do not survive a
|
|
73
|
+
* crash-and-reopen.
|
|
74
|
+
* - A custom {@link DraftStorageAdapter} for anything else.
|
|
75
|
+
*
|
|
76
|
+
* This sets the default used by the standalone helpers and by managers
|
|
77
|
+
* constructed without an explicit `storage` option. Mounted apps capture
|
|
78
|
+
* their own adapter at mount time, so calling this does not retarget
|
|
79
|
+
* already-running instances. With multiple mounts the most recent mount's
|
|
80
|
+
* backend wins *for the standalone helpers only*.
|
|
81
|
+
*
|
|
82
|
+
* Security note: neither built-in backend protects against same-origin
|
|
83
|
+
* script access (XSS) — both are readable by any script on the page. If
|
|
84
|
+
* workflows may contain secrets in node configs, disable drafts via
|
|
85
|
+
* `features.autoSaveDraft: false` or keep them off-disk with a custom
|
|
86
|
+
* in-memory adapter.
|
|
87
|
+
*/
|
|
88
|
+
export function setDraftStorage(option) {
|
|
89
|
+
activeAdapter = resolveDraftStorage(option);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the current module-level default draft storage adapter
|
|
93
|
+
*/
|
|
94
|
+
export function getDraftStorage() {
|
|
95
|
+
return activeAdapter;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Storage prefix of the page-default instance (`flowdrop:draft:default`).
|
|
99
|
+
*
|
|
100
|
+
* Every instance — including the default — uses an id-scoped prefix since
|
|
101
|
+
* v2.0. Standalone helper callers that don't pass a prefix get this one, so
|
|
102
|
+
* they keep addressing the default editor's drafts.
|
|
103
|
+
*/
|
|
104
|
+
export const DEFAULT_INSTANCE_DRAFT_PREFIX = `${STORAGE_KEY_PREFIX}:default`;
|
|
14
105
|
/**
|
|
15
106
|
* Generate a storage key for a workflow
|
|
16
107
|
*
|
|
@@ -19,25 +110,58 @@ const STORAGE_KEY_PREFIX = 'flowdrop:draft';
|
|
|
19
110
|
*
|
|
20
111
|
* @param workflowId - The workflow ID (optional)
|
|
21
112
|
* @param customKey - Custom storage key provided by enterprise (optional)
|
|
113
|
+
* @param prefix - Key namespace; pass a FlowDrop instance's `storagePrefix`
|
|
114
|
+
* to scope drafts per instance. Defaults to the page-default instance's
|
|
115
|
+
* prefix.
|
|
22
116
|
* @returns The storage key to use
|
|
23
117
|
*/
|
|
24
|
-
export function getDraftStorageKey(workflowId, customKey) {
|
|
118
|
+
export function getDraftStorageKey(workflowId, customKey, prefix = DEFAULT_INSTANCE_DRAFT_PREFIX) {
|
|
25
119
|
if (customKey) {
|
|
26
120
|
return customKey;
|
|
27
121
|
}
|
|
28
122
|
if (workflowId) {
|
|
29
|
-
return `${
|
|
123
|
+
return `${prefix}:${workflowId}`;
|
|
30
124
|
}
|
|
31
|
-
return `${
|
|
125
|
+
return `${prefix}:new`;
|
|
32
126
|
}
|
|
33
127
|
/**
|
|
34
|
-
*
|
|
128
|
+
* One-time migration of a 1.x draft key to its 2.0 scoped equivalent.
|
|
129
|
+
*
|
|
130
|
+
* In 1.x the page-default instance stored drafts under the bare
|
|
131
|
+
* `flowdrop:draft:<workflowId>` key; since 2.0 it uses
|
|
132
|
+
* `flowdrop:draft:default:<workflowId>`. When the scoped key is empty and the
|
|
133
|
+
* legacy key holds a draft, the draft is moved (copied, then the legacy key
|
|
134
|
+
* removed) so users upgrading mid-edit don't lose work.
|
|
135
|
+
*
|
|
136
|
+
* @param legacyKey - The 1.x bare-prefix key
|
|
137
|
+
* @param scopedKey - The 2.0 instance-scoped key
|
|
138
|
+
* @param storage - Adapter to migrate within (defaults to the module-level default)
|
|
139
|
+
*/
|
|
140
|
+
export function migrateLegacyDraftKey(legacyKey, scopedKey, storage = activeAdapter) {
|
|
141
|
+
if (legacyKey === scopedKey)
|
|
142
|
+
return;
|
|
143
|
+
try {
|
|
144
|
+
if (storage.getItem(scopedKey) !== null)
|
|
145
|
+
return;
|
|
146
|
+
const legacy = storage.getItem(legacyKey);
|
|
147
|
+
if (legacy === null)
|
|
148
|
+
return;
|
|
149
|
+
storage.setItem(scopedKey, legacy);
|
|
150
|
+
storage.removeItem(legacyKey);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
logger.warn('Failed to migrate legacy draft key:', error);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Save a workflow draft to draft storage
|
|
35
158
|
*
|
|
36
159
|
* @param workflow - The workflow to save
|
|
37
160
|
* @param storageKey - The storage key to use
|
|
161
|
+
* @param storage - Adapter to write to (defaults to the module-level default)
|
|
38
162
|
* @returns true if saved successfully, false otherwise
|
|
39
163
|
*/
|
|
40
|
-
export function saveDraft(workflow, storageKey) {
|
|
164
|
+
export function saveDraft(workflow, storageKey, storage = activeAdapter) {
|
|
41
165
|
try {
|
|
42
166
|
const draft = {
|
|
43
167
|
workflow,
|
|
@@ -47,62 +171,65 @@ export function saveDraft(workflow, storageKey) {
|
|
|
47
171
|
workflowName: workflow.name
|
|
48
172
|
}
|
|
49
173
|
};
|
|
50
|
-
|
|
174
|
+
storage.setItem(storageKey, JSON.stringify(draft));
|
|
51
175
|
return true;
|
|
52
176
|
}
|
|
53
177
|
catch (error) {
|
|
54
|
-
//
|
|
55
|
-
logger.warn('Failed to save draft to
|
|
178
|
+
// Storage might be full or disabled
|
|
179
|
+
logger.warn('Failed to save draft to storage:', error);
|
|
56
180
|
return false;
|
|
57
181
|
}
|
|
58
182
|
}
|
|
59
183
|
/**
|
|
60
|
-
* Load a workflow draft from
|
|
184
|
+
* Load a workflow draft from draft storage
|
|
61
185
|
*
|
|
62
186
|
* @param storageKey - The storage key to load from
|
|
187
|
+
* @param storage - Adapter to read from (defaults to the module-level default)
|
|
63
188
|
* @returns The stored draft, or null if not found
|
|
64
189
|
*/
|
|
65
|
-
export function loadDraft(storageKey) {
|
|
190
|
+
export function loadDraft(storageKey, storage = activeAdapter) {
|
|
66
191
|
try {
|
|
67
|
-
const stored =
|
|
192
|
+
const stored = storage.getItem(storageKey);
|
|
68
193
|
if (!stored) {
|
|
69
194
|
return null;
|
|
70
195
|
}
|
|
71
196
|
const draft = JSON.parse(stored);
|
|
72
197
|
// Validate the draft structure
|
|
73
198
|
if (!draft.workflow || !draft.metadata) {
|
|
74
|
-
logger.warn('Invalid draft structure in
|
|
199
|
+
logger.warn('Invalid draft structure in storage');
|
|
75
200
|
return null;
|
|
76
201
|
}
|
|
77
202
|
return draft;
|
|
78
203
|
}
|
|
79
204
|
catch (error) {
|
|
80
|
-
logger.warn('Failed to load draft from
|
|
205
|
+
logger.warn('Failed to load draft from storage:', error);
|
|
81
206
|
return null;
|
|
82
207
|
}
|
|
83
208
|
}
|
|
84
209
|
/**
|
|
85
|
-
* Delete a workflow draft from
|
|
210
|
+
* Delete a workflow draft from draft storage
|
|
86
211
|
*
|
|
87
212
|
* @param storageKey - The storage key to delete
|
|
213
|
+
* @param storage - Adapter to delete from (defaults to the module-level default)
|
|
88
214
|
*/
|
|
89
|
-
export function deleteDraft(storageKey) {
|
|
215
|
+
export function deleteDraft(storageKey, storage = activeAdapter) {
|
|
90
216
|
try {
|
|
91
|
-
|
|
217
|
+
storage.removeItem(storageKey);
|
|
92
218
|
}
|
|
93
219
|
catch (error) {
|
|
94
|
-
logger.warn('Failed to delete draft from
|
|
220
|
+
logger.warn('Failed to delete draft from storage:', error);
|
|
95
221
|
}
|
|
96
222
|
}
|
|
97
223
|
/**
|
|
98
224
|
* Check if a draft exists for a given storage key
|
|
99
225
|
*
|
|
100
226
|
* @param storageKey - The storage key to check
|
|
227
|
+
* @param storage - Adapter to check (defaults to the module-level default)
|
|
101
228
|
* @returns true if a draft exists
|
|
102
229
|
*/
|
|
103
|
-
export function hasDraft(storageKey) {
|
|
230
|
+
export function hasDraft(storageKey, storage = activeAdapter) {
|
|
104
231
|
try {
|
|
105
|
-
return
|
|
232
|
+
return storage.getItem(storageKey) !== null;
|
|
106
233
|
}
|
|
107
234
|
catch {
|
|
108
235
|
return false;
|
|
@@ -114,14 +241,15 @@ export function hasDraft(storageKey) {
|
|
|
114
241
|
* Useful for displaying draft information without parsing the entire workflow.
|
|
115
242
|
*
|
|
116
243
|
* @param storageKey - The storage key to check
|
|
244
|
+
* @param storage - Adapter to read from (defaults to the module-level default)
|
|
117
245
|
* @returns Draft metadata, or null if not found
|
|
118
246
|
*/
|
|
119
|
-
export function getDraftMetadata(storageKey) {
|
|
120
|
-
const draft = loadDraft(storageKey);
|
|
247
|
+
export function getDraftMetadata(storageKey, storage = activeAdapter) {
|
|
248
|
+
const draft = loadDraft(storageKey, storage);
|
|
121
249
|
return draft?.metadata ?? null;
|
|
122
250
|
}
|
|
123
251
|
/**
|
|
124
|
-
* Clear all FlowDrop drafts from
|
|
252
|
+
* Clear all FlowDrop drafts from draft storage
|
|
125
253
|
*
|
|
126
254
|
* Removes every key beginning with `flowdrop:draft:`. Intended to be called
|
|
127
255
|
* from a host application's logout handler so workflow drafts do not persist
|
|
@@ -130,29 +258,29 @@ export function getDraftMetadata(storageKey) {
|
|
|
130
258
|
* @param extraKeys - Additional explicit keys to remove. Pass any custom
|
|
131
259
|
* `draftStorageKey` values configured at mount time so they are cleared
|
|
132
260
|
* alongside the default-prefixed keys.
|
|
261
|
+
* @param storage - Adapter to clear (defaults to the module-level default)
|
|
133
262
|
* @returns The number of entries removed.
|
|
134
263
|
*/
|
|
135
|
-
export function clearAllDrafts(extraKeys = []) {
|
|
264
|
+
export function clearAllDrafts(extraKeys = [], storage = activeAdapter) {
|
|
136
265
|
try {
|
|
137
266
|
const keysToRemove = new Set();
|
|
138
|
-
for (
|
|
139
|
-
|
|
140
|
-
if (key && key.startsWith(`${STORAGE_KEY_PREFIX}:`)) {
|
|
267
|
+
for (const key of storage.keys()) {
|
|
268
|
+
if (key.startsWith(`${STORAGE_KEY_PREFIX}:`)) {
|
|
141
269
|
keysToRemove.add(key);
|
|
142
270
|
}
|
|
143
271
|
}
|
|
144
272
|
for (const key of extraKeys) {
|
|
145
|
-
if (
|
|
273
|
+
if (storage.getItem(key) !== null) {
|
|
146
274
|
keysToRemove.add(key);
|
|
147
275
|
}
|
|
148
276
|
}
|
|
149
277
|
for (const key of keysToRemove) {
|
|
150
|
-
|
|
278
|
+
storage.removeItem(key);
|
|
151
279
|
}
|
|
152
280
|
return keysToRemove.size;
|
|
153
281
|
}
|
|
154
282
|
catch (error) {
|
|
155
|
-
logger.warn('Failed to clear drafts from
|
|
283
|
+
logger.warn('Failed to clear drafts from storage:', error);
|
|
156
284
|
return 0;
|
|
157
285
|
}
|
|
158
286
|
}
|
|
@@ -175,6 +303,17 @@ export class DraftAutoSaveManager {
|
|
|
175
303
|
getWorkflow;
|
|
176
304
|
/** Function to check if workflow is dirty */
|
|
177
305
|
isDirty;
|
|
306
|
+
/**
|
|
307
|
+
* Runtime gate for draft persistence (e.g. a user-facing opt-out setting).
|
|
308
|
+
* Checked on every save, so it can change after construction.
|
|
309
|
+
*/
|
|
310
|
+
isPersistenceAllowed;
|
|
311
|
+
/**
|
|
312
|
+
* Storage adapter this instance writes to.
|
|
313
|
+
* Captured at construction, so a later `setDraftStorage()` call (e.g. from
|
|
314
|
+
* another FlowDrop mount on the same page) cannot retarget this manager.
|
|
315
|
+
*/
|
|
316
|
+
storage;
|
|
178
317
|
/** Last saved workflow hash (for change detection) */
|
|
179
318
|
lastSavedHash = null;
|
|
180
319
|
/**
|
|
@@ -188,6 +327,8 @@ export class DraftAutoSaveManager {
|
|
|
188
327
|
this.enabled = options.enabled;
|
|
189
328
|
this.getWorkflow = options.getWorkflow;
|
|
190
329
|
this.isDirty = options.isDirty;
|
|
330
|
+
this.isPersistenceAllowed = options.isPersistenceAllowed ?? (() => true);
|
|
331
|
+
this.storage = resolveDraftStorage(options.storage);
|
|
191
332
|
}
|
|
192
333
|
/**
|
|
193
334
|
* Start auto-save interval
|
|
@@ -217,7 +358,7 @@ export class DraftAutoSaveManager {
|
|
|
217
358
|
* @returns true if a draft was saved
|
|
218
359
|
*/
|
|
219
360
|
saveIfDirty() {
|
|
220
|
-
if (!this.enabled) {
|
|
361
|
+
if (!this.enabled || !this.isPersistenceAllowed()) {
|
|
221
362
|
return false;
|
|
222
363
|
}
|
|
223
364
|
const workflow = this.getWorkflow();
|
|
@@ -233,7 +374,7 @@ export class DraftAutoSaveManager {
|
|
|
233
374
|
if (currentHash === this.lastSavedHash) {
|
|
234
375
|
return false;
|
|
235
376
|
}
|
|
236
|
-
const saved = saveDraft(workflow, this.storageKey);
|
|
377
|
+
const saved = saveDraft(workflow, this.storageKey, this.storage);
|
|
237
378
|
if (saved) {
|
|
238
379
|
this.lastSavedHash = currentHash;
|
|
239
380
|
}
|
|
@@ -247,11 +388,14 @@ export class DraftAutoSaveManager {
|
|
|
247
388
|
* @returns true if saved successfully
|
|
248
389
|
*/
|
|
249
390
|
forceSave() {
|
|
391
|
+
if (!this.isPersistenceAllowed()) {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
250
394
|
const workflow = this.getWorkflow();
|
|
251
395
|
if (!workflow) {
|
|
252
396
|
return false;
|
|
253
397
|
}
|
|
254
|
-
const saved = saveDraft(workflow, this.storageKey);
|
|
398
|
+
const saved = saveDraft(workflow, this.storageKey, this.storage);
|
|
255
399
|
if (saved) {
|
|
256
400
|
this.lastSavedHash = this.hashWorkflow(workflow);
|
|
257
401
|
}
|
|
@@ -261,7 +405,7 @@ export class DraftAutoSaveManager {
|
|
|
261
405
|
* Clear the draft from storage
|
|
262
406
|
*/
|
|
263
407
|
clearDraft() {
|
|
264
|
-
deleteDraft(this.storageKey);
|
|
408
|
+
deleteDraft(this.storageKey, this.storage);
|
|
265
409
|
this.lastSavedHash = null;
|
|
266
410
|
}
|
|
267
411
|
/**
|
|
@@ -284,10 +428,14 @@ export class DraftAutoSaveManager {
|
|
|
284
428
|
*/
|
|
285
429
|
updateStorageKey(newKey) {
|
|
286
430
|
// If there's an existing draft with the old key, migrate it
|
|
287
|
-
const existingDraft = loadDraft(this.storageKey);
|
|
431
|
+
const existingDraft = loadDraft(this.storageKey, this.storage);
|
|
288
432
|
if (existingDraft && this.storageKey !== newKey) {
|
|
289
|
-
deleteDraft(this.storageKey);
|
|
290
|
-
|
|
433
|
+
deleteDraft(this.storageKey, this.storage);
|
|
434
|
+
// Migration is still a write — respect the user's opt-out. The old
|
|
435
|
+
// draft is deleted either way, which is in line with opting out.
|
|
436
|
+
if (this.isPersistenceAllowed()) {
|
|
437
|
+
saveDraft(existingDraft.workflow, newKey, this.storage);
|
|
438
|
+
}
|
|
291
439
|
}
|
|
292
440
|
this.storageKey = newKey;
|
|
293
441
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @module services/dynamicSchemaService
|
|
7
7
|
*/
|
|
8
8
|
import type { ConfigSchema, DynamicSchemaEndpoint, ExternalEditLink, ConfigEditOptions, WorkflowNode } from '../types/index.js';
|
|
9
|
+
import type { EndpointConfig } from '../config/endpoints.js';
|
|
9
10
|
/**
|
|
10
11
|
* Result of a dynamic schema fetch operation
|
|
11
12
|
*/
|
|
@@ -41,7 +42,7 @@ export interface DynamicSchemaResult {
|
|
|
41
42
|
* }
|
|
42
43
|
* ```
|
|
43
44
|
*/
|
|
44
|
-
export declare function fetchDynamicSchema(endpoint: DynamicSchemaEndpoint, node: WorkflowNode, workflowId?: string): Promise<DynamicSchemaResult>;
|
|
45
|
+
export declare function fetchDynamicSchema(endpointConfig: EndpointConfig | null, endpoint: DynamicSchemaEndpoint, node: WorkflowNode, workflowId?: string): Promise<DynamicSchemaResult>;
|
|
45
46
|
/**
|
|
46
47
|
* Resolves an external edit link URL with template variables.
|
|
47
48
|
*
|