@ixo/editor 5.33.0 → 5.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-RGPJQGNB.mjs → chunk-4AAU3G26.mjs} +2 -2
- package/dist/chunk-JNR73I6T.mjs +190 -0
- package/dist/chunk-JNR73I6T.mjs.map +1 -0
- package/dist/{chunk-NAR2R3YM.mjs → chunk-TK2RJ4KB.mjs} +935 -106
- package/dist/chunk-TK2RJ4KB.mjs.map +1 -0
- package/dist/core/index.d.ts +187 -4
- package/dist/core/index.mjs +33 -2
- package/dist/core/index.mjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +3 -3
- package/dist/mantine/index.mjs +2 -2
- package/dist/{store-DT8zznZ6.d.ts → store-5Paxg7-U.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-NAR2R3YM.mjs.map +0 -1
- package/dist/chunk-OK2W66I7.mjs +0 -1
- package/dist/chunk-OK2W66I7.mjs.map +0 -1
- /package/dist/{chunk-RGPJQGNB.mjs.map → chunk-4AAU3G26.mjs.map} +0 -0
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
transformSurveyToCredentialSubject,
|
|
66
66
|
updateXeroWorkReviewPayloadForEditor,
|
|
67
67
|
upsertXeroWorkItemForEditor
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-TK2RJ4KB.mjs";
|
|
69
69
|
|
|
70
70
|
// src/mantine/hooks/usePanel.ts
|
|
71
71
|
import { useCallback, useMemo, useEffect, useRef } from "react";
|
|
@@ -47355,4 +47355,4 @@ export {
|
|
|
47355
47355
|
ixoGraphQLClient,
|
|
47356
47356
|
getEntity
|
|
47357
47357
|
};
|
|
47358
|
-
//# sourceMappingURL=chunk-
|
|
47358
|
+
//# sourceMappingURL=chunk-4AAU3G26.mjs.map
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readBlocksFromFragment,
|
|
3
|
+
readCompiledFlowFromYDoc,
|
|
4
|
+
removeAllFlowBlocks,
|
|
5
|
+
removeBlockFromFragment,
|
|
6
|
+
replaceBlockInFragment,
|
|
7
|
+
writeCompiledBlocksToFragment
|
|
8
|
+
} from "./chunk-TK2RJ4KB.mjs";
|
|
9
|
+
|
|
10
|
+
// src/core/lib/flowCompiler/authoring.ts
|
|
11
|
+
import * as Y from "yjs";
|
|
12
|
+
function readFlowDocument(yDoc) {
|
|
13
|
+
const compiled = readCompiledFlowFromYDoc(yDoc);
|
|
14
|
+
if (!compiled) return null;
|
|
15
|
+
const propsByBlockId = /* @__PURE__ */ new Map();
|
|
16
|
+
for (const block of readBlocksFromFragment(yDoc.getXmlFragment("document"))) {
|
|
17
|
+
propsByBlockId.set(block.id, block.props);
|
|
18
|
+
}
|
|
19
|
+
const runtimeMap = yDoc.getMap("runtime");
|
|
20
|
+
const nodes = compiled.order.filter((nodeId) => compiled.nodes[nodeId]).map((nodeId) => {
|
|
21
|
+
const node = compiled.nodes[nodeId];
|
|
22
|
+
const props = propsByBlockId.get(node.blockId) ?? {};
|
|
23
|
+
const rawRuntime = runtimeMap.get(node.blockId);
|
|
24
|
+
const runtime = rawRuntime && typeof rawRuntime === "object" ? rawRuntime : {};
|
|
25
|
+
return {
|
|
26
|
+
nodeId,
|
|
27
|
+
blockId: node.blockId,
|
|
28
|
+
can: node.can,
|
|
29
|
+
with: node.with,
|
|
30
|
+
title: props.title ?? node.title,
|
|
31
|
+
description: props.description ?? node.description,
|
|
32
|
+
props,
|
|
33
|
+
runtime
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
meta: compiled.meta,
|
|
38
|
+
order: compiled.order,
|
|
39
|
+
edges: compiled.edges,
|
|
40
|
+
blockIndex: compiled.blockIndex,
|
|
41
|
+
nodes
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function setBlockProps(yDoc, blockId, partial) {
|
|
45
|
+
const fragment = yDoc.getXmlFragment("document");
|
|
46
|
+
const existing = readBlocksFromFragment(fragment).find((b) => b.id === blockId);
|
|
47
|
+
if (!existing) return false;
|
|
48
|
+
const merged = { ...existing.props, ...partial };
|
|
49
|
+
let ok = false;
|
|
50
|
+
yDoc.transact(() => {
|
|
51
|
+
ok = replaceBlockInFragment(fragment, { id: blockId, type: existing.type, props: merged });
|
|
52
|
+
const nodeId = findNodeIdForBlock(yDoc, blockId);
|
|
53
|
+
if (nodeId) {
|
|
54
|
+
const node = yDoc.getMap("qi.flow.nodes").get(nodeId);
|
|
55
|
+
if (node instanceof Y.Map) {
|
|
56
|
+
if ("title" in partial) node.set("title", merged.title ?? "");
|
|
57
|
+
if ("description" in partial) node.set("description", merged.description ?? "");
|
|
58
|
+
if ("authorisedActors" in partial || "parentCapability" in partial) {
|
|
59
|
+
const actor = actorFromProps(merged);
|
|
60
|
+
if (actor) node.set("actor", actor);
|
|
61
|
+
else node.delete("actor");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return ok;
|
|
67
|
+
}
|
|
68
|
+
function removeFlowNode(yDoc, nodeId) {
|
|
69
|
+
const doc = readFlowDocument(yDoc);
|
|
70
|
+
if (!doc) return { ok: false, referencedBy: [] };
|
|
71
|
+
const target = doc.nodes.find((n) => n.nodeId === nodeId);
|
|
72
|
+
if (!target) return { ok: false, referencedBy: [] };
|
|
73
|
+
const referencedBy = doc.nodes.filter((n) => n.nodeId !== nodeId && nodeReferences(n, nodeId, target.blockId)).map((n) => n.nodeId);
|
|
74
|
+
if (referencedBy.length > 0) return { ok: false, referencedBy };
|
|
75
|
+
const blockId = target.blockId;
|
|
76
|
+
yDoc.transact(() => {
|
|
77
|
+
removeBlockFromFragment(yDoc.getXmlFragment("document"), blockId);
|
|
78
|
+
yDoc.getMap("qi.flow.nodes").delete(nodeId);
|
|
79
|
+
yDoc.getMap("qi.flow.blockIndex").delete(nodeId);
|
|
80
|
+
const order = yDoc.getArray("qi.flow.order");
|
|
81
|
+
const idx = order.toArray().indexOf(nodeId);
|
|
82
|
+
if (idx >= 0) order.delete(idx, 1);
|
|
83
|
+
const edges = yDoc.getMap("qi.flow.edges");
|
|
84
|
+
for (const key of [...edges.keys()]) {
|
|
85
|
+
const e = edges.get(key);
|
|
86
|
+
if (e instanceof Y.Map && (e.get("source") === nodeId || e.get("target") === nodeId)) edges.delete(key);
|
|
87
|
+
}
|
|
88
|
+
yDoc.getMap("runtime").delete(blockId);
|
|
89
|
+
});
|
|
90
|
+
return { ok: true };
|
|
91
|
+
}
|
|
92
|
+
function reorderFlowNodes(yDoc, order) {
|
|
93
|
+
const orderArr = yDoc.getArray("qi.flow.order");
|
|
94
|
+
const current = orderArr.toArray();
|
|
95
|
+
if (order.length !== current.length) return false;
|
|
96
|
+
if (new Set(order).size !== order.length) return false;
|
|
97
|
+
const currentSet = new Set(current);
|
|
98
|
+
if (!order.every((id) => currentSet.has(id))) return false;
|
|
99
|
+
const blockIndex = yDoc.getMap("qi.flow.blockIndex");
|
|
100
|
+
const fragment = yDoc.getXmlFragment("document");
|
|
101
|
+
yDoc.transact(() => {
|
|
102
|
+
orderArr.delete(0, orderArr.length);
|
|
103
|
+
orderArr.push(order);
|
|
104
|
+
if (!fragmentHasContentBlocks(fragment)) {
|
|
105
|
+
const blocks = readBlocksFromFragment(fragment);
|
|
106
|
+
const byId = new Map(blocks.map((b) => [b.id, b]));
|
|
107
|
+
const orderedIds = order.map((nid) => blockIndex.get(nid)).filter((id) => !!id);
|
|
108
|
+
const ordered = orderedIds.map((id) => byId.get(id)).filter((b) => !!b);
|
|
109
|
+
const extras = blocks.filter((b) => !orderedIds.includes(b.id));
|
|
110
|
+
removeAllFlowBlocks(fragment);
|
|
111
|
+
writeCompiledBlocksToFragment(fragment, [...ordered, ...extras]);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
function updateNodeRuntime(yDoc, blockId, partial) {
|
|
117
|
+
const runtimeMap = yDoc.getMap("runtime");
|
|
118
|
+
const prev = runtimeMap.get(blockId);
|
|
119
|
+
const base = prev && typeof prev === "object" ? prev : {};
|
|
120
|
+
runtimeMap.set(blockId, { ...base, ...partial });
|
|
121
|
+
}
|
|
122
|
+
function resetStepRuntime(yDoc, blockId) {
|
|
123
|
+
updateNodeRuntime(yDoc, blockId, { state: "idle", error: void 0, output: {} });
|
|
124
|
+
}
|
|
125
|
+
function setFormAnswers(yDoc, blockId, answers) {
|
|
126
|
+
const runtimeMap = yDoc.getMap("runtime");
|
|
127
|
+
const prev = runtimeMap.get(blockId);
|
|
128
|
+
const base = prev && typeof prev === "object" ? prev : {};
|
|
129
|
+
const output = base.output && typeof base.output === "object" ? base.output : {};
|
|
130
|
+
const form = output.form && typeof output.form === "object" ? output.form : {};
|
|
131
|
+
runtimeMap.set(blockId, { ...base, output: { ...output, form: { ...form, answers: JSON.stringify(answers) } } });
|
|
132
|
+
}
|
|
133
|
+
function safeParseJson(value, fallback) {
|
|
134
|
+
if (typeof value !== "string" || value.length === 0) return fallback;
|
|
135
|
+
try {
|
|
136
|
+
return JSON.parse(value);
|
|
137
|
+
} catch {
|
|
138
|
+
return fallback;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function findNodeIdForBlock(yDoc, blockId) {
|
|
142
|
+
const blockIndex = yDoc.getMap("qi.flow.blockIndex");
|
|
143
|
+
for (const [nodeId, bId] of blockIndex.entries()) {
|
|
144
|
+
if (bId === blockId) return nodeId;
|
|
145
|
+
}
|
|
146
|
+
return void 0;
|
|
147
|
+
}
|
|
148
|
+
function actorFromProps(props) {
|
|
149
|
+
const authorisedActors = safeParseJson(props.authorisedActors, void 0);
|
|
150
|
+
const parentCapability = props.parentCapability && props.parentCapability.length > 0 ? props.parentCapability : void 0;
|
|
151
|
+
const hasActors = Array.isArray(authorisedActors) && authorisedActors.length > 0;
|
|
152
|
+
if (!hasActors && !parentCapability) return void 0;
|
|
153
|
+
const actor = {};
|
|
154
|
+
if (hasActors) actor.authorisedActors = authorisedActors;
|
|
155
|
+
if (parentCapability) actor.parentCapability = parentCapability;
|
|
156
|
+
return actor;
|
|
157
|
+
}
|
|
158
|
+
function nodeReferences(node, nodeId, blockId) {
|
|
159
|
+
const trigger = safeParseJson(node.props.trigger, void 0);
|
|
160
|
+
if (trigger?.sourceBlockId === nodeId) return true;
|
|
161
|
+
if (Array.isArray(trigger?.sources) && trigger.sources.some((s) => s?.sourceBlockId === nodeId)) return true;
|
|
162
|
+
const cond = safeParseJson(node.props.conditions, void 0);
|
|
163
|
+
if (Array.isArray(cond?.conditions) && cond.conditions.some((c) => c?.sourceBlockId === blockId)) return true;
|
|
164
|
+
const inputs = typeof node.props.inputs === "string" ? node.props.inputs : "";
|
|
165
|
+
if (inputs.includes(`${nodeId}.output`)) return true;
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
function fragmentHasContentBlocks(fragment) {
|
|
169
|
+
if (fragment.length === 0) return false;
|
|
170
|
+
const root = fragment.get(0);
|
|
171
|
+
if (!(root instanceof Y.XmlElement) || root.nodeName !== "blockGroup") return false;
|
|
172
|
+
for (let i = 0; i < root.length; i++) {
|
|
173
|
+
const container = root.get(i);
|
|
174
|
+
if (!(container instanceof Y.XmlElement)) continue;
|
|
175
|
+
const content = container.get(0);
|
|
176
|
+
if (content instanceof Y.XmlElement && content.length > 0) return true;
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export {
|
|
182
|
+
readFlowDocument,
|
|
183
|
+
setBlockProps,
|
|
184
|
+
removeFlowNode,
|
|
185
|
+
reorderFlowNodes,
|
|
186
|
+
updateNodeRuntime,
|
|
187
|
+
resetStepRuntime,
|
|
188
|
+
setFormAnswers
|
|
189
|
+
};
|
|
190
|
+
//# sourceMappingURL=chunk-JNR73I6T.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/lib/flowCompiler/authoring.ts"],"sourcesContent":["import * as Y from 'yjs';\nimport type { Doc as YDoc } from 'yjs';\nimport type { ActorConstraint, CompiledBlock, CompiledEdge, CompiledFlow } from '../../types/baseUcan';\nimport type { FlowNodeRuntimeState } from '../../types/authorization';\nimport { readCompiledFlowFromYDoc } from './readFlow';\nimport { readBlocksFromFragment, replaceBlockInFragment, removeBlockFromFragment, removeAllFlowBlocks, writeCompiledBlocksToFragment } from './documentFragment';\n\n/**\n * A single flow node as read from a live Y.Doc, assembled from all three sources:\n * structure (`qi.flow.*`), per-block `props` (the `document` fragment), and per-block\n * `runtime` (the `runtime` map). `props` and `runtime` are what the graph map cannot provide.\n */\nexport interface FlowDocumentNode {\n nodeId: string;\n blockId: string;\n can: string;\n with: string;\n title: string;\n description: string;\n /** Authoritative per-block props, recovered from the document fragment. */\n props: Record<string, string>;\n /** Per-block runtime; `{}` for a fresh/never-run node (e.g. a template). */\n runtime: FlowNodeRuntimeState;\n}\n\nexport interface FlowDocumentRead {\n meta: CompiledFlow['meta'];\n order: string[];\n edges: CompiledEdge[];\n blockIndex: Record<string, string>;\n nodes: FlowDocumentNode[];\n}\n\n// ─── Read ─────────────────────────────────────────────────────────────────────\n\n/**\n * Read a flow document **losslessly** from a headless Y.Doc, in one call.\n *\n * Why this exists: `readCompiledFlowFromYDoc` returns nodes with **empty `props`** (the\n * `qi.flow.nodes` map omits props — they live only in the `document` fragment), and\n * `decompileToBaseUcanFlow` is lossy for the same reason. `readFlowDocument` merges the three\n * sources so a consumer (e.g. an authoring agent) sees the *true* current flow:\n *\n * - structure ← `readCompiledFlowFromYDoc` (nodes, order, edges, `can`/`with`)\n * - per-block props ← `readBlocksFromFragment` (inputs/conditions/trigger/ttl/icon/…)\n * - per-block runtime ← the `runtime` Y.Map (state/output/error/…)\n *\n * Fragment props are authoritative for the denormalized fields (`title`/`description`); the\n * node-map copy is used only as a fallback when the fragment didn't persist them.\n *\n * Returns `null` when the doc has no flow at all (mirrors `readCompiledFlowFromYDoc`).\n */\nexport function readFlowDocument(yDoc: YDoc): FlowDocumentRead | null {\n const compiled = readCompiledFlowFromYDoc(yDoc);\n if (!compiled) return null;\n\n const propsByBlockId = new Map<string, Record<string, string>>();\n for (const block of readBlocksFromFragment(yDoc.getXmlFragment('document'))) {\n propsByBlockId.set(block.id, block.props);\n }\n\n const runtimeMap = yDoc.getMap('runtime');\n\n const nodes: FlowDocumentNode[] = compiled.order\n .filter((nodeId) => compiled.nodes[nodeId])\n .map((nodeId) => {\n const node = compiled.nodes[nodeId];\n const props = propsByBlockId.get(node.blockId) ?? {};\n const rawRuntime = runtimeMap.get(node.blockId);\n const runtime: FlowNodeRuntimeState = rawRuntime && typeof rawRuntime === 'object' ? (rawRuntime as FlowNodeRuntimeState) : {};\n\n return {\n nodeId,\n blockId: node.blockId,\n can: node.can,\n with: node.with,\n title: props.title ?? node.title,\n description: props.description ?? node.description,\n props,\n runtime,\n };\n });\n\n return {\n meta: compiled.meta,\n order: compiled.order,\n edges: compiled.edges,\n blockIndex: compiled.blockIndex,\n nodes,\n };\n}\n\n// ─── Per-block config writes (template authoring — surgical, no recompile) ─────\n\n/**\n * Edit one block's config props in place, in the `document` fragment. Surgical: it touches\n * only the target block (siblings untouched), does **not** recompile, and does **not** touch\n * the `runtime` map. Pass `''` for a prop to clear it (the writer drops empty values).\n *\n * Keeps the denormalized node-map fields in sync — `title`/`description` and the `actor`\n * object (derived from `authorisedActors`/`parentCapability`) live in BOTH the fragment and\n * `qi.flow.nodes`, so a fragment-only write would desync structural readers.\n *\n * Returns `false` when no block with `blockId` exists.\n */\nexport function setBlockProps(yDoc: YDoc, blockId: string, partial: Record<string, string>): boolean {\n const fragment = yDoc.getXmlFragment('document');\n const existing = readBlocksFromFragment(fragment).find((b) => b.id === blockId);\n if (!existing) return false;\n\n const merged: Record<string, string> = { ...existing.props, ...partial };\n\n let ok = false;\n yDoc.transact(() => {\n ok = replaceBlockInFragment(fragment, { id: blockId, type: existing.type, props: merged });\n\n const nodeId = findNodeIdForBlock(yDoc, blockId);\n if (nodeId) {\n const node = yDoc.getMap('qi.flow.nodes').get(nodeId);\n if (node instanceof Y.Map) {\n if ('title' in partial) node.set('title', merged.title ?? '');\n if ('description' in partial) node.set('description', merged.description ?? '');\n if ('authorisedActors' in partial || 'parentCapability' in partial) {\n const actor = actorFromProps(merged);\n if (actor) node.set('actor', actor);\n else node.delete('actor');\n }\n }\n }\n });\n\n return ok;\n}\n\n/**\n * Remove one step from the flow document — fragment block + `qi.flow.*` entries + its\n * `runtime` entry + any edges touching it — in one transaction. Siblings untouched.\n *\n * Guards against orphaning references: if another node's trigger, condition, or a\n * `{{nodeId.output.*}}` input ref points at this node, removal is refused and the referring\n * node ids are returned so the caller can surface them.\n */\nexport function removeFlowNode(yDoc: YDoc, nodeId: string): { ok: true } | { ok: false; referencedBy: string[] } {\n const doc = readFlowDocument(yDoc);\n if (!doc) return { ok: false, referencedBy: [] };\n\n const target = doc.nodes.find((n) => n.nodeId === nodeId);\n if (!target) return { ok: false, referencedBy: [] };\n\n const referencedBy = doc.nodes.filter((n) => n.nodeId !== nodeId && nodeReferences(n, nodeId, target.blockId)).map((n) => n.nodeId);\n if (referencedBy.length > 0) return { ok: false, referencedBy };\n\n const blockId = target.blockId;\n yDoc.transact(() => {\n removeBlockFromFragment(yDoc.getXmlFragment('document'), blockId);\n yDoc.getMap('qi.flow.nodes').delete(nodeId);\n yDoc.getMap('qi.flow.blockIndex').delete(nodeId);\n\n const order = yDoc.getArray<string>('qi.flow.order');\n const idx = order.toArray().indexOf(nodeId);\n if (idx >= 0) order.delete(idx, 1);\n\n const edges = yDoc.getMap('qi.flow.edges');\n for (const key of [...edges.keys()]) {\n const e = edges.get(key);\n if (e instanceof Y.Map && (e.get('source') === nodeId || e.get('target') === nodeId)) edges.delete(key);\n }\n\n yDoc.getMap('runtime').delete(blockId);\n });\n\n return { ok: true };\n}\n\n/**\n * Reorder the flow's steps. Always rewrites the logical order (`qi.flow.order`). Also\n * reorders the visual `document` fragment to match — but only when every block is an\n * attr-only compiled block; if the doc contains inline prose, the fragment is left untouched\n * (recreating it would lose content) and only the logical order changes.\n *\n * `order` must be a permutation of the current `qi.flow.order` (same ids, no dups); returns\n * `false` otherwise.\n */\nexport function reorderFlowNodes(yDoc: YDoc, order: string[]): boolean {\n const orderArr = yDoc.getArray<string>('qi.flow.order');\n const current = orderArr.toArray();\n if (order.length !== current.length) return false;\n if (new Set(order).size !== order.length) return false;\n const currentSet = new Set(current);\n if (!order.every((id) => currentSet.has(id))) return false;\n\n const blockIndex = yDoc.getMap('qi.flow.blockIndex');\n const fragment = yDoc.getXmlFragment('document');\n\n yDoc.transact(() => {\n orderArr.delete(0, orderArr.length);\n orderArr.push(order);\n\n if (!fragmentHasContentBlocks(fragment)) {\n const blocks = readBlocksFromFragment(fragment);\n const byId = new Map(blocks.map((b) => [b.id, b] as const));\n const orderedIds = order.map((nid) => blockIndex.get(nid) as string | undefined).filter((id): id is string => !!id);\n const ordered = orderedIds.map((id) => byId.get(id)).filter((b): b is CompiledBlock => !!b);\n const extras = blocks.filter((b) => !orderedIds.includes(b.id));\n removeAllFlowBlocks(fragment);\n writeCompiledBlocksToFragment(fragment, [...ordered, ...extras]);\n }\n });\n\n return true;\n}\n\n// ─── Runtime writes (copilot on a running flow — benign, non-executing) ────────\n\n/** Merge a partial into a node's runtime entry — the headless twin of the React `updateRuntime`. */\nexport function updateNodeRuntime(yDoc: YDoc, blockId: string, partial: Partial<FlowNodeRuntimeState>): void {\n const runtimeMap = yDoc.getMap('runtime');\n const prev = runtimeMap.get(blockId);\n const base: FlowNodeRuntimeState = prev && typeof prev === 'object' ? (prev as FlowNodeRuntimeState) : {};\n runtimeMap.set(blockId, { ...base, ...partial });\n}\n\n/**\n * Clear a failed step back to idle so the user can cleanly re-run it. The headless twin of\n * the editor's \"Reset\" recovery affordance — benign and non-executing.\n */\nexport function resetStepRuntime(yDoc: YDoc, blockId: string): void {\n updateNodeRuntime(yDoc, blockId, { state: 'idle', error: undefined, output: {} });\n}\n\n/**\n * Pre-fill a (live) form step's answers at `runtime.output.form.answers` (a JSON string,\n * matching `FormPanel`). Merges into existing `output`; **never** sets `state:'completed'` —\n * submission stays the user's action.\n */\nexport function setFormAnswers(yDoc: YDoc, blockId: string, answers: Record<string, unknown>): void {\n const runtimeMap = yDoc.getMap('runtime');\n const prev = runtimeMap.get(blockId);\n const base: FlowNodeRuntimeState = prev && typeof prev === 'object' ? (prev as FlowNodeRuntimeState) : {};\n const output: Record<string, any> = base.output && typeof base.output === 'object' ? base.output : {};\n const form: Record<string, any> = output.form && typeof output.form === 'object' ? output.form : {};\n runtimeMap.set(blockId, { ...base, output: { ...output, form: { ...form, answers: JSON.stringify(answers) } } });\n}\n\n// ─── Internal helpers ──────────────────────────────────────────────────────────\n\nfunction safeParseJson<T>(value: unknown, fallback: T): T {\n if (typeof value !== 'string' || value.length === 0) return fallback;\n try {\n return JSON.parse(value) as T;\n } catch {\n return fallback;\n }\n}\n\nfunction findNodeIdForBlock(yDoc: YDoc, blockId: string): string | undefined {\n const blockIndex = yDoc.getMap('qi.flow.blockIndex');\n for (const [nodeId, bId] of blockIndex.entries()) {\n if (bId === blockId) return nodeId;\n }\n return undefined;\n}\n\nfunction actorFromProps(props: Record<string, string>): ActorConstraint | undefined {\n const authorisedActors = safeParseJson<string[] | undefined>(props.authorisedActors, undefined);\n const parentCapability = props.parentCapability && props.parentCapability.length > 0 ? props.parentCapability : undefined;\n const hasActors = Array.isArray(authorisedActors) && authorisedActors.length > 0;\n if (!hasActors && !parentCapability) return undefined;\n const actor: ActorConstraint = {};\n if (hasActors) actor.authorisedActors = authorisedActors as string[];\n if (parentCapability) actor.parentCapability = parentCapability;\n return actor;\n}\n\nfunction nodeReferences(node: FlowDocumentNode, nodeId: string, blockId: string): boolean {\n const trigger = safeParseJson<{ sourceBlockId?: string; sources?: Array<{ sourceBlockId?: string }> } | undefined>(node.props.trigger, undefined);\n if (trigger?.sourceBlockId === nodeId) return true;\n if (Array.isArray(trigger?.sources) && trigger.sources.some((s) => s?.sourceBlockId === nodeId)) return true;\n\n const cond = safeParseJson<{ conditions?: Array<{ sourceBlockId?: string }> } | undefined>(node.props.conditions, undefined);\n if (Array.isArray(cond?.conditions) && cond.conditions.some((c) => c?.sourceBlockId === blockId)) return true;\n\n const inputs = typeof node.props.inputs === 'string' ? node.props.inputs : '';\n if (inputs.includes(`${nodeId}.output`)) return true;\n\n return false;\n}\n\nfunction fragmentHasContentBlocks(fragment: Y.XmlFragment): boolean {\n if (fragment.length === 0) return false;\n const root = fragment.get(0);\n if (!(root instanceof Y.XmlElement) || root.nodeName !== 'blockGroup') return false;\n for (let i = 0; i < root.length; i++) {\n const container = root.get(i);\n if (!(container instanceof Y.XmlElement)) continue;\n const content = container.get(0);\n if (content instanceof Y.XmlElement && content.length > 0) return true; // inline children = prose\n }\n return false;\n}\n"],"mappings":"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","names":[]}
|