@ixo/editor 6.22.0 → 6.23.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.
@@ -3,30 +3,33 @@ import {
3
3
  compileBlockProps,
4
4
  createYMapFromNode,
5
5
  getAction,
6
+ readActionState,
6
7
  readBlocksFromFragment,
7
8
  readCompiledFlowFromYDoc,
8
9
  removeAllFlowBlocks,
9
10
  removeBlockFromFragment,
10
11
  replaceBlockInFragment,
12
+ resolveRunIdForExecution,
13
+ resolveRunIdForRead,
11
14
  swapBlocksInFragment,
15
+ writeActionState,
12
16
  writeCompiledBlocksToFragment
13
- } from "./chunk-2WSXLAX5.js";
17
+ } from "./chunk-VFYF2B5E.js";
14
18
 
15
19
  // src/core/lib/flowCompiler/authoring.ts
16
20
  import * as Y from "yjs";
17
- function readFlowDocument(yDoc) {
21
+ function readFlowDocument(yDoc, runId) {
18
22
  const compiled = readCompiledFlowFromYDoc(yDoc);
19
23
  if (!compiled) return null;
20
24
  const propsByBlockId = /* @__PURE__ */ new Map();
21
25
  for (const block of readBlocksFromFragment(yDoc.getXmlFragment("document"))) {
22
26
  propsByBlockId.set(block.id, block.props);
23
27
  }
24
- const runtimeMap = yDoc.getMap("runtime");
28
+ const resolvedRunId = resolveRunIdForRead(yDoc, runId);
25
29
  const nodes = compiled.order.filter((nodeId) => compiled.nodes[nodeId]).map((nodeId) => {
26
30
  const node = compiled.nodes[nodeId];
27
31
  const props = propsByBlockId.get(node.blockId) ?? {};
28
- const rawRuntime = runtimeMap.get(node.blockId);
29
- const runtime = rawRuntime && typeof rawRuntime === "object" ? rawRuntime : {};
32
+ const runtime = resolvedRunId ? readActionState(yDoc, resolvedRunId, node.blockId) : {};
30
33
  return {
31
34
  nodeId,
32
35
  blockId: node.blockId,
@@ -106,8 +109,8 @@ function setBlockProps(yDoc, blockId, partial) {
106
109
  });
107
110
  return ok;
108
111
  }
109
- function removeFlowNode(yDoc, nodeId) {
110
- const doc = readFlowDocument(yDoc);
112
+ function removeFlowNode(yDoc, nodeId, runId) {
113
+ const doc = readFlowDocument(yDoc, resolveRunIdForRead(yDoc, runId));
111
114
  if (!doc) return { ok: false, referencedBy: [] };
112
115
  const target = doc.nodes.find((n) => n.nodeId === nodeId);
113
116
  if (!target) return { ok: false, referencedBy: [] };
@@ -126,7 +129,6 @@ function removeFlowNode(yDoc, nodeId) {
126
129
  const e = edges.get(key);
127
130
  if (e instanceof Y.Map && (e.get("source") === nodeId || e.get("target") === nodeId)) edges.delete(key);
128
131
  }
129
- yDoc.getMap("runtime").delete(blockId);
130
132
  });
131
133
  return { ok: true };
132
134
  }
@@ -181,22 +183,18 @@ function swapFlowBlocks(yDoc, blockIdA, blockIdB) {
181
183
  });
182
184
  return ok;
183
185
  }
184
- function updateNodeRuntime(yDoc, blockId, partial) {
185
- const runtimeMap = yDoc.getMap("runtime");
186
- const prev = runtimeMap.get(blockId);
187
- const base = prev && typeof prev === "object" ? prev : {};
188
- runtimeMap.set(blockId, { ...base, ...partial });
186
+ function updateNodeRuntime(yDoc, blockId, partial, runId) {
187
+ writeActionState(yDoc, resolveRunIdForExecution(yDoc, runId), blockId, partial);
189
188
  }
190
- function resetStepRuntime(yDoc, blockId) {
191
- updateNodeRuntime(yDoc, blockId, { state: "idle", error: void 0, output: {} });
189
+ function resetStepRuntime(yDoc, blockId, runId) {
190
+ updateNodeRuntime(yDoc, blockId, { state: "idle", error: void 0, output: {} }, runId);
192
191
  }
193
- function setFormAnswers(yDoc, blockId, answers) {
194
- const runtimeMap = yDoc.getMap("runtime");
195
- const prev = runtimeMap.get(blockId);
196
- const base = prev && typeof prev === "object" ? prev : {};
192
+ function setFormAnswers(yDoc, blockId, answers, runId) {
193
+ const resolvedRunId = resolveRunIdForExecution(yDoc, runId);
194
+ const base = readActionState(yDoc, resolvedRunId, blockId);
197
195
  const output = base.output && typeof base.output === "object" ? base.output : {};
198
196
  const form = output.form && typeof output.form === "object" ? output.form : {};
199
- runtimeMap.set(blockId, { ...base, output: { ...output, form: { ...form, answers: JSON.stringify(answers) } } });
197
+ writeActionState(yDoc, resolvedRunId, blockId, { output: { ...output, form: { ...form, answers: JSON.stringify(answers) } } });
200
198
  }
201
199
  function safeParseJson(value, fallback) {
202
200
  if (typeof value !== "string" || value.length === 0) return fallback;
@@ -246,6 +244,115 @@ function fragmentHasContentBlocks(fragment) {
246
244
  return false;
247
245
  }
248
246
 
247
+ // src/core/lib/flowCompiler/participants.ts
248
+ import * as Y2 from "yjs";
249
+ var FLOW_PARTICIPANTS_MAP_KEY = "qi.flow.participants";
250
+ function readFlowParticipants(yDoc) {
251
+ const participants = [];
252
+ getParticipantsMap(yDoc).forEach((value) => {
253
+ const participant = toParticipant(value);
254
+ if (participant) participants.push(participant);
255
+ });
256
+ return participants.sort((a, b) => {
257
+ const aAt = a.addedAt ?? Number.POSITIVE_INFINITY;
258
+ const bAt = b.addedAt ?? Number.POSITIVE_INFINITY;
259
+ if (aAt !== bAt) return aAt < bAt ? -1 : 1;
260
+ return compareUserIds(a.userId, b.userId);
261
+ });
262
+ }
263
+ function upsertFlowParticipant(yDoc, participant) {
264
+ const userId = participant.userId;
265
+ if (typeof userId !== "string" || userId.length === 0) return;
266
+ yDoc.transact(() => {
267
+ const entry = ensureEntry(getParticipantsMap(yDoc), userId);
268
+ entry.set("userId", userId);
269
+ entry.set("powerLevel", toPowerLevel(participant.powerLevel));
270
+ mergeOptionalString(entry, "displayName", participant.displayName);
271
+ mergeOptionalString(entry, "avatarUrl", participant.avatarUrl);
272
+ mergeRequirements(entry, participant.requires);
273
+ const addedAt = toTimestamp(entry.get("addedAt")) ?? toTimestamp(participant.addedAt);
274
+ if (addedAt !== void 0) entry.set("addedAt", addedAt);
275
+ });
276
+ }
277
+ function removeFlowParticipant(yDoc, userId) {
278
+ yDoc.transact(() => {
279
+ const map = getParticipantsMap(yDoc);
280
+ if (map.has(userId)) map.delete(userId);
281
+ });
282
+ }
283
+ function setFlowParticipantPowerLevel(yDoc, userId, powerLevel) {
284
+ yDoc.transact(() => {
285
+ const entry = getParticipantsMap(yDoc).get(userId);
286
+ if (entry instanceof Y2.Map) entry.set("powerLevel", toPowerLevel(powerLevel));
287
+ });
288
+ }
289
+ function setFlowParticipantRequirements(yDoc, userId, requires) {
290
+ yDoc.transact(() => {
291
+ const entry = getParticipantsMap(yDoc).get(userId);
292
+ if (entry instanceof Y2.Map) mergeRequirements(entry, requires ?? []);
293
+ });
294
+ }
295
+ function getParticipantsMap(yDoc) {
296
+ return yDoc.getMap(FLOW_PARTICIPANTS_MAP_KEY);
297
+ }
298
+ function ensureEntry(map, userId) {
299
+ const existing = map.get(userId);
300
+ if (existing instanceof Y2.Map) return existing;
301
+ const created = new Y2.Map();
302
+ map.set(userId, created);
303
+ return created;
304
+ }
305
+ function toParticipant(value) {
306
+ if (!(value instanceof Y2.Map)) return void 0;
307
+ const userId = value.get("userId");
308
+ if (typeof userId !== "string" || userId.length === 0) return void 0;
309
+ const participant = { userId, powerLevel: toPowerLevel(value.get("powerLevel")) };
310
+ const displayName = toNonEmptyString(value.get("displayName"));
311
+ if (displayName !== void 0) participant.displayName = displayName;
312
+ const avatarUrl = toNonEmptyString(value.get("avatarUrl"));
313
+ if (avatarUrl !== void 0) participant.avatarUrl = avatarUrl;
314
+ const requires = toRequirements(value.get("requires"));
315
+ if (requires.length > 0) participant.requires = requires;
316
+ const addedAt = toTimestamp(value.get("addedAt"));
317
+ if (addedAt !== void 0) participant.addedAt = addedAt;
318
+ return participant;
319
+ }
320
+ function toPowerLevel(value) {
321
+ const numeric = typeof value === "string" ? Number(value) : value;
322
+ return typeof numeric === "number" && Number.isFinite(numeric) ? Math.trunc(numeric) : 0;
323
+ }
324
+ function toTimestamp(value) {
325
+ const numeric = typeof value === "string" ? Number(value) : value;
326
+ return typeof numeric === "number" && Number.isFinite(numeric) ? Math.trunc(numeric) : void 0;
327
+ }
328
+ function toNonEmptyString(value) {
329
+ return typeof value === "string" && value.length > 0 ? value : void 0;
330
+ }
331
+ function toRequirements(value) {
332
+ if (!Array.isArray(value)) return [];
333
+ const requires = [];
334
+ for (const entry of value) {
335
+ if (typeof entry !== "string" || entry.length === 0) continue;
336
+ if (!requires.includes(entry)) requires.push(entry);
337
+ }
338
+ return requires;
339
+ }
340
+ function mergeOptionalString(entry, key, value) {
341
+ if (value === void 0) return;
342
+ if (value.length === 0) entry.delete(key);
343
+ else entry.set(key, value);
344
+ }
345
+ function mergeRequirements(entry, value) {
346
+ if (value === void 0) return;
347
+ const requires = toRequirements(value);
348
+ if (requires.length === 0) entry.delete("requires");
349
+ else entry.set("requires", requires);
350
+ }
351
+ function compareUserIds(a, b) {
352
+ if (a === b) return 0;
353
+ return a < b ? -1 : 1;
354
+ }
355
+
249
356
  export {
250
357
  readFlowDocument,
251
358
  addFlowNode,
@@ -255,6 +362,12 @@ export {
255
362
  swapFlowBlocks,
256
363
  updateNodeRuntime,
257
364
  resetStepRuntime,
258
- setFormAnswers
365
+ setFormAnswers,
366
+ FLOW_PARTICIPANTS_MAP_KEY,
367
+ readFlowParticipants,
368
+ upsertFlowParticipant,
369
+ removeFlowParticipant,
370
+ setFlowParticipantPowerLevel,
371
+ setFlowParticipantRequirements
259
372
  };
260
- //# sourceMappingURL=chunk-EO2K4IDP.js.map
373
+ //# sourceMappingURL=chunk-LBFFAKSN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/lib/flowCompiler/authoring.ts","../src/core/lib/flowCompiler/participants.ts"],"sourcesContent":["import * as Y from 'yjs';\nimport type { Doc as YDoc } from 'yjs';\nimport type { ActorConstraint, CompiledBlock, CompiledEdge, CompiledFlow, CompiledFlowNode, FlowCapability } from '../../types/baseUcan';\nimport type { FlowNodeRuntimeState } from '../../types/authorization';\nimport { getAction } from '../actionRegistry/registry';\nimport { readCompiledFlowFromYDoc } from './readFlow';\nimport { compileBlockProps, COMPILED_BLOCK_TYPE } from './blockMapping';\nimport { createYMapFromNode } from './hydrate';\nimport { readActionState, resolveRunIdForExecution, resolveRunIdForRead, writeActionState } from '../flowEngine/runs';\nimport {\n readBlocksFromFragment,\n replaceBlockInFragment,\n removeBlockFromFragment,\n removeAllFlowBlocks,\n writeCompiledBlocksToFragment,\n swapBlocksInFragment,\n} 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 run's `actions` map, resolved against the flat `runtime` mirror\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, runId?: string): 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 resolvedRunId = resolveRunIdForRead(yDoc, runId);\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 // Pure read — `readActionState` never writes, so this stays safe on a\n // read-only viewer and on a flow with no session at all.\n const runtime: FlowNodeRuntimeState = resolvedRunId ? readActionState(yDoc, resolvedRunId, node.blockId) : {};\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// ─── Add (template authoring — the inverse of removeFlowNode) ─────────────────\n\nexport interface AddFlowNodeOptions {\n /** Registry action type, e.g. `'qi/form.submit'`. Must exist in the registry. */\n type: string;\n /** Insert into the logical order right after this node id; appended to the end if omitted. */\n afterNodeId?: string;\n /** Optional starting title (defaults to the action's `can` / type). */\n title?: string;\n /** Optional extra block props merged over the compiled defaults. */\n props?: Record<string, string>;\n}\n\n/**\n * Add a step to the flow document — the inverse of `removeFlowNode`. Inserts an\n * attr-only `action` block into the `document` fragment and registers the\n * matching `qi.flow.*` structure (`nodes`, `blockIndex`, `order`) in one\n * transaction, mirroring exactly what the compiler's `hydrate` writes for a\n * single node. No recompile, no runtime entry (a template node is never-run).\n *\n * Returns the new ids, or `null` if `type` is not a known registry action.\n */\nexport function addFlowNode(yDoc: YDoc, opts: AddFlowNodeOptions): { nodeId: string; blockId: string } | null {\n const action = getAction(opts.type);\n if (!action) return null;\n\n const nodeId = `node_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;\n const blockId = `flow_block_${nodeId}`;\n\n const flowId = (yDoc.getMap('qi.flow.meta').get('flowId') as string | undefined) || '';\n const withUri = flowId ? `ixo:flow:${flowId}:${nodeId}` : `ixo:flow:${nodeId}`;\n const can = action.can ?? '';\n const title = opts.title || can || action.type;\n\n const cap: FlowCapability = { id: nodeId, can, with: withUri, title, nb: {} };\n const props: Record<string, string> = { ...compileBlockProps(cap, action.type), triggerMode: 'manual', ...(opts.props ?? {}) };\n\n const node: CompiledFlowNode = {\n id: nodeId,\n blockId,\n can,\n with: withUri,\n registryType: action.type,\n title,\n description: '',\n props,\n };\n\n yDoc.transact(() => {\n writeCompiledBlocksToFragment(yDoc.getXmlFragment('document'), [{ id: blockId, type: COMPILED_BLOCK_TYPE, props }]);\n yDoc.getMap('qi.flow.nodes').set(nodeId, createYMapFromNode(node));\n yDoc.getMap('qi.flow.blockIndex').set(nodeId, blockId);\n\n const order = yDoc.getArray<string>('qi.flow.order');\n if (opts.afterNodeId) {\n const idx = order.toArray().indexOf(opts.afterNodeId);\n if (idx >= 0) order.insert(idx + 1, [nodeId]);\n else order.push([nodeId]);\n } else {\n order.push([nodeId]);\n }\n });\n\n return { nodeId, blockId };\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, runId?: string): { ok: true } | { ok: false; referencedBy: string[] } {\n const doc = readFlowDocument(yDoc, resolveRunIdForRead(yDoc, runId));\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 // Do not delete run state here. Definition edits must leave frozen\n // manifests and historical action facts inspectable.\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/**\n * Swap two step blocks by document position — the move-up/move-down primitive\n * for template authoring. Reorders the visual `document` fragment (so the change\n * is what the author sees), and keeps `qi.flow.order` consistent when BOTH\n * blocks are graph-registered nodes. Works for slash-menu (\"legacy\") blocks too,\n * since it operates on document position rather than the graph.\n *\n * Returns `false` if either block id is missing.\n */\nexport function swapFlowBlocks(yDoc: YDoc, blockIdA: string, blockIdB: string): boolean {\n const fragment = yDoc.getXmlFragment('document');\n let ok = false;\n yDoc.transact(() => {\n ok = swapBlocksInFragment(fragment, blockIdA, blockIdB);\n if (!ok) return;\n\n // Mirror the swap in the logical order for graph-registered nodes.\n const blockIndex = yDoc.getMap<string>('qi.flow.blockIndex');\n let nodeA: string | undefined;\n let nodeB: string | undefined;\n for (const [nodeId, bId] of blockIndex.entries()) {\n if (bId === blockIdA) nodeA = nodeId;\n else if (bId === blockIdB) nodeB = nodeId;\n }\n if (nodeA && nodeB) {\n const order = yDoc.getArray<string>('qi.flow.order');\n const arr = order.toArray();\n const ia = arr.indexOf(nodeA);\n const ib = arr.indexOf(nodeB);\n if (ia >= 0 && ib >= 0) {\n [arr[ia], arr[ib]] = [arr[ib], arr[ia]];\n order.delete(0, order.length);\n order.push(arr);\n }\n }\n });\n return ok;\n}\n\n// ─── Runtime writes (copilot on a running flow — benign, non-executing) ────────\n\n/**\n * Merge a partial into a node's action state — the headless twin of the React `updateRuntime`.\n *\n * Goes through `writeActionState`, so the run entry and the flat mirror are\n * written in one transaction from one resolved `prev`. A flat-only write here\n * would be invisible to run-scoped readers the moment they land.\n */\nexport function updateNodeRuntime(yDoc: YDoc, blockId: string, partial: Partial<FlowNodeRuntimeState>, runId?: string): void {\n writeActionState(yDoc, resolveRunIdForExecution(yDoc, runId), blockId, 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 *\n * Resetting only the flat map is the failure this exists to avoid: a surviving\n * `completed`/`failed` run entry beats a fresh `idle` flat entry under\n * `resolveActionState` rule (a), so \"Reset\" would appear to do nothing at all\n * once readers go run-first.\n */\nexport function resetStepRuntime(yDoc: YDoc, blockId: string, runId?: string): void {\n updateNodeRuntime(yDoc, blockId, { state: 'idle', error: undefined, output: {} }, runId);\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>, runId?: string): void {\n const resolvedRunId = resolveRunIdForExecution(yDoc, runId);\n const base = readActionState(yDoc, resolvedRunId, blockId);\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 writeActionState(yDoc, resolvedRunId, blockId, { 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 // The compiler serializes trigger source references as block ids; docs\n // compiled before that remap carry node ids. Guard against both.\n const trigger = safeParseJson<{ sourceBlockId?: string; sources?: Array<{ sourceBlockId?: string }> } | undefined>(node.props.trigger, undefined);\n if (trigger?.sourceBlockId === nodeId || trigger?.sourceBlockId === blockId) return true;\n if (Array.isArray(trigger?.sources) && trigger.sources.some((s) => s?.sourceBlockId === nodeId || s?.sourceBlockId === blockId)) 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","import * as Y from 'yjs';\nimport type { Doc as YDoc, Map as YMap } from 'yjs';\n\n/**\n * Top-level Y.Doc map holding the flow's **human** participant roster, keyed by\n * Matrix user id. Deliberately not called \"agents\": everything under\n * `lib/flowAgent/*` means an AI/oracle actor, and the two must not be conflated.\n *\n * This is template *configuration*, not execution state — the roster records who\n * a flow is meant to be run with, at what Matrix power level, and which of the\n * flow's connections (`connections.ts`) each of them needs access to, so that\n * instantiating a template into a room can invite exactly those users and ask\n * for exactly the right grants. It is therefore NOT cleared by\n * `clearRuntimeForTemplateClone` (`flowEngine/runtime.ts`), which only clears\n * observation/execution maps; a clone must carry the roster forward or the\n * instantiated room comes up empty.\n */\nexport const FLOW_PARTICIPANTS_MAP_KEY = 'qi.flow.participants';\n\nexport type FlowParticipant = {\n /** Matrix user id, e.g. `'@alice:matrix.example.org'`. */\n userId: string;\n /** Matrix power level; integer, `0` when unknown. */\n powerLevel: number;\n displayName?: string;\n /** `mxc://` url. */\n avatarUrl?: string;\n /**\n * Toolkit keys (`FlowConnection.toolkit`) this participant needs access to.\n * Absent when the participant needs none.\n */\n requires?: string[];\n /** Epoch ms. Supplied by the caller — this module never calls `Date.now()`. */\n addedAt?: number;\n};\n\n/**\n * Read the participant roster.\n *\n * Normalizes defensively rather than trusting the map: this is read against a\n * live, replicated doc, so an entry can be observed mid-sync, written by an older\n * client, or malformed outright. Anything that is not a `Y.Map` carrying a\n * non-empty `userId` is skipped, and a read never throws.\n *\n * Order is stable across peers — `addedAt` ascending with unstamped entries last,\n * tie-broken by `userId` — so a rendered roster does not reshuffle on every sync.\n */\nexport function readFlowParticipants(yDoc: YDoc): FlowParticipant[] {\n const participants: FlowParticipant[] = [];\n getParticipantsMap(yDoc).forEach((value) => {\n const participant = toParticipant(value);\n if (participant) participants.push(participant);\n });\n\n return participants.sort((a, b) => {\n const aAt = a.addedAt ?? Number.POSITIVE_INFINITY;\n const bAt = b.addedAt ?? Number.POSITIVE_INFINITY;\n if (aAt !== bAt) return aAt < bAt ? -1 : 1;\n return compareUserIds(a.userId, b.userId);\n });\n}\n\n/**\n * Add a participant, or merge into the existing entry for the same `userId`.\n *\n * `addedAt` is write-once: an existing stamp is preserved so a later edit\n * (a power-level bump, a display-name refresh) cannot reorder the roster.\n * Optional string fields are merged — omit one to leave it as it is, pass `''`\n * to clear it; `requires` follows the same rule with `[]` as the clearing value.\n */\nexport function upsertFlowParticipant(yDoc: YDoc, participant: FlowParticipant): void {\n const userId = participant.userId;\n if (typeof userId !== 'string' || userId.length === 0) return;\n\n yDoc.transact(() => {\n const entry = ensureEntry(getParticipantsMap(yDoc), userId);\n entry.set('userId', userId);\n entry.set('powerLevel', toPowerLevel(participant.powerLevel));\n mergeOptionalString(entry, 'displayName', participant.displayName);\n mergeOptionalString(entry, 'avatarUrl', participant.avatarUrl);\n mergeRequirements(entry, participant.requires);\n\n const addedAt = toTimestamp(entry.get('addedAt')) ?? toTimestamp(participant.addedAt);\n if (addedAt !== undefined) entry.set('addedAt', addedAt);\n });\n}\n\n/** Remove a participant. No-op when the roster has no entry for `userId`. */\nexport function removeFlowParticipant(yDoc: YDoc, userId: string): void {\n yDoc.transact(() => {\n const map = getParticipantsMap(yDoc);\n if (map.has(userId)) map.delete(userId);\n });\n}\n\n/**\n * Set an existing participant's power level. No-op when the participant is not on\n * the roster — a power level alone carries no identity, so creating an entry from\n * one would invent a participant nobody added.\n */\nexport function setFlowParticipantPowerLevel(yDoc: YDoc, userId: string, powerLevel: number): void {\n yDoc.transact(() => {\n const entry = getParticipantsMap(yDoc).get(userId);\n if (entry instanceof Y.Map) entry.set('powerLevel', toPowerLevel(powerLevel));\n });\n}\n\n/**\n * Replace the connections an existing participant needs access to. Pass `[]` to\n * clear them. No-op when the participant is not on the roster, for the same\n * reason as {@link setFlowParticipantPowerLevel}.\n */\nexport function setFlowParticipantRequirements(yDoc: YDoc, userId: string, requires: string[]): void {\n yDoc.transact(() => {\n const entry = getParticipantsMap(yDoc).get(userId);\n if (entry instanceof Y.Map) mergeRequirements(entry, requires ?? []);\n });\n}\n\n// ─── Internal helpers ──────────────────────────────────────────────────────────\n\nfunction getParticipantsMap(yDoc: YDoc): YMap<unknown> {\n return yDoc.getMap<unknown>(FLOW_PARTICIPANTS_MAP_KEY);\n}\n\n/** The entry for `userId`, replacing any malformed (non-`Y.Map`) value in place. */\nfunction ensureEntry(map: YMap<unknown>, userId: string): YMap<unknown> {\n const existing = map.get(userId);\n if (existing instanceof Y.Map) return existing;\n const created = new Y.Map<unknown>();\n map.set(userId, created);\n return created;\n}\n\nfunction toParticipant(value: unknown): FlowParticipant | undefined {\n if (!(value instanceof Y.Map)) return undefined;\n\n const userId = value.get('userId');\n if (typeof userId !== 'string' || userId.length === 0) return undefined;\n\n const participant: FlowParticipant = { userId, powerLevel: toPowerLevel(value.get('powerLevel')) };\n\n const displayName = toNonEmptyString(value.get('displayName'));\n if (displayName !== undefined) participant.displayName = displayName;\n\n const avatarUrl = toNonEmptyString(value.get('avatarUrl'));\n if (avatarUrl !== undefined) participant.avatarUrl = avatarUrl;\n\n const requires = toRequirements(value.get('requires'));\n if (requires.length > 0) participant.requires = requires;\n\n const addedAt = toTimestamp(value.get('addedAt'));\n if (addedAt !== undefined) participant.addedAt = addedAt;\n\n return participant;\n}\n\n/** Absent, non-numeric, or NaN power levels read as `0` — Matrix's default. */\nfunction toPowerLevel(value: unknown): number {\n const numeric = typeof value === 'string' ? Number(value) : value;\n return typeof numeric === 'number' && Number.isFinite(numeric) ? Math.trunc(numeric) : 0;\n}\n\nfunction toTimestamp(value: unknown): number | undefined {\n const numeric = typeof value === 'string' ? Number(value) : value;\n return typeof numeric === 'number' && Number.isFinite(numeric) ? Math.trunc(numeric) : undefined;\n}\n\nfunction toNonEmptyString(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/** Non-empty strings only, de-duplicated, in the order they were written. */\nfunction toRequirements(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n const requires: string[] = [];\n for (const entry of value) {\n if (typeof entry !== 'string' || entry.length === 0) continue;\n if (!requires.includes(entry)) requires.push(entry);\n }\n return requires;\n}\n\nfunction mergeOptionalString(entry: YMap<unknown>, key: string, value: string | undefined): void {\n if (value === undefined) return;\n if (value.length === 0) entry.delete(key);\n else entry.set(key, value);\n}\n\n/** Omit to leave the requirements as they are, pass `[]` to clear them. */\nfunction mergeRequirements(entry: YMap<unknown>, value: string[] | undefined): void {\n if (value === undefined) return;\n const requires = toRequirements(value);\n if (requires.length === 0) entry.delete('requires');\n else entry.set('requires', requires);\n}\n\nfunction compareUserIds(a: string, b: string): number {\n if (a === b) return 0;\n return a < b ? -1 : 1;\n}\n"],"mappings":"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","names":["Y"]}