@oomol-lab/open-flow 0.1.0-beta.81 → 0.1.0-beta.82
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/browser/{FlowCanvas-CrsiDHK8.js → FlowCanvas-Dew2fmoT.js} +55 -274
- package/dist/browser/{createResourceDialog-CS3u9ga9.js → createResourceDialog-bdOJa5Zk.js} +2 -1
- package/dist/browser/{exportPng-BOPfjeEi.js → exportPng-Cjdb6COo.js} +2 -2
- package/dist/browser/{flowChanges-CFj5pL4Y.js → flowChanges-URBEd4DI.js} +2583 -71
- package/dist/browser/{flowWorkspace-BeQaeJ3e.js → flowWorkspace-BlXx-yAn.js} +440 -2578
- package/dist/browser/{markdownContent-CAG_CQfH.js → markdownContent-D8G_oNOe.js} +18 -41
- package/dist/browser/{markdownContent-frwDfQQU.js → markdownContent-IS8xXDoc.js} +18 -40
- package/dist/browser/preview.css +88 -80
- package/dist/browser/preview.js +150 -60
- package/dist/browser/ui.css +8 -0
- package/dist/browser/{dist-CHwj9BhV.js → videoLink-NAWDmBtf.js} +35 -1
- package/dist/browser/workbench-contract.d.ts +6 -0
- package/dist/browser/workbench.css +259 -251
- package/dist/browser/workbench.d.ts +2 -0
- package/dist/browser/workbench.js +289 -137
- package/dist/browser/{ContentIcon-CMn0c-kl.js → wrapLayout-DZvW9dBs.js} +4397 -4152
- package/dist/command/index.js +43 -41
- package/dist/common/authoring.d.ts +1 -1
- package/dist/common/control-api-conformance.js +306 -2
- package/dist/common/control-api.d.ts +20 -0
- package/dist/common/control-api.js +306 -4
- package/dist/common/control-requests.d.ts +3 -5
- package/dist/common/control-requests.js +5 -7
- package/dist/common/flow-encoding.d.ts +1 -0
- package/dist/common/flow-encoding.js +167 -1
- package/dist/common/flow-semantics.js +20 -0
- package/dist/common/flow-workflowBundle.d.ts +27 -0
- package/dist/common/flow-workflowFile.d.ts +2 -0
- package/dist/common/flow-workflowReferences.d.ts +4 -0
- package/dist/common/mcp.d.ts +2 -0
- package/dist/common/mcp.js +312 -4
- package/dist/render/browser/licenses.md +4047 -0
- package/dist/render/browser/runtime.css +14877 -0
- package/dist/render/browser/runtime.js +266765 -0
- package/dist/render/common/png.d.ts +24 -0
- package/dist/render/node/index.d.ts +11 -0
- package/dist/render/node/index.js +9491 -0
- package/dist/render/node/licenses.md +75 -0
- package/package.json +12 -2
- package/src/control/common/api.ts +50 -0
- package/src/control/common/flowDecoders.ts +2 -0
- package/src/control/common/mcp.ts +4 -4
- package/src/control/common/requests.ts +12 -1
- package/src/flow/common/encoding.ts +1 -0
- package/src/flow/common/workflowBundle.ts +117 -0
- package/src/flow/common/workflowFile.ts +4 -0
- package/src/flow/common/workflowReferences.ts +20 -0
|
@@ -8617,6 +8617,31 @@ function isSchemaKeyword(value) {
|
|
|
8617
8617
|
return schemaKeywords.has(value);
|
|
8618
8618
|
}
|
|
8619
8619
|
//#endregion
|
|
8620
|
+
//#region src/flow/common/workflowReferences.ts
|
|
8621
|
+
/** Workflow declarations share discovery across authoring, admission and resource indexing. */
|
|
8622
|
+
function nodeWorkflowReferences(node) {
|
|
8623
|
+
if (node.kind != "task") return [];
|
|
8624
|
+
if ("moduleId" in node.task) return (node.task.capabilities ?? []).flatMap((item, index) => item.kind == "workflow" ? [{
|
|
8625
|
+
target: item,
|
|
8626
|
+
path: `task/capabilities/${index}`,
|
|
8627
|
+
tool: item.name
|
|
8628
|
+
}] : []);
|
|
8629
|
+
if (node.task.executor.kind == "workflow") return [{
|
|
8630
|
+
target: {
|
|
8631
|
+
...node.task.executor,
|
|
8632
|
+
inputs: node.task.inputs.filter((port) => "handle" in port),
|
|
8633
|
+
outputs: node.task.outputs.filter((port) => "handle" in port)
|
|
8634
|
+
},
|
|
8635
|
+
path: "task/executor"
|
|
8636
|
+
}];
|
|
8637
|
+
if (node.task.executor.kind == "agent") return node.task.executor.tools.flatMap((item, index) => item.kind == "workflow" ? [{
|
|
8638
|
+
target: item,
|
|
8639
|
+
path: `task/executor/tools/${index}`,
|
|
8640
|
+
tool: item.name
|
|
8641
|
+
}] : []);
|
|
8642
|
+
return [];
|
|
8643
|
+
}
|
|
8644
|
+
//#endregion
|
|
8620
8645
|
//#region src/workflow/common/workflow.ts
|
|
8621
8646
|
var portSchema = object({
|
|
8622
8647
|
handle: string$1().min(1),
|
|
@@ -10547,7 +10572,7 @@ var entrySchema = discriminatedUnion("type", [
|
|
|
10547
10572
|
/** Project only the selected published definition and its current bindings. */
|
|
10548
10573
|
function liveEntries(content, current, bindings) {
|
|
10549
10574
|
const byNode = new Map(bindings.filter((item) => item.flowId == current.flowId && item.currentPublicationId == current.publicationId && item.currentRevisionId == current.revisionId).map((item) => [item.triggerNodeId, item]));
|
|
10550
|
-
return decodeEntries(Object.entries(content.document.graph.nodes).toSorted(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([nodeId, node]) => {
|
|
10575
|
+
return decodeEntries$1(Object.entries(content.document.graph.nodes).toSorted(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).flatMap(([nodeId, node]) => {
|
|
10551
10576
|
if (node.kind != "start" && node.kind != "manual" && node.kind != "webhook" && node.kind != "cron" && node.kind != "error" && node.kind != "poll" && node.kind != "integration") return [];
|
|
10552
10577
|
const config = triggerConfiguration(node);
|
|
10553
10578
|
return [{
|
|
@@ -10595,12 +10620,12 @@ function decodeLiveDetails(value) {
|
|
|
10595
10620
|
publication: current,
|
|
10596
10621
|
status,
|
|
10597
10622
|
enabled: source.enabled,
|
|
10598
|
-
entries: decodeEntries(source.entries, current),
|
|
10623
|
+
entries: decodeEntries$1(source.entries, current),
|
|
10599
10624
|
version: 1
|
|
10600
10625
|
};
|
|
10601
10626
|
}
|
|
10602
10627
|
/** Both producers and consumers enforce the same published-entry invariants. */
|
|
10603
|
-
function decodeEntries(values, current) {
|
|
10628
|
+
function decodeEntries$1(values, current) {
|
|
10604
10629
|
const parsed = array(entrySchema).safeParse(values);
|
|
10605
10630
|
if (!parsed.success) return invalidResponse();
|
|
10606
10631
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -10670,17 +10695,134 @@ function conditionInputPorts(node) {
|
|
|
10670
10695
|
nullable: operand.kind === "value" ? operand.value === null : true
|
|
10671
10696
|
}]));
|
|
10672
10697
|
}
|
|
10698
|
+
function clearConditionBinding(operand) {
|
|
10699
|
+
return operand.kind == "source" && operand.source.kind == "binding" ? { kind: "value" } : operand;
|
|
10700
|
+
}
|
|
10701
|
+
function clearConditionBindings(node) {
|
|
10702
|
+
return {
|
|
10703
|
+
...node,
|
|
10704
|
+
cases: node.cases.map((item) => ({
|
|
10705
|
+
...item,
|
|
10706
|
+
groups: item.groups.map((group) => ({
|
|
10707
|
+
...group,
|
|
10708
|
+
expressions: group.expressions.map((expression) => ({
|
|
10709
|
+
...expression,
|
|
10710
|
+
left: clearConditionBinding(expression.left),
|
|
10711
|
+
...expression.right == null ? {} : { right: clearConditionBinding(expression.right) }
|
|
10712
|
+
}))
|
|
10713
|
+
}))
|
|
10714
|
+
}))
|
|
10715
|
+
};
|
|
10716
|
+
}
|
|
10673
10717
|
//#endregion
|
|
10674
10718
|
//#region src/flow/common/model.ts
|
|
10675
10719
|
function portsByHandle(ports) {
|
|
10676
10720
|
return Object.fromEntries(ports.flatMap((port) => "handle" in port ? [[port.handle, port]] : []));
|
|
10677
10721
|
}
|
|
10678
10722
|
//#endregion
|
|
10723
|
+
//#region src/trigger/common/config.ts
|
|
10724
|
+
/** Deployment-bound selections owned by the Trigger configuration contract. */
|
|
10725
|
+
function clearTriggerExternalConfig(key, config) {
|
|
10726
|
+
const fields = key == "jira.on_issue_event" || key == "intercom.on_conversation_event" || key == "sentry.on_issue_alert" || key == "zoom.on_recording_ready" || key == "fireflies.on_meeting_ready" ? ["sourceId", "eventTypes"] : key == "slackbot.on_event" ? [
|
|
10727
|
+
"sourceId",
|
|
10728
|
+
"eventTypes",
|
|
10729
|
+
"channelIds"
|
|
10730
|
+
] : key == "feishu_app_bot.on_event" ? [
|
|
10731
|
+
"sourceId",
|
|
10732
|
+
"eventTypes",
|
|
10733
|
+
"resource",
|
|
10734
|
+
"chatIds"
|
|
10735
|
+
] : key == "linear.on_issue_changed" ? ["teamId", "stateIds"] : [];
|
|
10736
|
+
return {
|
|
10737
|
+
...config,
|
|
10738
|
+
...Object.fromEntries(fields.map((field) => [field, { kind: "unset" }]))
|
|
10739
|
+
};
|
|
10740
|
+
}
|
|
10741
|
+
//#endregion
|
|
10742
|
+
//#region src/flow/common/connectionUsage.ts
|
|
10743
|
+
function clearNodeConnections(graph, connectionId) {
|
|
10744
|
+
return {
|
|
10745
|
+
...graph,
|
|
10746
|
+
nodes: Object.fromEntries(Object.entries(graph.nodes).map(([id, node]) => {
|
|
10747
|
+
if ((node.kind == "poll" || node.kind == "integration") && (connectionId == null || node.connectionId == connectionId)) {
|
|
10748
|
+
const { connectionId: _, ...remaining } = node;
|
|
10749
|
+
return [id, remaining];
|
|
10750
|
+
}
|
|
10751
|
+
if (node.kind != "task") return [id, node];
|
|
10752
|
+
if ("executor" in node.task) {
|
|
10753
|
+
const executor = node.task.executor;
|
|
10754
|
+
const clear = (value) => {
|
|
10755
|
+
if (value.connectionId === "") return value;
|
|
10756
|
+
if (connectionId != null && value.connectionId != connectionId) return value;
|
|
10757
|
+
const { connectionId: _, ...rest } = value;
|
|
10758
|
+
return rest;
|
|
10759
|
+
};
|
|
10760
|
+
if (executor.kind == "connector") return [id, {
|
|
10761
|
+
...node,
|
|
10762
|
+
task: {
|
|
10763
|
+
...node.task,
|
|
10764
|
+
executor: clear(executor)
|
|
10765
|
+
}
|
|
10766
|
+
}];
|
|
10767
|
+
if (executor.kind == "agent") return [id, {
|
|
10768
|
+
...node,
|
|
10769
|
+
task: {
|
|
10770
|
+
...node.task,
|
|
10771
|
+
executor: {
|
|
10772
|
+
...executor,
|
|
10773
|
+
tools: executor.tools.map(clear),
|
|
10774
|
+
...executor.notification == null ? {} : { notification: clear(executor.notification) }
|
|
10775
|
+
}
|
|
10776
|
+
}
|
|
10777
|
+
}];
|
|
10778
|
+
return [id, node];
|
|
10779
|
+
}
|
|
10780
|
+
const capabilities = node.task.capabilities?.map((capability) => {
|
|
10781
|
+
if (capability.kind == "workflow" || capability.kind == "http") return capability;
|
|
10782
|
+
if (!("mode" in capability)) {
|
|
10783
|
+
if ("action" in capability) {
|
|
10784
|
+
const { connectionId: selected, ...rest } = capability;
|
|
10785
|
+
return {
|
|
10786
|
+
...rest,
|
|
10787
|
+
connections: capability.connections.filter((item) => connectionId != null && item.connectionId != connectionId),
|
|
10788
|
+
...selected != null && connectionId != null && selected != connectionId ? { connectionId: selected } : {}
|
|
10789
|
+
};
|
|
10790
|
+
}
|
|
10791
|
+
return {
|
|
10792
|
+
...capability,
|
|
10793
|
+
...connectionId == null && (capability.connectionHints?.length ?? 0) > 0 ? { actionHints: [.../* @__PURE__ */ new Set([...capability.actionHints ?? [], ...capability.connectionHints.map((hint) => hint.action)])] } : {},
|
|
10794
|
+
...capability.connectionHints == null ? {} : { connectionHints: capability.connectionHints.filter((item) => connectionId != null && item.connectionId != connectionId) }
|
|
10795
|
+
};
|
|
10796
|
+
}
|
|
10797
|
+
if (capability.mode != "independent") return capability;
|
|
10798
|
+
return {
|
|
10799
|
+
...capability,
|
|
10800
|
+
actions: capability.actions.map((action) => {
|
|
10801
|
+
if (action.connectionId === "") return action;
|
|
10802
|
+
if (connectionId != null && action.connectionId != connectionId) return action;
|
|
10803
|
+
const { connectionId: _, ...remaining } = action;
|
|
10804
|
+
return remaining;
|
|
10805
|
+
})
|
|
10806
|
+
};
|
|
10807
|
+
});
|
|
10808
|
+
return [id, capabilities == null ? node : {
|
|
10809
|
+
...node,
|
|
10810
|
+
task: {
|
|
10811
|
+
...node.task,
|
|
10812
|
+
capabilities
|
|
10813
|
+
}
|
|
10814
|
+
}];
|
|
10815
|
+
}))
|
|
10816
|
+
};
|
|
10817
|
+
}
|
|
10818
|
+
//#endregion
|
|
10679
10819
|
//#region src/flow/common/workflowFile.ts
|
|
10680
10820
|
var envelope = strictObject({
|
|
10681
10821
|
kind: literal("open-flow-workflow"),
|
|
10682
10822
|
version: literal(1),
|
|
10683
10823
|
name: string$1().optional(),
|
|
10824
|
+
icon: string$1().optional(),
|
|
10825
|
+
description: string$1().optional(),
|
|
10684
10826
|
content: unknown(),
|
|
10685
10827
|
presentation: record$2(string$1(), json$3()).optional()
|
|
10686
10828
|
});
|
|
@@ -10693,6 +10835,126 @@ function decodeWorkflowFile(value) {
|
|
|
10693
10835
|
content: decodeRevisionContent(file.content)
|
|
10694
10836
|
};
|
|
10695
10837
|
}
|
|
10838
|
+
function cleanInput(input) {
|
|
10839
|
+
if (input.kind != "sources" || !input.sources.some((source) => source.kind == "binding")) return input;
|
|
10840
|
+
const sources = input.sources.filter((source) => source.kind != "binding");
|
|
10841
|
+
return sources.length == 0 ? { kind: "unset" } : {
|
|
10842
|
+
kind: "sources",
|
|
10843
|
+
sources
|
|
10844
|
+
};
|
|
10845
|
+
}
|
|
10846
|
+
/** Clear only owned structured references, never strings in code or business values. */
|
|
10847
|
+
function cleanWorkflowFile(value) {
|
|
10848
|
+
const file = decodeWorkflowFile(value);
|
|
10849
|
+
const original = file.content.document.graph;
|
|
10850
|
+
const graph = clearNodeConnections(original);
|
|
10851
|
+
const nodes = Object.fromEntries(Object.entries(graph.nodes).map(([id, source]) => {
|
|
10852
|
+
let node = source;
|
|
10853
|
+
if ("inputs" in node) node = {
|
|
10854
|
+
...node,
|
|
10855
|
+
inputs: Object.fromEntries(Object.entries(node.inputs).map(([key, input]) => [key, cleanInput(input)]))
|
|
10856
|
+
};
|
|
10857
|
+
if (node.kind == "outputs") node = {
|
|
10858
|
+
...node,
|
|
10859
|
+
outputMappings: Object.fromEntries(Object.entries(node.outputMappings).map(([key, input]) => [key, cleanInput(input)]))
|
|
10860
|
+
};
|
|
10861
|
+
if (node.kind == "condition") node = clearConditionBindings(node);
|
|
10862
|
+
if (node.kind == "error" && node.sourceFlowIds != null) node = {
|
|
10863
|
+
...node,
|
|
10864
|
+
sourceFlowIds: []
|
|
10865
|
+
};
|
|
10866
|
+
if (node.kind == "poll" || node.kind == "integration") node = {
|
|
10867
|
+
...node,
|
|
10868
|
+
config: clearTriggerExternalConfig(node.definition.key, node.config)
|
|
10869
|
+
};
|
|
10870
|
+
return [id, node];
|
|
10871
|
+
}));
|
|
10872
|
+
return {
|
|
10873
|
+
file: {
|
|
10874
|
+
...file,
|
|
10875
|
+
content: {
|
|
10876
|
+
...file.content,
|
|
10877
|
+
document: {
|
|
10878
|
+
...file.content.document,
|
|
10879
|
+
bindings: {},
|
|
10880
|
+
graph: {
|
|
10881
|
+
...graph,
|
|
10882
|
+
nodes
|
|
10883
|
+
}
|
|
10884
|
+
}
|
|
10885
|
+
}
|
|
10886
|
+
},
|
|
10887
|
+
summary: {
|
|
10888
|
+
changedNodeIds: Object.keys(nodes).filter((id) => !dequal(nodes[id], original.nodes[id])),
|
|
10889
|
+
removedBindings: Object.keys(file.content.document.bindings).length
|
|
10890
|
+
}
|
|
10891
|
+
};
|
|
10892
|
+
}
|
|
10893
|
+
//#endregion
|
|
10894
|
+
//#region src/flow/common/workflowBundle.ts
|
|
10895
|
+
var entries = array(strictObject({
|
|
10896
|
+
flowId: string$1().min(1),
|
|
10897
|
+
file: unknown()
|
|
10898
|
+
})).min(1);
|
|
10899
|
+
var bundleSchema = strictObject({
|
|
10900
|
+
kind: literal("open-flow-workflow-bundle"),
|
|
10901
|
+
version: literal(1),
|
|
10902
|
+
entryFlowId: string$1().min(1),
|
|
10903
|
+
workflows: entries
|
|
10904
|
+
});
|
|
10905
|
+
var previewSchema = strictObject({
|
|
10906
|
+
version: literal(1),
|
|
10907
|
+
entryFlowId: string$1().min(1),
|
|
10908
|
+
workflows: entries,
|
|
10909
|
+
unavailableFlowIds: array(string$1().min(1))
|
|
10910
|
+
});
|
|
10911
|
+
function decodeEntries(value, entryFlowId, unavailableFlowIds = []) {
|
|
10912
|
+
const workflows = value.map(({ flowId, file }) => ({
|
|
10913
|
+
flowId,
|
|
10914
|
+
file: decodeWorkflowFile(file)
|
|
10915
|
+
}));
|
|
10916
|
+
const ids = new Set(workflows.map(({ flowId }) => flowId));
|
|
10917
|
+
if (ids.size != workflows.length || !ids.has(entryFlowId)) throw new TypeError("Workflow identities must be unique and include the entry workflow.");
|
|
10918
|
+
const unavailable = new Set(unavailableFlowIds);
|
|
10919
|
+
if (unavailable.size != unavailableFlowIds.length || unavailableFlowIds.some((id) => ids.has(id))) throw new TypeError("Invalid unavailable workflow identities.");
|
|
10920
|
+
for (const { file } of workflows) for (const node of Object.values(file.content.document.graph.nodes)) for (const { target } of nodeWorkflowReferences(node)) if (target.flowId && !ids.has(target.flowId) && !unavailable.has(target.flowId)) throw new TypeError("A referenced workflow is missing from the bundle.");
|
|
10921
|
+
return workflows;
|
|
10922
|
+
}
|
|
10923
|
+
function decodeWorkflowBundle(value) {
|
|
10924
|
+
checkJsonDepth(value, -4);
|
|
10925
|
+
const bundle = bundleSchema.parse(value);
|
|
10926
|
+
return {
|
|
10927
|
+
...bundle,
|
|
10928
|
+
workflows: decodeEntries(bundle.workflows, bundle.entryFlowId)
|
|
10929
|
+
};
|
|
10930
|
+
}
|
|
10931
|
+
function decodeWorkflowExportPreview(value) {
|
|
10932
|
+
checkJsonDepth(value, -4);
|
|
10933
|
+
const preview = previewSchema.parse(value);
|
|
10934
|
+
return {
|
|
10935
|
+
...preview,
|
|
10936
|
+
workflows: decodeEntries(preview.workflows, preview.entryFlowId, preview.unavailableFlowIds)
|
|
10937
|
+
};
|
|
10938
|
+
}
|
|
10939
|
+
function cleanWorkflowBundle(value) {
|
|
10940
|
+
const bundle = decodeWorkflowBundle(value);
|
|
10941
|
+
return {
|
|
10942
|
+
...bundle,
|
|
10943
|
+
workflows: bundle.workflows.map(({ flowId, file }) => ({
|
|
10944
|
+
flowId,
|
|
10945
|
+
file: cleanWorkflowFile(file).file
|
|
10946
|
+
}))
|
|
10947
|
+
};
|
|
10948
|
+
}
|
|
10949
|
+
function workflowBundleFromPreview(preview) {
|
|
10950
|
+
if (preview.unavailableFlowIds.length) throw new TypeError("Some referenced workflows are unavailable.");
|
|
10951
|
+
return cleanWorkflowBundle({
|
|
10952
|
+
kind: "open-flow-workflow-bundle",
|
|
10953
|
+
version: 1,
|
|
10954
|
+
entryFlowId: preview.entryFlowId,
|
|
10955
|
+
workflows: preview.workflows
|
|
10956
|
+
});
|
|
10957
|
+
}
|
|
10696
10958
|
//#endregion
|
|
10697
10959
|
//#region src/flow/common/encoding.ts
|
|
10698
10960
|
var encoder$1 = new TextEncoder();
|
|
@@ -11996,6 +12258,8 @@ function flow(value) {
|
|
|
11996
12258
|
resourceReferences: resourceReferences(source.resourceReferences),
|
|
11997
12259
|
flowId: string(source.flowId),
|
|
11998
12260
|
name: string(source.name),
|
|
12261
|
+
...source.icon === void 0 ? {} : { icon: string(source.icon) },
|
|
12262
|
+
...source.description === void 0 ? {} : { description: string(source.description) },
|
|
11999
12263
|
status,
|
|
12000
12264
|
updatedAt: string(source.updatedAt),
|
|
12001
12265
|
version: 1
|
|
@@ -12482,6 +12746,18 @@ function decodeTagListItem(value) {
|
|
|
12482
12746
|
}
|
|
12483
12747
|
//#endregion
|
|
12484
12748
|
//#region src/control/common/api.ts
|
|
12749
|
+
function decodeWorkflowBundleImportResult(value) {
|
|
12750
|
+
const source = record(value);
|
|
12751
|
+
if (source.version != 1 || !Array.isArray(source.flows) || source.flows.length == 0) return invalidResponse();
|
|
12752
|
+
const entry = flow(source.flow);
|
|
12753
|
+
const flows = source.flows.map(flow);
|
|
12754
|
+
if (new Set(flows.map((item) => item.flowId)).size != flows.length || !flows.some((item) => item.flowId == entry.flowId)) return invalidResponse();
|
|
12755
|
+
return {
|
|
12756
|
+
version: 1,
|
|
12757
|
+
flow: entry,
|
|
12758
|
+
flows
|
|
12759
|
+
};
|
|
12760
|
+
}
|
|
12485
12761
|
function isRunTerminalEvent(event) {
|
|
12486
12762
|
return event?.kind == "run.completed" || event?.kind == "run.failed" || event?.kind == "run.canceled" || event?.kind == "run.indeterminate";
|
|
12487
12763
|
}
|
|
@@ -12799,6 +13075,32 @@ var ControlClient = class {
|
|
|
12799
13075
|
return invalidResponse();
|
|
12800
13076
|
}
|
|
12801
13077
|
}
|
|
13078
|
+
async getFlowExportPreview(flowId) {
|
|
13079
|
+
const value = await this.request(`/v1/flows/${segment(flowId)}/export-preview`);
|
|
13080
|
+
try {
|
|
13081
|
+
return decodeWorkflowExportPreview(value);
|
|
13082
|
+
} catch {
|
|
13083
|
+
return invalidResponse();
|
|
13084
|
+
}
|
|
13085
|
+
}
|
|
13086
|
+
async exportFlowBundle(flowId) {
|
|
13087
|
+
const preview = await this.getFlowExportPreview(flowId);
|
|
13088
|
+
if (preview.unavailableFlowIds.length) throw new ApiError(400, "flow.invalid", "Some referenced workflows are unavailable.");
|
|
13089
|
+
return workflowBundleFromPreview(preview);
|
|
13090
|
+
}
|
|
13091
|
+
async importFlowBundle(file, options = {}) {
|
|
13092
|
+
return decodeWorkflowBundleImportResult(await this.request("/v1/flows/import-bundle", {
|
|
13093
|
+
method: "POST",
|
|
13094
|
+
headers: { "Idempotency-Key": options.idempotencyKey ?? `flow-${randomId()}` },
|
|
13095
|
+
body: JSON.stringify({
|
|
13096
|
+
file,
|
|
13097
|
+
name: options.name,
|
|
13098
|
+
teamId: options.teamId,
|
|
13099
|
+
tagIds: options.tagIds,
|
|
13100
|
+
version: 1
|
|
13101
|
+
})
|
|
13102
|
+
}));
|
|
13103
|
+
}
|
|
12802
13104
|
async importFlow(file, options = {}) {
|
|
12803
13105
|
return flow(await this.request("/v1/flows/import", {
|
|
12804
13106
|
method: "POST",
|
|
@@ -13455,4 +13757,4 @@ var ControlClient = class {
|
|
|
13455
13757
|
}
|
|
13456
13758
|
};
|
|
13457
13759
|
//#endregion
|
|
13458
|
-
export { ApiError, ControlClient, actionSummary, controlErrorCode, controlErrorMetadata, connectorAccess as decodeConnectorAccess, connectorAccessSnapshot as decodeConnectorAccessSnapshot, decodeEventSource, decodeEventSources, decodeResultList, decodeResultRead, decodeRunEvent, decodeTriggerCatalog, flowInputDefinitions, flowInspection, inspectFlowDraft, isRunTerminalEvent, liveEntries, nodeDetails, normalizeFlowQuery, parseProviderAccessSource, parseResultQuery, providerAccessBindingId, providerIconAppearance, readResult, searchTriggerKeys };
|
|
13760
|
+
export { ApiError, ControlClient, actionSummary, controlErrorCode, controlErrorMetadata, connectorAccess as decodeConnectorAccess, connectorAccessSnapshot as decodeConnectorAccessSnapshot, decodeEventSource, decodeEventSources, decodeResultList, decodeResultRead, decodeRunEvent, decodeTriggerCatalog, decodeWorkflowBundleImportResult, flowInputDefinitions, flowInspection, inspectFlowDraft, isRunTerminalEvent, liveEntries, nodeDetails, normalizeFlowQuery, parseProviderAccessSource, parseResultQuery, providerAccessBindingId, providerIconAppearance, readResult, searchTriggerKeys };
|
|
@@ -224,12 +224,10 @@ export declare const controlRequests: {
|
|
|
224
224
|
version: 1;
|
|
225
225
|
};
|
|
226
226
|
updateFlow: (value: unknown) => {
|
|
227
|
-
name: string;
|
|
228
|
-
tagIds?: string[] | undefined;
|
|
229
|
-
version: 1;
|
|
230
|
-
} | {
|
|
231
227
|
name?: string | undefined;
|
|
232
|
-
|
|
228
|
+
icon?: string | null | undefined;
|
|
229
|
+
description?: string | null | undefined;
|
|
230
|
+
tagIds?: string[] | undefined;
|
|
233
231
|
version: 1;
|
|
234
232
|
};
|
|
235
233
|
renameFlow: (value: unknown) => {
|
|
@@ -17948,15 +17948,13 @@ var schemas = {
|
|
|
17948
17948
|
tagIds,
|
|
17949
17949
|
version
|
|
17950
17950
|
}),
|
|
17951
|
-
updateFlow:
|
|
17952
|
-
name: flowName,
|
|
17953
|
-
tagIds: tagIds.optional(),
|
|
17954
|
-
version
|
|
17955
|
-
}), strictObject({
|
|
17951
|
+
updateFlow: strictObject({
|
|
17956
17952
|
name: flowName.optional(),
|
|
17957
|
-
|
|
17953
|
+
icon: string().nullable().optional(),
|
|
17954
|
+
description: string().nullable().optional(),
|
|
17955
|
+
tagIds: tagIds.optional(),
|
|
17958
17956
|
version
|
|
17959
|
-
})
|
|
17957
|
+
}).refine((value) => value.name !== void 0 || value.icon !== void 0 || value.description !== void 0 || value.tagIds !== void 0, "Flow settings are empty."),
|
|
17960
17958
|
renameFlow: strictObject({
|
|
17961
17959
|
name: flowName,
|
|
17962
17960
|
version
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CodeModule, FlowDocument, Graph, Group, InputMapping, InputPort, JsonValue, ManagedTaskDefinition, Port, RevisionContent, TriggerNode } from '@oomol-lab/open-flow/flow-change';
|
|
2
2
|
export * from './flow-workflowFile.js';
|
|
3
|
+
export * from './flow-workflowBundle.js';
|
|
3
4
|
export { maxJsonDepth } from './flow-json.js';
|
|
4
5
|
export { decodeFlowDocument, decodeRevisionContent, upgradeWorkflowInterfaceDocument } from './flow-change-schema.js';
|
|
5
6
|
export { upgradeRevisionContent } from '@oomol-lab/open-flow/flow-change';
|
|
@@ -9856,6 +9856,8 @@ var envelope = strictObject({
|
|
|
9856
9856
|
kind: literal("open-flow-workflow"),
|
|
9857
9857
|
version: literal(1),
|
|
9858
9858
|
name: string().optional(),
|
|
9859
|
+
icon: string().optional(),
|
|
9860
|
+
description: string().optional(),
|
|
9859
9861
|
content: unknown(),
|
|
9860
9862
|
presentation: record$1(string(), json$1()).optional()
|
|
9861
9863
|
});
|
|
@@ -9936,6 +9938,170 @@ function workflowNameFromFile(name) {
|
|
|
9936
9938
|
return name.replace(/(?:\.openflow)?\.json$/i, "");
|
|
9937
9939
|
}
|
|
9938
9940
|
//#endregion
|
|
9941
|
+
//#region src/flow/common/workflowReferences.ts
|
|
9942
|
+
/** Rewrite only declared workflow identities, preserving business values and saved ports. */
|
|
9943
|
+
function mapNodeWorkflowTargets(node, map) {
|
|
9944
|
+
if (node.kind != "task") return node;
|
|
9945
|
+
const task = node.task;
|
|
9946
|
+
if ("moduleId" in task) return task.capabilities?.some((item) => item.kind == "workflow") ? {
|
|
9947
|
+
...node,
|
|
9948
|
+
task: {
|
|
9949
|
+
...task,
|
|
9950
|
+
capabilities: task.capabilities.map((item) => item.kind == "workflow" ? Object.assign({}, item, map(item)) : item)
|
|
9951
|
+
}
|
|
9952
|
+
} : node;
|
|
9953
|
+
const executor = task.executor;
|
|
9954
|
+
if (executor.kind == "workflow") return {
|
|
9955
|
+
...node,
|
|
9956
|
+
task: {
|
|
9957
|
+
...task,
|
|
9958
|
+
executor: {
|
|
9959
|
+
...executor,
|
|
9960
|
+
...map(executor)
|
|
9961
|
+
}
|
|
9962
|
+
}
|
|
9963
|
+
};
|
|
9964
|
+
if (executor.kind == "agent") return {
|
|
9965
|
+
...node,
|
|
9966
|
+
task: {
|
|
9967
|
+
...task,
|
|
9968
|
+
executor: {
|
|
9969
|
+
...executor,
|
|
9970
|
+
tools: executor.tools.map((tool) => tool.kind == "workflow" ? Object.assign({}, tool, map(tool)) : tool)
|
|
9971
|
+
}
|
|
9972
|
+
}
|
|
9973
|
+
};
|
|
9974
|
+
return node;
|
|
9975
|
+
}
|
|
9976
|
+
/** Workflow declarations share discovery across authoring, admission and resource indexing. */
|
|
9977
|
+
function nodeWorkflowReferences(node) {
|
|
9978
|
+
if (node.kind != "task") return [];
|
|
9979
|
+
if ("moduleId" in node.task) return (node.task.capabilities ?? []).flatMap((item, index) => item.kind == "workflow" ? [{
|
|
9980
|
+
target: item,
|
|
9981
|
+
path: `task/capabilities/${index}`,
|
|
9982
|
+
tool: item.name
|
|
9983
|
+
}] : []);
|
|
9984
|
+
if (node.task.executor.kind == "workflow") return [{
|
|
9985
|
+
target: {
|
|
9986
|
+
...node.task.executor,
|
|
9987
|
+
inputs: node.task.inputs.filter((port) => "handle" in port),
|
|
9988
|
+
outputs: node.task.outputs.filter((port) => "handle" in port)
|
|
9989
|
+
},
|
|
9990
|
+
path: "task/executor"
|
|
9991
|
+
}];
|
|
9992
|
+
if (node.task.executor.kind == "agent") return node.task.executor.tools.flatMap((item, index) => item.kind == "workflow" ? [{
|
|
9993
|
+
target: item,
|
|
9994
|
+
path: `task/executor/tools/${index}`,
|
|
9995
|
+
tool: item.name
|
|
9996
|
+
}] : []);
|
|
9997
|
+
return [];
|
|
9998
|
+
}
|
|
9999
|
+
//#endregion
|
|
10000
|
+
//#region src/flow/common/workflowBundle.ts
|
|
10001
|
+
var entries$1 = array(strictObject({
|
|
10002
|
+
flowId: string().min(1),
|
|
10003
|
+
file: unknown()
|
|
10004
|
+
})).min(1);
|
|
10005
|
+
var bundleSchema = strictObject({
|
|
10006
|
+
kind: literal("open-flow-workflow-bundle"),
|
|
10007
|
+
version: literal(1),
|
|
10008
|
+
entryFlowId: string().min(1),
|
|
10009
|
+
workflows: entries$1
|
|
10010
|
+
});
|
|
10011
|
+
var previewSchema = strictObject({
|
|
10012
|
+
version: literal(1),
|
|
10013
|
+
entryFlowId: string().min(1),
|
|
10014
|
+
workflows: entries$1,
|
|
10015
|
+
unavailableFlowIds: array(string().min(1))
|
|
10016
|
+
});
|
|
10017
|
+
function decodeEntries(value, entryFlowId, unavailableFlowIds = []) {
|
|
10018
|
+
const workflows = value.map(({ flowId, file }) => ({
|
|
10019
|
+
flowId,
|
|
10020
|
+
file: decodeWorkflowFile(file)
|
|
10021
|
+
}));
|
|
10022
|
+
const ids = new Set(workflows.map(({ flowId }) => flowId));
|
|
10023
|
+
if (ids.size != workflows.length || !ids.has(entryFlowId)) throw new TypeError("Workflow identities must be unique and include the entry workflow.");
|
|
10024
|
+
const unavailable = new Set(unavailableFlowIds);
|
|
10025
|
+
if (unavailable.size != unavailableFlowIds.length || unavailableFlowIds.some((id) => ids.has(id))) throw new TypeError("Invalid unavailable workflow identities.");
|
|
10026
|
+
for (const { file } of workflows) for (const node of Object.values(file.content.document.graph.nodes)) for (const { target } of nodeWorkflowReferences(node)) if (target.flowId && !ids.has(target.flowId) && !unavailable.has(target.flowId)) throw new TypeError("A referenced workflow is missing from the bundle.");
|
|
10027
|
+
return workflows;
|
|
10028
|
+
}
|
|
10029
|
+
function decodeWorkflowBundle(value) {
|
|
10030
|
+
checkJsonDepth(value, -4);
|
|
10031
|
+
const bundle = bundleSchema.parse(value);
|
|
10032
|
+
return {
|
|
10033
|
+
...bundle,
|
|
10034
|
+
workflows: decodeEntries(bundle.workflows, bundle.entryFlowId)
|
|
10035
|
+
};
|
|
10036
|
+
}
|
|
10037
|
+
function decodeWorkflowExportPreview(value) {
|
|
10038
|
+
checkJsonDepth(value, -4);
|
|
10039
|
+
const preview = previewSchema.parse(value);
|
|
10040
|
+
return {
|
|
10041
|
+
...preview,
|
|
10042
|
+
workflows: decodeEntries(preview.workflows, preview.entryFlowId, preview.unavailableFlowIds)
|
|
10043
|
+
};
|
|
10044
|
+
}
|
|
10045
|
+
function cleanWorkflowBundle(value) {
|
|
10046
|
+
const bundle = decodeWorkflowBundle(value);
|
|
10047
|
+
return {
|
|
10048
|
+
...bundle,
|
|
10049
|
+
workflows: bundle.workflows.map(({ flowId, file }) => ({
|
|
10050
|
+
flowId,
|
|
10051
|
+
file: cleanWorkflowFile(file).file
|
|
10052
|
+
}))
|
|
10053
|
+
};
|
|
10054
|
+
}
|
|
10055
|
+
function workflowBundleFromPreview(preview) {
|
|
10056
|
+
if (preview.unavailableFlowIds.length) throw new TypeError("Some referenced workflows are unavailable.");
|
|
10057
|
+
return cleanWorkflowBundle({
|
|
10058
|
+
kind: "open-flow-workflow-bundle",
|
|
10059
|
+
version: 1,
|
|
10060
|
+
entryFlowId: preview.entryFlowId,
|
|
10061
|
+
workflows: preview.workflows
|
|
10062
|
+
});
|
|
10063
|
+
}
|
|
10064
|
+
function encodeWorkflowBundle(bundle) {
|
|
10065
|
+
return `${JSON.stringify(cleanWorkflowBundle(bundle), null, 2)}\n`;
|
|
10066
|
+
}
|
|
10067
|
+
function parseWorkflowImportFile(text) {
|
|
10068
|
+
const value = JSON.parse(text);
|
|
10069
|
+
return value != null && typeof value == "object" && "kind" in value && value.kind == "open-flow-workflow-bundle" ? decodeWorkflowBundle(value) : decodeWorkflowFile(value);
|
|
10070
|
+
}
|
|
10071
|
+
/** A bundle creates new drafts, so old published interface provenance must be refreshed. */
|
|
10072
|
+
function remapWorkflowBundle(bundle, flowIds) {
|
|
10073
|
+
const cleaned = cleanWorkflowBundle(bundle);
|
|
10074
|
+
function identity(flowId) {
|
|
10075
|
+
const mapped = flowIds.get(flowId);
|
|
10076
|
+
if (mapped == null || mapped.length == 0) throw new TypeError("Missing imported workflow identity.");
|
|
10077
|
+
return mapped;
|
|
10078
|
+
}
|
|
10079
|
+
const workflows = cleaned.workflows.map(({ flowId, file }) => ({
|
|
10080
|
+
flowId: identity(flowId),
|
|
10081
|
+
file: {
|
|
10082
|
+
...file,
|
|
10083
|
+
content: {
|
|
10084
|
+
...file.content,
|
|
10085
|
+
document: {
|
|
10086
|
+
...file.content.document,
|
|
10087
|
+
graph: {
|
|
10088
|
+
...file.content.document.graph,
|
|
10089
|
+
nodes: Object.fromEntries(Object.entries(file.content.document.graph.nodes).map(([id, node]) => [id, mapNodeWorkflowTargets(node, (target) => ({
|
|
10090
|
+
flowId: target.flowId ? identity(target.flowId) : "",
|
|
10091
|
+
revisionId: ""
|
|
10092
|
+
}))]))
|
|
10093
|
+
}
|
|
10094
|
+
}
|
|
10095
|
+
}
|
|
10096
|
+
}
|
|
10097
|
+
}));
|
|
10098
|
+
return decodeWorkflowBundle({
|
|
10099
|
+
...cleaned,
|
|
10100
|
+
entryFlowId: identity(cleaned.entryFlowId),
|
|
10101
|
+
workflows
|
|
10102
|
+
});
|
|
10103
|
+
}
|
|
10104
|
+
//#endregion
|
|
9939
10105
|
//#region src/flow/common/encoding.ts
|
|
9940
10106
|
var encoder = new TextEncoder();
|
|
9941
10107
|
function canonicalText(value) {
|
|
@@ -10315,4 +10481,4 @@ function repairRevision(bytes) {
|
|
|
10315
10481
|
return repairRevisionEnvelope(revisionValue(bytes));
|
|
10316
10482
|
}
|
|
10317
10483
|
//#endregion
|
|
10318
|
-
export { canonicalDocument, canonicalGraph, canonicalInputs, canonicalJsonBytes, canonicalModule, canonicalPorts, canonicalRevisionGraph, canonicalTask, cleanWorkflowFile, decodeFlowDocument, decodeRevision, decodeRevisionContent, decodeWorkflowFile, digestBytes, encodeRevision, encodeWorkflowFile, maxJsonDepth, parseWorkflowFile, repairRevision, revisionRepairKind, triggerRuntimeJson, upgradeRevisionContent, upgradeWorkflowInterfaceDocument, workflowFileName, workflowNameFromFile };
|
|
10484
|
+
export { canonicalDocument, canonicalGraph, canonicalInputs, canonicalJsonBytes, canonicalModule, canonicalPorts, canonicalRevisionGraph, canonicalTask, cleanWorkflowBundle, cleanWorkflowFile, decodeFlowDocument, decodeRevision, decodeRevisionContent, decodeWorkflowBundle, decodeWorkflowExportPreview, decodeWorkflowFile, digestBytes, encodeRevision, encodeWorkflowBundle, encodeWorkflowFile, maxJsonDepth, parseWorkflowFile, parseWorkflowImportFile, remapWorkflowBundle, repairRevision, revisionRepairKind, triggerRuntimeJson, upgradeRevisionContent, upgradeWorkflowInterfaceDocument, workflowBundleFromPreview, workflowFileName, workflowNameFromFile };
|
|
@@ -12336,10 +12336,30 @@ strictObject({
|
|
|
12336
12336
|
kind: literal("open-flow-workflow"),
|
|
12337
12337
|
version: literal(1),
|
|
12338
12338
|
name: string().optional(),
|
|
12339
|
+
icon: string().optional(),
|
|
12340
|
+
description: string().optional(),
|
|
12339
12341
|
content: unknown(),
|
|
12340
12342
|
presentation: record$1(string(), json$1()).optional()
|
|
12341
12343
|
});
|
|
12342
12344
|
//#endregion
|
|
12345
|
+
//#region src/flow/common/workflowBundle.ts
|
|
12346
|
+
var entries$2 = array(strictObject({
|
|
12347
|
+
flowId: string().min(1),
|
|
12348
|
+
file: unknown()
|
|
12349
|
+
})).min(1);
|
|
12350
|
+
strictObject({
|
|
12351
|
+
kind: literal("open-flow-workflow-bundle"),
|
|
12352
|
+
version: literal(1),
|
|
12353
|
+
entryFlowId: string().min(1),
|
|
12354
|
+
workflows: entries$2
|
|
12355
|
+
});
|
|
12356
|
+
strictObject({
|
|
12357
|
+
version: literal(1),
|
|
12358
|
+
entryFlowId: string().min(1),
|
|
12359
|
+
workflows: entries$2,
|
|
12360
|
+
unavailableFlowIds: array(string().min(1))
|
|
12361
|
+
});
|
|
12362
|
+
//#endregion
|
|
12343
12363
|
//#region src/flow/common/encoding.ts
|
|
12344
12364
|
var encoder = new TextEncoder();
|
|
12345
12365
|
function canonicalText(value) {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { WorkflowFile } from './flow-workflowFile.js';
|
|
2
|
+
export interface WorkflowBundleEntry {
|
|
3
|
+
readonly flowId: string;
|
|
4
|
+
readonly file: WorkflowFile;
|
|
5
|
+
}
|
|
6
|
+
export interface WorkflowBundle {
|
|
7
|
+
readonly kind: 'open-flow-workflow-bundle';
|
|
8
|
+
readonly version: 1;
|
|
9
|
+
readonly entryFlowId: string;
|
|
10
|
+
readonly workflows: readonly WorkflowBundleEntry[];
|
|
11
|
+
}
|
|
12
|
+
/** A saved export snapshot; unavailable targets carry no account metadata. */
|
|
13
|
+
export interface WorkflowExportPreview {
|
|
14
|
+
readonly version: 1;
|
|
15
|
+
readonly entryFlowId: string;
|
|
16
|
+
readonly workflows: readonly WorkflowBundleEntry[];
|
|
17
|
+
readonly unavailableFlowIds: readonly string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function decodeWorkflowBundle(value: unknown): WorkflowBundle;
|
|
20
|
+
export declare function decodeWorkflowExportPreview(value: unknown): WorkflowExportPreview;
|
|
21
|
+
export declare function cleanWorkflowBundle(value: unknown): WorkflowBundle;
|
|
22
|
+
export declare function workflowBundleFromPreview(preview: WorkflowExportPreview): WorkflowBundle;
|
|
23
|
+
export declare function encodeWorkflowBundle(bundle: WorkflowBundle): string;
|
|
24
|
+
export type WorkflowImportFile = WorkflowFile | WorkflowBundle;
|
|
25
|
+
export declare function parseWorkflowImportFile(text: string): WorkflowImportFile;
|
|
26
|
+
/** A bundle creates new drafts, so old published interface provenance must be refreshed. */
|
|
27
|
+
export declare function remapWorkflowBundle(bundle: WorkflowBundle, flowIds: ReadonlyMap<string, string>): WorkflowBundle;
|
|
@@ -3,6 +3,8 @@ export interface WorkflowFile {
|
|
|
3
3
|
readonly kind: 'open-flow-workflow';
|
|
4
4
|
readonly version: 1;
|
|
5
5
|
readonly name?: string;
|
|
6
|
+
readonly icon?: string;
|
|
7
|
+
readonly description?: string;
|
|
6
8
|
readonly content: RevisionContent;
|
|
7
9
|
readonly presentation?: Readonly<Record<string, JsonValue>>;
|
|
8
10
|
}
|