@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.
@@ -1,11 +1,154 @@
1
1
  import * as _blocknote_core from '@blocknote/core';
2
2
  import { BlockSchemaFromSpecs, InlineContentSchema, StyleSchema, BlockNoteEditor, PartialBlock } from '@blocknote/core';
3
- import * as React from 'react';
4
- import React__default from 'react';
5
3
  import { MatrixClient } from 'matrix-js-sdk';
4
+ import * as Y from 'yjs';
6
5
  import { Map, Doc, Array as Array$1 } from 'yjs';
6
+ import * as React from 'react';
7
+ import React__default from 'react';
7
8
  import { Delegation } from '@ixo/ucan';
8
9
 
10
+ type DID = string;
11
+ type ClaimCollectionURI = string;
12
+ type EvaluationStatus = 'pending' | 'approved' | 'rejected';
13
+ interface LinkedClaim {
14
+ collectionId: ClaimCollectionURI;
15
+ }
16
+ interface FlowNodeAuthzExtension {
17
+ linkedClaim?: LinkedClaim;
18
+ }
19
+ /**
20
+ * Canonical persisted block lifecycle shared by browser and headless writers.
21
+ *
22
+ * `pending`, `retry_scheduled`, and `awaiting_human` are orchestration resting
23
+ * states written by Flow Manager. They must remain part of this union: the
24
+ * Editor waist validates persisted states, and treating them as unknown would
25
+ * erase them during read/merge and re-arm work that is already queued.
26
+ */
27
+ type NodeState = 'idle' | 'pending' | 'running' | 'retry_scheduled' | 'awaiting_human' | 'completed' | 'failed' | 'cancelled' | 'awaiting_readback' | 'needs_verification';
28
+ type ReadBackTerminalState = 'pending' | 'completed' | 'failed';
29
+ interface ActionReadBackMetadata {
30
+ kind: string;
31
+ status?: ReadBackTerminalState;
32
+ correlationId?: string;
33
+ validationSource?: string;
34
+ requestedAt?: string;
35
+ lastCheckedAt?: string;
36
+ terminalAt?: string;
37
+ blockId?: string;
38
+ actionType?: string;
39
+ actorDid?: DID;
40
+ invocationCid?: string;
41
+ capabilityId?: string;
42
+ pendingInvocation?: {
43
+ id: string;
44
+ triggeringBlockId: string;
45
+ eventName: string;
46
+ sourceRunId?: string;
47
+ };
48
+ [key: string]: any;
49
+ }
50
+ /**
51
+ * One advisory report from a contracted helper oracle, landed by the flow
52
+ * manager under `runtime[blockId].serviceReports[serviceRole]`.
53
+ */
54
+ interface NodeServiceReport {
55
+ output: Record<string, unknown>;
56
+ oracleDid: string;
57
+ invocationId: string;
58
+ receivedAt: number;
59
+ }
60
+ interface FlowNodeRuntimeState {
61
+ state?: NodeState;
62
+ output?: Record<string, any>;
63
+ executedByDid?: DID;
64
+ executedAt?: number;
65
+ /** Monotonic attempt number within this session run. */
66
+ attempt?: number;
67
+ /** Stable id for the current/last action execution attempt. */
68
+ executionId?: string;
69
+ executionStartedAt?: number;
70
+ outputSequence?: number;
71
+ /** Matrix event id at the current head of this action's immutable history. */
72
+ lastEventId?: string;
73
+ /** Unix timestamp (ms) when the block first became enabled/activated */
74
+ enabledAt?: number;
75
+ /**
76
+ * Set when a human resolves a `needs_verification` block by confirming the
77
+ * side effect really happened (see NodeState). It moves the block to
78
+ * `completed` and tells `verifyCompletion` to trust it despite the missing
79
+ * declared proof field. Records who confirmed and when for the audit trail.
80
+ */
81
+ manuallyVerified?: boolean;
82
+ manuallyVerifiedByDid?: DID;
83
+ manuallyVerifiedAt?: number;
84
+ /** Metadata needed to reconcile an externally completed action later. */
85
+ readBack?: ActionReadBackMetadata;
86
+ /** Last explicit completion-contract reconciliation. */
87
+ reconciledAt?: number;
88
+ completionSource?: string;
89
+ invocations?: string[];
90
+ lastInvocationCid?: string;
91
+ assignments?: Array<{
92
+ actorDid: DID;
93
+ assignedByDid?: DID;
94
+ at: number;
95
+ status: 'assigned' | 'accepted' | 'declined';
96
+ }>;
97
+ commitments?: Array<{
98
+ actorDid: DID;
99
+ at: number;
100
+ expiresAt?: number;
101
+ }>;
102
+ proposals?: Array<{
103
+ id: string;
104
+ proposedByDid: DID;
105
+ proposedAt: number;
106
+ mode: 'inputs_patch' | 'output_patch';
107
+ patch: any;
108
+ rationale?: string;
109
+ status: 'open' | 'accepted' | 'rejected';
110
+ decidedByDid?: DID;
111
+ decidedAt?: number;
112
+ acceptanceInvocationCid?: string;
113
+ }>;
114
+ pendingPayload?: Record<string, unknown>;
115
+ error?: {
116
+ message: string;
117
+ code?: string;
118
+ at: number;
119
+ data?: any;
120
+ };
121
+ /**
122
+ * Generic per-block escape hatch for state that does not fit the typed
123
+ * lifecycle fields above and should survive browser refresh via Yjs.
124
+ */
125
+ cache?: Record<string, unknown>;
126
+ /** Per-instance user-typed values that need to survive reload (e.g. encrypted API keys
127
+ * the user entered into a form-style action block). Action blocks own the shape. */
128
+ userInputs?: Record<string, any>;
129
+ /**
130
+ * Advisory oracle reports written by the flow manager, keyed by service
131
+ * role (e.g. 'evaluation-report'). Service receipts are NOT execution
132
+ * results: they never touch the node's own state/output and are optional
133
+ * input to the human decision, not a blocker.
134
+ */
135
+ serviceReports?: Record<string, NodeServiceReport>;
136
+ claimId?: string;
137
+ submittedByDid?: DID;
138
+ evaluationStatus?: EvaluationStatus;
139
+ executionTimestamp?: number;
140
+ }
141
+ interface FlowNodeBase {
142
+ id: string;
143
+ type: string;
144
+ props: Record<string, any>;
145
+ activationCondition?: {
146
+ upstreamNodeId: string;
147
+ requiredStatus: EvaluationStatus;
148
+ };
149
+ }
150
+ type FlowNode = FlowNodeBase & FlowNodeAuthzExtension;
151
+
9
152
  type ProposalActionType = 'Spend' | 'UpdateMembers' | 'Stake' | 'Join' | 'AuthzExec' | 'AuthzGrant' | 'AuthzRevoke' | 'BurnNft' | 'Mint' | 'Execute' | 'Instantiate' | 'ManageSubDaos' | 'ManageCw721' | 'ManageCw20' | 'Migrate' | 'TransferNft' | 'UpdateAdmin' | 'UpdatePreProposeConfig' | 'UpdateVotingConfig' | 'GovernanceVote' | 'WithdrawTokenSwap' | 'UpdateInfo' | 'Custom' | 'ManageStorageItems' | 'ValidatorActions' | 'PerformTokenSwap' | 'DaoAdminExec' | 'StakeToGroup' | 'SendGroupToken' | 'AcceptToMarketplace' | 'CreateEntity';
10
153
  interface Member$1 {
11
154
  addr: string;
@@ -4891,129 +5034,6 @@ declare class MatrixMetadataManager {
4891
5034
  dispose(): void;
4892
5035
  }
4893
5036
 
4894
- type DID = string;
4895
- type ClaimCollectionURI = string;
4896
- type EvaluationStatus = 'pending' | 'approved' | 'rejected';
4897
- interface LinkedClaim {
4898
- collectionId: ClaimCollectionURI;
4899
- }
4900
- interface FlowNodeAuthzExtension {
4901
- linkedClaim?: LinkedClaim;
4902
- }
4903
- type NodeState = 'idle' | 'running' | 'completed' | 'failed' | 'cancelled' | 'awaiting_readback' | 'needs_verification';
4904
- type ReadBackTerminalState = 'pending' | 'completed' | 'failed';
4905
- interface ActionReadBackMetadata {
4906
- kind: string;
4907
- status?: ReadBackTerminalState;
4908
- correlationId?: string;
4909
- validationSource?: string;
4910
- requestedAt?: string;
4911
- lastCheckedAt?: string;
4912
- terminalAt?: string;
4913
- blockId?: string;
4914
- actionType?: string;
4915
- actorDid?: DID;
4916
- invocationCid?: string;
4917
- capabilityId?: string;
4918
- pendingInvocation?: {
4919
- id: string;
4920
- triggeringBlockId: string;
4921
- eventName: string;
4922
- sourceRunId?: string;
4923
- };
4924
- [key: string]: any;
4925
- }
4926
- /**
4927
- * One advisory report from a contracted helper oracle, landed by the flow
4928
- * manager under `runtime[blockId].serviceReports[serviceRole]`.
4929
- */
4930
- interface NodeServiceReport {
4931
- output: Record<string, unknown>;
4932
- oracleDid: string;
4933
- invocationId: string;
4934
- receivedAt: number;
4935
- }
4936
- interface FlowNodeRuntimeState {
4937
- state?: NodeState;
4938
- output?: Record<string, any>;
4939
- executedByDid?: DID;
4940
- executedAt?: number;
4941
- /** Unix timestamp (ms) when the block first became enabled/activated */
4942
- enabledAt?: number;
4943
- /**
4944
- * Set when a human resolves a `needs_verification` block by confirming the
4945
- * side effect really happened (see NodeState). It moves the block to
4946
- * `completed` and tells `verifyCompletion` to trust it despite the missing
4947
- * declared proof field. Records who confirmed and when for the audit trail.
4948
- */
4949
- manuallyVerified?: boolean;
4950
- manuallyVerifiedByDid?: DID;
4951
- manuallyVerifiedAt?: number;
4952
- /** Metadata needed to reconcile an externally completed action later. */
4953
- readBack?: ActionReadBackMetadata;
4954
- invocations?: string[];
4955
- lastInvocationCid?: string;
4956
- assignments?: Array<{
4957
- actorDid: DID;
4958
- assignedByDid?: DID;
4959
- at: number;
4960
- status: 'assigned' | 'accepted' | 'declined';
4961
- }>;
4962
- commitments?: Array<{
4963
- actorDid: DID;
4964
- at: number;
4965
- expiresAt?: number;
4966
- }>;
4967
- proposals?: Array<{
4968
- id: string;
4969
- proposedByDid: DID;
4970
- proposedAt: number;
4971
- mode: 'inputs_patch' | 'output_patch';
4972
- patch: any;
4973
- rationale?: string;
4974
- status: 'open' | 'accepted' | 'rejected';
4975
- decidedByDid?: DID;
4976
- decidedAt?: number;
4977
- acceptanceInvocationCid?: string;
4978
- }>;
4979
- pendingPayload?: Record<string, unknown>;
4980
- error?: {
4981
- message: string;
4982
- code?: string;
4983
- at: number;
4984
- data?: any;
4985
- };
4986
- /**
4987
- * Generic per-block escape hatch for state that does not fit the typed
4988
- * lifecycle fields above and should survive browser refresh via Yjs.
4989
- */
4990
- cache?: Record<string, unknown>;
4991
- /** Per-instance user-typed values that need to survive reload (e.g. encrypted API keys
4992
- * the user entered into a form-style action block). Action blocks own the shape. */
4993
- userInputs?: Record<string, any>;
4994
- /**
4995
- * Advisory oracle reports written by the flow manager, keyed by service
4996
- * role (e.g. 'evaluation-report'). Service receipts are NOT execution
4997
- * results: they never touch the node's own state/output and are optional
4998
- * input to the human decision, not a blocker.
4999
- */
5000
- serviceReports?: Record<string, NodeServiceReport>;
5001
- claimId?: string;
5002
- submittedByDid?: DID;
5003
- evaluationStatus?: EvaluationStatus;
5004
- executionTimestamp?: number;
5005
- }
5006
- interface FlowNodeBase {
5007
- id: string;
5008
- type: string;
5009
- props: Record<string, any>;
5010
- activationCondition?: {
5011
- upstreamNodeId: string;
5012
- requiredStatus: EvaluationStatus;
5013
- };
5014
- }
5015
- type FlowNode = FlowNodeBase & FlowNodeAuthzExtension;
5016
-
5017
5037
  /**
5018
5038
  * UCAN types for @ixo/ucan integration
5019
5039
  *
@@ -5080,6 +5100,14 @@ interface StoredInvocation {
5080
5100
  executedAt: number;
5081
5101
  /** Flow ID context */
5082
5102
  flowId: string;
5103
+ /**
5104
+ * Session run that produced this invocation.
5105
+ *
5106
+ * Optional for records written before multi-run storage. New execution
5107
+ * surfaces must populate it so audit/status queries cannot mix concurrent
5108
+ * runs of the same flow.
5109
+ */
5110
+ sessionRunId?: string;
5083
5111
  /** Block ID if block-level execution */
5084
5112
  blockId?: string;
5085
5113
  /** Execution result */
@@ -5430,7 +5458,7 @@ interface UcanService {
5430
5458
  getAllDelegations: () => StoredDelegation[];
5431
5459
  getRootDelegation: () => StoredDelegation | null;
5432
5460
  createAndValidateInvocation: (params: CreateInvocationParams, flowId: string, blockId?: string) => Promise<InvocationResult>;
5433
- executeWithInvocation: <T>(params: CreateInvocationParams, action: () => Promise<T>, flowId: string, blockId?: string) => Promise<ExecutionWithInvocationResult & {
5461
+ executeWithInvocation: <T>(params: CreateInvocationParams, action: () => Promise<T>, flowId: string, blockId?: string, sessionRunId?: string) => Promise<ExecutionWithInvocationResult & {
5434
5462
  actionResult?: T;
5435
5463
  }>;
5436
5464
  validateDelegationChain: (audienceDid: string, capability: UcanCapability) => Promise<DelegationChainValidationResult>;
@@ -5519,9 +5547,36 @@ interface IxoEditorType<BSchema extends IxoBlockSchema = IxoBlockSchema, ISchema
5519
5547
  _yFlow?: Array$1<any>;
5520
5548
  /**
5521
5549
  * Y.Map for runtime per-node state (claim status, timestamps, etc.)
5550
+ *
5551
+ * This is the pre-runs FLAT map, keyed by blockId. It is still a live write
5552
+ * target for already-deployed clients, so every run-scoped write mirrors into
5553
+ * it and every run-scoped read falls back to it
5554
+ * (`core/lib/flowEngine/runs.ts`). Prefer `readActionState` /
5555
+ * `writeActionState` over touching this handle directly.
5556
+ *
5557
+ * PHASE A COMPAT — REMOVAL TRIGGER: when `writeActionState` no longer mirrors
5558
+ * to the flat map (runs.ts compat register item 1).
5522
5559
  * @internal
5523
5560
  */
5524
5561
  _yRuntime?: Map<any>;
5562
+ /**
5563
+ * Y.Map of runs: `runId → Y.Map { meta, actions }`, where `actions` is a
5564
+ * `Y.Map<blockId, FlowNodeRuntimeState>` of PLAIN objects. Empty until an
5565
+ * actor starts a session or migrates a legacy flow — runs are never created
5566
+ * by opening a document or by writing to it.
5567
+ *
5568
+ * Containers are re-resolved from the doc on every access inside `runs.ts` —
5569
+ * never cache the nested `actions` map across a tick, because a losing
5570
+ * concurrent-create merge orphans the reference and writes vanish silently.
5571
+ * @internal
5572
+ */
5573
+ _yRuns?: Map<any>;
5574
+ /**
5575
+ * Y.Map of write-once terminal (closed/cancelled) latches per run. Phase B
5576
+ * writes it; Phase A only attaches it so the shape lands.
5577
+ * @internal
5578
+ */
5579
+ _yRunsTerminal?: Map<any>;
5525
5580
  /**
5526
5581
  * Y.Map for per-node semantic context records written by the flow manager
5527
5582
  * (keyed by block/node id, see NodeContextRecord)
@@ -5559,6 +5614,8 @@ interface IxoEditorType<BSchema extends IxoBlockSchema = IxoBlockSchema, ISchema
5559
5614
  * @internal
5560
5615
  */
5561
5616
  _yAgentLeases?: Map<any>;
5617
+ /** Host-provided Matrix run timeline. */
5618
+ _runEventLog?: RunEventAppender;
5562
5619
  /**
5563
5620
  * Y.Map for queued Xero invoice/payment work items.
5564
5621
  * @internal
@@ -5759,6 +5816,2434 @@ interface IxoBlockProps<TBlock = any> {
5759
5816
  block: TBlock;
5760
5817
  }
5761
5818
 
5819
+ interface FlowRuntimeStateManager {
5820
+ get: (nodeId: string) => FlowNodeRuntimeState;
5821
+ update: (nodeId: string, updates: Partial<FlowNodeRuntimeState>) => void;
5822
+ }
5823
+ /**
5824
+ * The small, public Y.Doc surface needed to clear execution state.
5825
+ *
5826
+ * Keeping this structural prevents a linked consumer with a compatible Yjs
5827
+ * minor version from inheriting this package's private Y.Doc type identity.
5828
+ * Template cleanup only needs map iteration/deletion and one transaction.
5829
+ */
5830
+ interface TemplateCloneDocument {
5831
+ getMap(name?: string): {
5832
+ forEach(callback: (value: unknown, key: string) => void): void;
5833
+ delete(key: string): void;
5834
+ };
5835
+ transact(callback: () => void): void;
5836
+ }
5837
+ /**
5838
+ * `FlowRuntimeStateManager` for an editor.
5839
+ *
5840
+ * IGNITION PHASE A: when a Y.Doc is reachable this delegates to the run-scoped
5841
+ * manager (`runs.ts#createRunScopedRuntimeManager`), so every `update()` made
5842
+ * through it dual-writes the run entry and the flat mirror in one transaction,
5843
+ * and every `get()` resolves the two through the freshness predicate. That is
5844
+ * what makes a *downgrade* — a reset, an unchecked box, a read-back proof
5845
+ * failure — visible on both sides; a flat-only downgrade can never be
5846
+ * materialised into the run and would strand the stale higher state forever
5847
+ * (§9.3 The adoption gate).
5848
+ *
5849
+ * The name is kept because it is public API (`src/index.ts`, `src/core/index.ts`).
5850
+ *
5851
+ * The two non-doc branches are unchanged on purpose: a duck-typed `_yRuntime`
5852
+ * (test stubs, mocks) still gets a plain map manager, and a handle-less editor
5853
+ * still gets the historical in-memory manager rather than a throw — narrowing
5854
+ * that contract is a separate, breaking change.
5855
+ */
5856
+ declare const createRuntimeStateManager: (editor?: IxoEditorType | null, runId?: string) => FlowRuntimeStateManager;
5857
+ /**
5858
+ * `FlowRuntimeStateManager` for a Y.Doc.
5859
+ *
5860
+ * IGNITION PHASE A: a thin alias for the run-scoped manager over the active
5861
+ * run. Kept as a named export because it is public API and both orchestrators
5862
+ * (flow-manager, flow-agent) import it.
5863
+ */
5864
+ declare const createYDocRuntimeManager: (yDoc: Doc, runId?: string) => FlowRuntimeStateManager;
5865
+ /**
5866
+ * Clears runtime, invocations, and pending invocations from a Y.Doc.
5867
+ * Used when cloning a flow as a template — the new document should
5868
+ * carry only configuration (intent), not execution history.
5869
+ *
5870
+ * The audit trail (which now also holds run records as `type: 'block.run'`
5871
+ * entries) and pending invocations are observation, not configuration —
5872
+ * both are cleared on template clone.
5873
+ *
5874
+ * `barrierState` belongs to the same class and was missing here: a partially
5875
+ * filled barrier (`block.event.all`) survived the clone, so a single source
5876
+ * firing in the clone could satisfy the barrier using entries emitted in the
5877
+ * *source* flow and queue an invocation whose merged payload mixes two flows.
5878
+ *
5879
+ * `dmNotificationState` is dedup bookkeeping about DMs that were sent for the
5880
+ * source flow's execution; carrying it into a clone suppresses the clone's
5881
+ * first legitimate notification for every block already notified upstream.
5882
+ *
5883
+ * `runs` and `runsTerminal` are where that same execution state now lives
5884
+ * (Ignition Phase A). Clearing the flat `runtime` map without clearing `runs`
5885
+ * would leave the clone pre-completed for every adopted block. Deleting the
5886
+ * outer run key is sufficient — the nested per-run maps go with it.
5887
+ *
5888
+ * `qi.flow.connectionBindings` names one workspace's connected accounts, so it
5889
+ * is cleared too: a clone that kept them would point at a Xero organisation its
5890
+ * own members hold no grant for, and would read as connected while every call
5891
+ * through it fails. The requirements themselves (`qi.flow.connections`) are
5892
+ * configuration and survive, exactly like the participant roster.
5893
+ */
5894
+ declare function clearRuntimeForTemplateClone(yDoc: TemplateCloneDocument): void;
5895
+
5896
+ /**
5897
+ * Run record stored in the audit trail as `type: 'block.run'`.
5898
+ *
5899
+ * Per Phase 0 #2 (eng review pass 2), run records are NOT a parallel
5900
+ * `_yRunHistory` structure — they ride on the existing `auditTrail` Y.Map
5901
+ * via `useAuditTrail.addEvent`. The shape below is what goes into the
5902
+ * audit trail event's `details` field.
5903
+ *
5904
+ * See `docs/flow-engine/events-and-triggers-plan.md` §3.4, §18, §19.
5905
+ */
5906
+ interface RunRecordDetails {
5907
+ /**
5908
+ * Stable identifier for **this execution**, deterministic from invocation
5909
+ * context (`run-<ts>-<rand>` / `readback-<ts>-<rand>`).
5910
+ *
5911
+ * D2 — **NOT the session run, and never renamed.** This is persisted data in
5912
+ * live rooms and it is the `sourceRunId` component of
5913
+ * `computePendingInvocationId`; renaming it forks that join and the same
5914
+ * logical event queues twice. New code calls this the *execution* id and
5915
+ * uses {@link RunRecordDetails.sessionRunId} for the session run.
5916
+ */
5917
+ runId: string;
5918
+ /**
5919
+ * The session run (`runs.ts`) this execution belonged to. Phase A writes it
5920
+ * additively and **nothing reads it** — it exists so Phase B's per-run
5921
+ * history attribution is free, and it deliberately does not participate in
5922
+ * `computePendingInvocationId` (moving the id space is Phase B, together with
5923
+ * `pendingInvocations` and `barrierState`).
5924
+ */
5925
+ sessionRunId?: string;
5926
+ /** Action's output. */
5927
+ output: Record<string, unknown>;
5928
+ /**
5929
+ * Events the action emitted on this run. Persisted as part of the run
5930
+ * record so the reconciliation loop can process them idempotently — even
5931
+ * across page refreshes and across multiple clients.
5932
+ */
5933
+ events: Array<{
5934
+ name: string;
5935
+ payload: Record<string, unknown>;
5936
+ }>;
5937
+ /** ISO timestamp when the action started. */
5938
+ startedAt: string;
5939
+ /** ISO timestamp when the action completed (success or failure). */
5940
+ completedAt: string;
5941
+ /** DID of the actor who signed the invocation that produced this run. */
5942
+ actorDid: string;
5943
+ /** UCAN invocation CID when execution produced one. */
5944
+ invocationCid?: string;
5945
+ /** Capability/proof CID used when no invocation CID was produced. */
5946
+ capabilityId?: string;
5947
+ /** Optional error if the run failed. */
5948
+ error?: {
5949
+ message: string;
5950
+ code?: string;
5951
+ };
5952
+ /** External read-back metadata associated with this run or reconciliation. */
5953
+ readBack?: Record<string, unknown>;
5954
+ /** True when this audit entry was written by external read-back reconciliation. */
5955
+ reconciled?: boolean;
5956
+ /**
5957
+ * If this run was triggered by a pending invocation (i.e. it's a listener
5958
+ * run), the id of that pending invocation. Used to dedup replays and trace
5959
+ * causality back through `triggeredBy`.
5960
+ */
5961
+ fromPendingInvocationId?: string;
5962
+ /**
5963
+ * If this run is a listener run, the (sourceBlockId, eventName) that
5964
+ * caused it. Used by the failure visibility surface to attribute failures
5965
+ * back to the source block (CP-1).
5966
+ */
5967
+ triggeredBy?: {
5968
+ sourceBlockId: string;
5969
+ eventName: string;
5970
+ };
5971
+ /** Source run id for listener runs, stored explicitly for failure lookups. */
5972
+ sourceRunId?: string;
5973
+ }
5974
+ declare const RUN_RECORD_AUDIT_TYPE = "block.run";
5975
+ /**
5976
+ * Pending invocation queued on a listener block.
5977
+ *
5978
+ * Stored in `_yPendingInvocations: Y.Map<blockId, Y.Map<id, PendingInvocation>>`.
5979
+ *
5980
+ * The id is deterministic — derived from
5981
+ * `(sourceBlockId, sourceRunId, listenerBlockId, eventName, eventIndex)` —
5982
+ * so the reconciliation loop can run idempotently from multiple clients
5983
+ * without producing duplicates.
5984
+ *
5985
+ * See `docs/flow-engine/events-and-triggers-plan.md` §3.4, §3.5.1, §18.
5986
+ */
5987
+ interface PendingInvocation {
5988
+ /** Deterministic id, see `computePendingInvocationId`. */
5989
+ id: string;
5990
+ /** Block that emitted the event. */
5991
+ triggeringBlockId: string;
5992
+ /** Run id of the triggering source run, used for the deterministic id. */
5993
+ sourceRunId: string;
5994
+ /** Session run that owns this queue entry. Required by Phase B writers. */
5995
+ sessionRunId?: string;
5996
+ /** Event name from the source action's vocabulary. */
5997
+ eventName: string;
5998
+ /** Event index within the source run's `events` array (a single run can emit multiple). */
5999
+ eventIndex: number;
6000
+ /**
6001
+ * The frozen event payload, captured by value at emission time. The
6002
+ * assignee invokes the listener against this payload, not against the
6003
+ * source block's current state. This is the property that makes the
6004
+ * Sally → Mike scenario produce 10 distinct emails even when Mike acts
6005
+ * on them all hours later.
6006
+ */
6007
+ payload: Record<string, unknown>;
6008
+ /**
6009
+ * Snapshots of `nodeId.output.*` ref values that the listener's inputs
6010
+ * reference, captured at queue time. Keyed by the full ref string.
6011
+ *
6012
+ * §3.5.1: ref snapshots are the load-bearing fix for the lag-time
6013
+ * overwrite scenario. If a listener references a non-trigger block's
6014
+ * output (e.g. `evaluateBlock.output.claimId`), that value is captured
6015
+ * here at queue time. Resolution at invocation time prefers the snapshot
6016
+ * over current state, so multiple queued invocations don't drift when
6017
+ * the source re-runs.
6018
+ */
6019
+ refSnapshots: Record<string, unknown>;
6020
+ /** DID of the assigned actor who must invoke this listener. Resolved from `props.assignment.assignedActor.did`. */
6021
+ assigneeDid: string;
6022
+ /** ISO timestamp when the source emission happened. */
6023
+ emittedAt: string;
6024
+ /** ISO timestamp after which this pending invocation is considered expired. Resolved from `FlowCapability.ttl` at queue time. */
6025
+ expiresAt: string;
6026
+ }
6027
+ /**
6028
+ * Compute a deterministic id for a pending invocation from its content.
6029
+ *
6030
+ * The same (sourceBlockId, sourceRunId, listenerBlockId, eventName,
6031
+ * eventIndex) tuple always produces the same id. This is the property that
6032
+ * makes the reconciliation loop idempotent — re-running it from a different
6033
+ * client, or after a page refresh, produces the same `Y.Map.set` operation
6034
+ * with the same key, which Yjs converges to a single entry.
6035
+ *
6036
+ * Implementation: simple deterministic string concatenation, hashed via a
6037
+ * 32-bit FNV-1a. The id is short and stable; collision risk within a single
6038
+ * flow is negligible because the inputs are scoped (block ids are unique
6039
+ * within a flow, run ids are unique within a block).
6040
+ */
6041
+ declare function computePendingInvocationId(args: {
6042
+ sourceBlockId: string;
6043
+ sourceRunId: string;
6044
+ listenerBlockId: string;
6045
+ eventName: string;
6046
+ eventIndex: number;
6047
+ sessionRunId?: string;
6048
+ }): string;
6049
+ /**
6050
+ * Walk an inputs object and collect every RuntimeRef of the form
6051
+ * `nodeId.output.fieldPath`. Returns a map of `{refString: resolvedValue}`
6052
+ * suitable for storing as `PendingInvocation.refSnapshots`.
6053
+ *
6054
+ * The walker mirrors `resolveRuntimeRefs` in `flowCompiler/resolveRefs.ts`
6055
+ * but reads instead of resolving — it captures the current value of each
6056
+ * ref so the listener can later resolve against the snapshot rather than
6057
+ * against current state.
6058
+ *
6059
+ * See `docs/flow-engine/events-and-triggers-plan.md` §3.5.1.
6060
+ */
6061
+ declare function snapshotInputRefs(inputs: unknown, getNodeOutput: (nodeId: string) => Record<string, unknown> | undefined): Record<string, unknown>;
6062
+ /**
6063
+ * Get the top-level pending invocations Y.Map from the editor's yDoc.
6064
+ * Lazily creates it if missing.
6065
+ *
6066
+ * Shape: `Y.Map<blockId, Y.Map<pendingInvocationId, PendingInvocation>>`.
6067
+ * The outer map is keyed by listener block id; the inner map is keyed by
6068
+ * deterministic pending invocation id (see `computePendingInvocationId`).
6069
+ */
6070
+ declare function getPendingInvocationsMap(yDoc: Y.Doc, sessionRunId?: string): Y.Map<Y.Map<unknown>>;
6071
+ /**
6072
+ * Count all pending invocations in one session run without materialising any
6073
+ * missing CRDT containers.
6074
+ */
6075
+ declare function countPendingInvocations(yDoc: Y.Doc, sessionRunId?: string): number;
6076
+ /**
6077
+ * Get the inner pending-invocations map for a specific listener block.
6078
+ * Lazily creates it if missing. Caller is responsible for being inside a
6079
+ * Yjs transaction if atomic creation matters.
6080
+ */
6081
+ declare function getOrCreateBlockPendingMap(yDoc: Y.Doc, blockId: string, sessionRunId?: string): Y.Map<unknown>;
6082
+ /**
6083
+ * Read all pending invocations for a block as plain JS objects.
6084
+ * Returns an array sorted by `emittedAt` ascending (oldest first).
6085
+ */
6086
+ declare function readPendingInvocations(yDoc: Y.Doc, blockId: string, sessionRunId?: string): PendingInvocation[];
6087
+ /**
6088
+ * Idempotently write a pending invocation under its deterministic id.
6089
+ *
6090
+ * Returns true if a new entry was created, false if the id already
6091
+ * existed (meaning another client or a previous reconciliation pass
6092
+ * already queued this invocation). This is the property that makes
6093
+ * `reconcilePendingInvocations` safe to run from multiple clients
6094
+ * simultaneously and across page refreshes — see plan §18.
6095
+ *
6096
+ * Wraps the write in a Yjs transaction so the existence check and the
6097
+ * subsequent set are atomic from the local client's perspective. Concurrent
6098
+ * clients each computing the same id will all converge to a single entry
6099
+ * because Y.Map.set with the same key is last-writer-wins on identical
6100
+ * content.
6101
+ */
6102
+ declare function queuePendingInvocation(yDoc: Y.Doc, listenerBlockId: string, invocation: PendingInvocation, sessionRunId?: string): boolean;
6103
+ /**
6104
+ * Remove a pending invocation by id. Used when the assignee completes the
6105
+ * invocation (transitioning to a `block.run` audit trail entry) or when
6106
+ * the expiration sweep marks it as expired.
6107
+ */
6108
+ declare function removePendingInvocation(yDoc: Y.Doc, listenerBlockId: string, pendingInvocationId: string, sessionRunId?: string): boolean;
6109
+ /**
6110
+ * Append a run record to the audit trail for a block. Run records are
6111
+ * stored as audit trail events with `type: 'block.run'` and the structured
6112
+ * data in `details`. Per Phase 0 #2 of eng review pass 2, this avoids
6113
+ * inventing a parallel `_yRunHistory` storage system.
6114
+ *
6115
+ * Y.Array.push from concurrent clients merges correctly — verified by the
6116
+ * existing `useAuditTrail` shipping in production.
6117
+ */
6118
+ declare function appendRunRecord(yDoc: Y.Doc, blockId: string, details: RunRecordDetails, userId: string): void;
6119
+ /**
6120
+ * Read all run records for a block from the audit trail. Filters audit
6121
+ * trail entries to only those with `type: 'block.run'`.
6122
+ */
6123
+ declare function readRunRecords(yDoc: Y.Doc, blockId: string, sessionRunId?: string): RunRecordDetails[];
6124
+ /**
6125
+ * A failed listener run, attributed to the source block emission that
6126
+ * triggered it. Used by the failure visibility surface (CP-1) on source
6127
+ * blocks: the source block can show "N listeners failed for your last run".
6128
+ */
6129
+ interface FailedListenerRun {
6130
+ /** Block id of the listener whose run failed. */
6131
+ listenerBlockId: string;
6132
+ /** The full RunRecordDetails of the failed listener invocation. */
6133
+ record: RunRecordDetails;
6134
+ }
6135
+ /**
6136
+ * Find all failed listener runs that were triggered by a specific source
6137
+ * block run. Walks every block's audit trail, filters to listener runs
6138
+ * triggered by (sourceBlockId, sourceRunId), and returns the ones with an
6139
+ * error set.
6140
+ *
6141
+ * Used by the source block UI to show a failure badge linked to a specific
6142
+ * run — if Sally evaluates 10 claims and 2 of Mike's emails fail, Sally
6143
+ * sees "2 failed listeners on claim-G" rather than discovering it days
6144
+ * later in the email service logs.
6145
+ */
6146
+ declare function findFailedListenersForSourceRun(yDoc: Y.Doc, sourceBlockId: string, sourceRunId: string, listenerBlockIds: string[]): FailedListenerRun[];
6147
+ /**
6148
+ * Replay a previously failed listener run by re-queueing a pending
6149
+ * invocation with the same content. Reuses the original frozen payload
6150
+ * and ref snapshots from the failed run record's audit trail entry, so the
6151
+ * replay sees exactly the same data the original invocation saw.
6152
+ *
6153
+ * CP-2 from the plan. Used by the replay button in the failure visibility
6154
+ * surface. Returns true if a new pending invocation was queued.
6155
+ *
6156
+ * Note: replay does NOT re-derive the deterministic id from the original
6157
+ * source emission, because the original pending invocation's id is already
6158
+ * present (or removed) in the pendingInvocations Y.Map. Instead, replay
6159
+ * generates a fresh id by appending a `:replay-N` suffix to the original.
6160
+ * This means the replay creates a NEW pending invocation that the assignee
6161
+ * can act on, separate from any history of the original.
6162
+ */
6163
+ declare function replayFailedListenerRun(yDoc: Y.Doc, failedRecord: RunRecordDetails, listenerBlockId: string, originalPayload: Record<string, unknown>, originalRefSnapshots: Record<string, unknown>, assigneeDid: string, sessionRunId?: string): boolean;
6164
+
6165
+ /**
6166
+ * The raw consumer handler bag (mantine `BlocknoteHandlers`), as visible to
6167
+ * action `run()` implementations via `ctx.handlers`. The real interface lives
6168
+ * in the mantine layer and cannot be imported here without a core→mantine
6169
+ * cycle, so this declares only the members actions actually call — loosely
6170
+ * typed, since the parameter shapes are owned by the consumer contract.
6171
+ *
6172
+ * There is deliberately NO index signature: calling an undeclared handler is a
6173
+ * compile error, so a renamed consumer handler surfaces here instead of
6174
+ * failing at runtime. Add the member when an action starts using a new
6175
+ * handler. Prefer `ctx.services.*` (the typed, adapted contract) over
6176
+ * `ctx.handlers` for new actions — this escape hatch exists for actions that
6177
+ * predate `buildServicesFromHandlers`.
6178
+ */
6179
+ interface ActionHandlers {
6180
+ askCompanion?: (prompt: string) => Promise<any>;
6181
+ vote?: (...args: any[]) => any;
6182
+ getPreProposalContractAddress?: (...args: any[]) => any;
6183
+ getGroupContractAddress?: (...args: any[]) => any;
6184
+ getProposalContractAddress?: (...args: any[]) => any;
6185
+ createProposal?: (...args: any[]) => any;
6186
+ getUserRoles?: (...args: any[]) => any;
6187
+ getClaimData?: (...args: any[]) => any;
6188
+ requestPin?: (...args: any[]) => any;
6189
+ signCredential?: (...args: any[]) => any;
6190
+ publicFileUpload?: (...args: any[]) => any;
6191
+ createDomain?: (...args: any[]) => any;
6192
+ createAddLinkedResourceMessage?: (...args: any[]) => any;
6193
+ executeTransaction?: (...args: any[]) => any;
6194
+ createGovernanceGroup?: (...args: any[]) => any;
6195
+ getEntityDid?: (...args: any[]) => any;
6196
+ getCurrentUser?: (...args: any[]) => any;
6197
+ createAddLinkedEntityMessage?: (...args: any[]) => any;
6198
+ sourceDomainSpaces?: (...args: any[]) => any;
6199
+ importProtocolTemplatesToSpace?: (...args: any[]) => any;
6200
+ integrations?: {
6201
+ executeTool?: (...args: any[]) => any;
6202
+ fetchCurrentState?: (...args: any[]) => any;
6203
+ getEntityDid?: (...args: any[]) => any;
6204
+ };
6205
+ }
6206
+ interface ActionContext {
6207
+ actorDid: string;
6208
+ flowId: string;
6209
+ /** Explicit session run; distinct from an individual action execution id. */
6210
+ sessionRunId?: string;
6211
+ nodeId: string;
6212
+ services: ActionServices;
6213
+ flowNode?: FlowNode;
6214
+ runtime?: FlowRuntimeStateManager;
6215
+ flowUri?: string;
6216
+ handlers?: ActionHandlers;
6217
+ editor?: IxoEditorType;
6218
+ /**
6219
+ * The flow document. Present on both execution paths — `editor` is undefined
6220
+ * headless, so an action that needs flow-level configuration (the connection
6221
+ * bindings, say) has to read it from here rather than from the editor.
6222
+ */
6223
+ yDoc?: Doc;
6224
+ pendingInvocation?: PendingInvocation;
6225
+ }
6226
+ /**
6227
+ * Lifecycle state of an IXO claims-module collection.
6228
+ *
6229
+ * Mirrors `ixo.claims.v1beta1.CollectionState` (the on-chain enum). Carried as
6230
+ * a numeric enum at this boundary so the consumer-side handler can map it
6231
+ * directly onto the SDK enum without a string lookup.
6232
+ *
6233
+ * - `OPEN` (0) — accepting claims/bids.
6234
+ * - `PAUSED` (1) — temporarily not accepting submissions.
6235
+ * - `CLOSED` (2) — permanently closed.
6236
+ */
6237
+ declare enum CollectionStateEnum {
6238
+ OPEN = 0,
6239
+ PAUSED = 1,
6240
+ CLOSED = 2
6241
+ }
6242
+ /**
6243
+ * A single coin amount. Mirrors `cosmos.base.v1beta1.Coin`. `amount` is the
6244
+ * integer base-denom amount carried as a string (no `Long`/`bigint` at this
6245
+ * boundary).
6246
+ */
6247
+ interface CollectionCoin {
6248
+ denom: string;
6249
+ amount: string;
6250
+ }
6251
+ /**
6252
+ * A CW20 token payment leg. Mirrors `ixo.claims.v1beta1.CW20Payment`.
6253
+ */
6254
+ interface CollectionCW20Payment {
6255
+ address: string;
6256
+ /** Integer amount carried as a string. */
6257
+ amount: string;
6258
+ }
6259
+ /**
6260
+ * A CW1155 contract payment leg. Mirrors `ixo.claims.v1beta1.Contract1155Payment`.
6261
+ */
6262
+ interface CollectionContract1155Payment {
6263
+ address: string;
6264
+ tokenId: string;
6265
+ /** Integer amount carried as a string. */
6266
+ amount: string;
6267
+ }
6268
+ /**
6269
+ * One payment leg of a collection (submission / evaluation / approval /
6270
+ * rejection). Mirrors `ixo.claims.v1beta1.Payment`.
6271
+ *
6272
+ * Optional/empty legs are represented by an empty `amount` array. The consumer
6273
+ * handler fills `account` with the collection admin address when creating.
6274
+ */
6275
+ interface CollectionPayment {
6276
+ /** Destination/charging account address. */
6277
+ account: string;
6278
+ /** Native-coin amounts. Empty when this leg charges nothing in native coin. */
6279
+ amount: CollectionCoin[];
6280
+ /** Optional CW20 payment legs. */
6281
+ cw20Payment?: CollectionCW20Payment[];
6282
+ /** Optional CW1155 contract payment. */
6283
+ contract_1155Payment?: CollectionContract1155Payment;
6284
+ /** Optional payment timeout in nanoseconds, carried as a string. */
6285
+ timeoutNs?: string;
6286
+ /** Whether this leg is paid by the oracle rather than the claimant. */
6287
+ isOraclePayment?: boolean;
6288
+ }
6289
+ /**
6290
+ * The four payment legs of a collection. Mirrors `ixo.claims.v1beta1.Payments`.
6291
+ */
6292
+ interface Payments {
6293
+ submission?: CollectionPayment;
6294
+ evaluation?: CollectionPayment;
6295
+ approval?: CollectionPayment;
6296
+ rejection?: CollectionPayment;
6297
+ }
6298
+ /**
6299
+ * Per-intent configuration for a collection. Mirrors the
6300
+ * `ixo.claims.v1beta1.CollectionIntentOptions` shape — controls whether/how
6301
+ * claimants can declare an intent before submitting.
6302
+ */
6303
+ interface CollectionIntentOptions {
6304
+ /** Whether intents are enabled on this collection. */
6305
+ allowed?: boolean;
6306
+ /** Optional intent timeout in nanoseconds, carried as a string. */
6307
+ timeoutNs?: string;
6308
+ /** Optional per-intent payment override. */
6309
+ payment?: CollectionPayment;
6310
+ }
6311
+ /**
6312
+ * Parameters for creating a collection (`MsgCreateCollection`).
6313
+ *
6314
+ * `entity` and `protocol` are template configuration; the consumer resolves the
6315
+ * `signer`/admin from its own wallet context, so it is not part of this
6316
+ * boundary. `quota` is carried as a string (`0` = unlimited).
6317
+ */
6318
+ interface CollectionCreateParams {
6319
+ /** Entity (deed) DID the collection belongs to. */
6320
+ entity: string;
6321
+ /** Protocol DID/id the collection follows. */
6322
+ protocol: string;
6323
+ /** Initial lifecycle state. Defaults to OPEN if omitted by the consumer. */
6324
+ state?: CollectionStateEnum;
6325
+ /** ISO-8601 start date. */
6326
+ startDate?: string;
6327
+ /** ISO-8601 end date. */
6328
+ endDate?: string;
6329
+ /** Max number of claims; `0` = unlimited. Carried as a string. */
6330
+ quota?: string;
6331
+ /** Payment configuration for the four claim legs. */
6332
+ payments?: Payments;
6333
+ /** Intent configuration. */
6334
+ intents?: CollectionIntentOptions;
6335
+ }
6336
+ /**
6337
+ * The full, canonical on-chain state of a collection, returned by every
6338
+ * `collection.*` operation (read or write) and stored verbatim as
6339
+ * `runtime.output`. It is never a delta — see IXO-2573: `output` always holds
6340
+ * the latest full on-chain collection state.
6341
+ *
6342
+ * Field names mirror `ixo.claims.v1beta1.Collection`. Numeric chain types
6343
+ * (`Long`/uint64) are carried as strings; `state` is the numeric enum.
6344
+ */
6345
+ interface CollectionState {
6346
+ /** Collection identifier (the chain-assigned id). */
6347
+ collectionId: string;
6348
+ /** Entity (deed) DID the collection belongs to. */
6349
+ entity: string;
6350
+ /** Protocol DID/id the collection follows. */
6351
+ protocol: string;
6352
+ /** Admin address authorised to mutate the collection. */
6353
+ admin?: string;
6354
+ /** Current lifecycle state. */
6355
+ state: CollectionStateEnum;
6356
+ /** ISO-8601 start date, if set. */
6357
+ startDate?: string;
6358
+ /** ISO-8601 end date, if set. */
6359
+ endDate?: string;
6360
+ /** Max number of claims; `0` = unlimited. Carried as a string. */
6361
+ quota: string;
6362
+ /** Number of claims submitted so far. Carried as a string. */
6363
+ count: string;
6364
+ /** Number of claims evaluated so far. Carried as a string. */
6365
+ evaluated?: string;
6366
+ /** Number of approved claims. Carried as a string. */
6367
+ approved?: string;
6368
+ /** Number of rejected claims. Carried as a string. */
6369
+ rejected?: string;
6370
+ /** Number of disputed claims. Carried as a string. */
6371
+ disputed?: string;
6372
+ /** Payment configuration for the four claim legs. */
6373
+ payments?: Payments;
6374
+ /** Intent configuration. */
6375
+ intents?: CollectionIntentOptions;
6376
+ }
6377
+ /**
6378
+ * Role a grantee holds on a claim collection. Drives which custom claims-module
6379
+ * authorization is granted: `submit` → `SubmitClaimAuthorization`,
6380
+ * `evaluate` → `EvaluateClaimAuthorization` (each carries `[]constraints`, one
6381
+ * per collection). See IXO-2586.
6382
+ */
6383
+ type CollectionUserRole = 'submit' | 'evaluate';
6384
+ /**
6385
+ * One per-collection authorization constraint held by a grantee for a role.
6386
+ * Carries the LIVE (decremented) limits as read back from chain — the revoke
6387
+ * read-modify-write must preserve these verbatim (IXO-2590), so re-granting
6388
+ * from a template would wrongly reset spent quota.
6389
+ */
6390
+ interface CollectionGrantee {
6391
+ /** Grantee bech32 address. */
6392
+ address: string;
6393
+ /** Optional resolved DID (display / audit). */
6394
+ did?: string;
6395
+ /** Role this grant confers. */
6396
+ role: CollectionUserRole;
6397
+ /** Remaining agent quota; `0` = unlimited. Carried as a string. */
6398
+ agentQuota?: string;
6399
+ /** Per-claim max amount cap (evaluate role). */
6400
+ maxAmount?: CollectionCoin[];
6401
+ /** Intent duration in nanoseconds, carried as a string. */
6402
+ intentDurationNs?: string;
6403
+ }
6404
+ /**
6405
+ * A member enumerated from a group account, used for grant fan-out. Mirrors the
6406
+ * `PODMember` shape produced by the `pod/memberMultiSelect` enumeration
6407
+ * (abstracts cw4 members / token-staking stakers / nft-staking / multisig
6408
+ * signers).
6409
+ */
6410
+ interface CollectionMember {
6411
+ address: string;
6412
+ did?: string;
6413
+ role?: string;
6414
+ votingPower?: number;
6415
+ }
6416
+ /**
6417
+ * DAO DAO classification of an address. On IXO both user accounts and CosmWasm
6418
+ * contracts share the `ixo1…` prefix, so classification is layered: bech32
6419
+ * byte-length heuristic → Wasm `ContractInfo` query → cw2 `{ "info": {} }`
6420
+ * smart query (IXO-2592).
6421
+ */
6422
+ interface AddressClassification {
6423
+ /** `user` = plain account; `contract` = CosmWasm contract / module account. */
6424
+ kind: 'user' | 'contract';
6425
+ /** Present when `kind === 'contract'` and cw2 info resolved a DAO DAO group type. */
6426
+ daodao?: {
6427
+ /** cw2 contract name family, e.g. `dao-dao-core`, `cw4-group`, `dao-voting-cw4`. */
6428
+ type: string;
6429
+ /** Whether the contract can itself exercise a granted authz (only dao-core can MsgExec). */
6430
+ canExerciseGrant: boolean;
6431
+ };
6432
+ }
6433
+ /**
6434
+ * Provenance/identity of a carbon batch (= a CARBON token group; the batch id
6435
+ * is the on-chain token id). `entityDid` + `adminAddress` identify the entity
6436
+ * admin account the batch was minted from — both are REQUIRED to construct a
6437
+ * harvest (the authz grant + exec transfer target that account). The host
6438
+ * `loadBatches` handler performs provenance recovery for transferred batches so
6439
+ * these are populated before the editor ever sees them. See the carbon-credit
6440
+ * technical doc §4–§5 (IXO-2675).
6441
+ */
6442
+ interface CarbonBatchRef {
6443
+ /** Token/batch id. */
6444
+ id: string;
6445
+ /** Minter entity DID. */
6446
+ entityDid: string;
6447
+ /** Entity admin account address (the FROM account for a harvest transfer). */
6448
+ adminAddress: string;
6449
+ /** Human-readable entity name, for display. */
6450
+ alsoKnownAs?: string;
6451
+ }
6452
+ /**
6453
+ * A harvestable batch: held on an entity admin account the user owns but not
6454
+ * yet pulled into their wallet. `claimable` = the admin-held amount that
6455
+ * becomes the user's on harvest.
6456
+ */
6457
+ interface CarbonHarvestableBatch extends CarbonBatchRef {
6458
+ /** Harvestable amount (admin-held; becomes user `amount` after harvest). */
6459
+ claimable: number;
6460
+ }
6461
+ /**
6462
+ * A retireable batch: credits the user already holds in their wallet and can
6463
+ * burn/offset. `entityDid` is best-effort (display/provenance) and not required
6464
+ * to retire — retirement is a single owner-signed message.
6465
+ */
6466
+ interface CarbonRetireableBatch {
6467
+ /** Token/batch id. */
6468
+ id: string;
6469
+ /** Amount available in the user's wallet to retire. */
6470
+ amount: number;
6471
+ /** Minter entity DID, when known. */
6472
+ entityDid?: string;
6473
+ /** Human-readable entity name, for display. */
6474
+ alsoKnownAs?: string;
6475
+ }
6476
+ interface HttpService {
6477
+ request: (params: {
6478
+ url: string;
6479
+ method: string;
6480
+ headers?: Record<string, string>;
6481
+ body?: any;
6482
+ }) => Promise<{
6483
+ status: number;
6484
+ headers: Record<string, string>;
6485
+ data: any;
6486
+ }>;
6487
+ }
6488
+ interface EmailService {
6489
+ send: (params: {
6490
+ to: string;
6491
+ subject: string;
6492
+ template: string;
6493
+ templateVersion?: string;
6494
+ variables?: Record<string, any>;
6495
+ cc?: string;
6496
+ bcc?: string;
6497
+ replyTo?: string;
6498
+ }) => Promise<{
6499
+ messageId: string;
6500
+ sentAt: string;
6501
+ }>;
6502
+ }
6503
+ interface NotifyService {
6504
+ send: (params: {
6505
+ channel: string;
6506
+ to: string[];
6507
+ cc?: string[];
6508
+ bcc?: string[];
6509
+ subject?: string;
6510
+ body?: string;
6511
+ bodyType?: 'text' | 'html';
6512
+ from?: string;
6513
+ replyTo?: string;
6514
+ }) => Promise<{
6515
+ messageId: string;
6516
+ sentAt: string;
6517
+ }>;
6518
+ }
6519
+ interface BidService {
6520
+ submitBid: (params: {
6521
+ collectionId: string;
6522
+ role: string;
6523
+ surveyAnswers: Record<string, any>;
6524
+ entityDid?: string;
6525
+ onBehalfOfAddress?: string;
6526
+ }) => Promise<any>;
6527
+ approveBid: (params: {
6528
+ bidId: string;
6529
+ collectionId: string;
6530
+ did: string;
6531
+ entityDid?: string;
6532
+ }) => Promise<any>;
6533
+ rejectBid: (params: {
6534
+ bidId: string;
6535
+ collectionId: string;
6536
+ did: string;
6537
+ reason: string;
6538
+ entityDid?: string;
6539
+ }) => Promise<any>;
6540
+ approveServiceAgentApplication: (params: {
6541
+ adminAddress: string;
6542
+ collectionId: string;
6543
+ agentQuota: number;
6544
+ deedDid: string;
6545
+ currentUserAddress: string;
6546
+ }) => Promise<void>;
6547
+ approveEvaluatorApplication: (params: {
6548
+ adminAddress: string;
6549
+ collectionId: string;
6550
+ deedDid: string;
6551
+ evaluatorAddress: string;
6552
+ agentQuota?: number;
6553
+ claimIds?: string[];
6554
+ maxAmounts?: Array<{
6555
+ denom: string;
6556
+ amount: string;
6557
+ }>;
6558
+ }) => Promise<void>;
6559
+ }
6560
+ interface ClaimService {
6561
+ requestPin: (config?: {
6562
+ title?: string;
6563
+ description?: string;
6564
+ submitText?: string;
6565
+ }) => Promise<string>;
6566
+ submitClaim: (params: {
6567
+ surveyData: any;
6568
+ deedDid: string;
6569
+ collectionId: string;
6570
+ adminAddress: string;
6571
+ pin: string;
6572
+ entityDid?: string;
6573
+ }) => Promise<{
6574
+ transactionHash: string;
6575
+ claimId: string;
6576
+ }>;
6577
+ evaluateClaim: (granteeAddress: string, did: string, payload: {
6578
+ claimId: string;
6579
+ collectionId: string;
6580
+ adminAddress: string;
6581
+ status?: number;
6582
+ verificationProof: string;
6583
+ amount?: {
6584
+ denom: string;
6585
+ amount: string;
6586
+ };
6587
+ }) => Promise<{
6588
+ code: number;
6589
+ transactionHash: string;
6590
+ rawLog?: string;
6591
+ height?: number;
6592
+ txIndex?: number;
6593
+ gasWanted?: bigint;
6594
+ gasUsed?: bigint;
6595
+ }>;
6596
+ disputeClaim?: (granteeAddress: string, did: string, payload: {
6597
+ subjectId: string;
6598
+ disputeType: number;
6599
+ reason: string;
6600
+ }) => Promise<any>;
6601
+ getCurrentUser: () => {
6602
+ address: string;
6603
+ did?: string;
6604
+ };
6605
+ createUdid?: (params: any) => Promise<any>;
6606
+ }
6607
+ /**
6608
+ * Claims-module collection lifecycle service. The editor declares the
6609
+ * contract only; the consumer app implements each method (broadcast on chain,
6610
+ * resolve admin from its wallet context, map string<->Long).
6611
+ *
6612
+ * Per IXO-2573, each write op should broadcast then the dispatcher re-fetches
6613
+ * via `get(...)` so `runtime.output` always holds the latest full
6614
+ * `CollectionState`. `get` is the read-only `refresh` primitive.
6615
+ */
6616
+ interface CollectionService {
6617
+ /** Read the full current on-chain state of a collection. */
6618
+ get: (params: {
6619
+ collectionId: string;
6620
+ }) => Promise<CollectionState>;
6621
+ /** Broadcast `MsgCreateCollection`. Returns the new collectionId + tx hash. */
6622
+ create: (params: CollectionCreateParams) => Promise<{
6623
+ transactionHash: string;
6624
+ collectionId: string;
6625
+ }>;
6626
+ /** Broadcast `MsgUpdateCollectionState`. */
6627
+ updateState: (params: {
6628
+ collectionId: string;
6629
+ state: CollectionStateEnum;
6630
+ adminAddress: string;
6631
+ }) => Promise<{
6632
+ transactionHash: string;
6633
+ }>;
6634
+ /** Broadcast `MsgUpdateCollectionDates`. */
6635
+ updateDates: (params: {
6636
+ collectionId: string;
6637
+ startDate?: string;
6638
+ endDate?: string;
6639
+ adminAddress: string;
6640
+ }) => Promise<{
6641
+ transactionHash: string;
6642
+ }>;
6643
+ /** Broadcast `MsgUpdateCollectionQuota`. `quota` carried as a string; `0` = unlimited. */
6644
+ updateQuota: (params: {
6645
+ collectionId: string;
6646
+ quota: string;
6647
+ adminAddress: string;
6648
+ }) => Promise<{
6649
+ transactionHash: string;
6650
+ }>;
6651
+ /** Broadcast `MsgUpdateCollectionPayments`. */
6652
+ updatePayments: (params: {
6653
+ collectionId: string;
6654
+ payments: Payments;
6655
+ adminAddress: string;
6656
+ }) => Promise<{
6657
+ transactionHash: string;
6658
+ }>;
6659
+ /** Broadcast `MsgUpdateCollectionIntents`. */
6660
+ updateIntents: (params: {
6661
+ collectionId: string;
6662
+ intents: CollectionIntentOptions;
6663
+ adminAddress: string;
6664
+ }) => Promise<{
6665
+ transactionHash: string;
6666
+ }>;
6667
+ }
6668
+ /**
6669
+ * Claim-collection user-management service (IXO-2586). The editor declares the
6670
+ * contract only; the consumer app implements each method (build/broadcast the
6671
+ * claims-module authz messages, query authz grants, classify addresses,
6672
+ * enumerate group members). Extends → replaces the reactive `bid` service.
6673
+ */
6674
+ interface CollectionUsersService {
6675
+ /**
6676
+ * Grant submit/evaluate authz for ONE collection to a grantee. The handler
6677
+ * reads the grantee's existing authz for the role's msgTypeUrl and APPENDS a
6678
+ * per-collection constraint (preserving other collections' live values),
6679
+ * then broadcasts `MsgCreateClaimAuthorization` routed via
6680
+ * `MsgGrantEntityAccountAuthz` (entity admin = granter). See IXO-2589.
6681
+ */
6682
+ grant: (params: {
6683
+ granterAdminAddress: string;
6684
+ granteeAddress: string;
6685
+ collectionId: string;
6686
+ role: CollectionUserRole;
6687
+ agentQuota?: string;
6688
+ maxAmount?: CollectionCoin[];
6689
+ intentDurationNs?: string;
6690
+ deedDid?: string;
6691
+ }) => Promise<{
6692
+ transactionHash: string;
6693
+ }>;
6694
+ /**
6695
+ * Per-collection read-modify-write revoke (IXO-2590). Reads the grantee's
6696
+ * live authz, drops the target collection's constraint, and — when other
6697
+ * constraints remain — broadcasts a single atomic tx ordered
6698
+ * `[MsgRevokeEntityAccountAuthz, then one MsgCreateClaimAuthorization per
6699
+ * remaining constraint]`, preserving each remaining constraint's live
6700
+ * (decremented) quota/limits. Short-circuits to a plain revoke when the
6701
+ * target was the only constraint.
6702
+ */
6703
+ revoke: (params: {
6704
+ granterAdminAddress: string;
6705
+ granteeAddress: string;
6706
+ collectionId: string;
6707
+ role: CollectionUserRole;
6708
+ }) => Promise<{
6709
+ transactionHash: string;
6710
+ }>;
6711
+ /**
6712
+ * List the grantees holding a submit/evaluate constraint for a collection.
6713
+ * Queries authz grants against the entity admin account, decodes the
6714
+ * authorizations, and filters constraints by `collectionId` (IXO-2591).
6715
+ */
6716
+ list: (params: {
6717
+ granterAdminAddress: string;
6718
+ collectionId: string;
6719
+ }) => Promise<{
6720
+ grantees: CollectionGrantee[];
6721
+ }>;
6722
+ /** Classify an address as a plain user vs a DAO DAO contract (IXO-2592). */
6723
+ classifyAddress: (params: {
6724
+ address: string;
6725
+ }) => Promise<AddressClassification>;
6726
+ /** Enumerate the members of a group account for grant fan-out (IXO-2592). */
6727
+ enumerateMembers: (params: {
6728
+ groupAddress: string;
6729
+ }) => Promise<{
6730
+ members: CollectionMember[];
6731
+ }>;
6732
+ }
6733
+ interface MatrixCredentialService {
6734
+ storeCredential: (params: {
6735
+ roomId: string;
6736
+ credentialKey: string;
6737
+ credential: Record<string, any>;
6738
+ cid: string;
6739
+ }) => Promise<{
6740
+ storedAt: string;
6741
+ duplicate: boolean;
6742
+ }>;
6743
+ }
6744
+ /** Result of any integration tool execution (direct or via a binding). */
6745
+ interface IntegrationExecuteOutcome {
6746
+ successful: boolean;
6747
+ data?: Record<string, unknown>;
6748
+ error?: string;
6749
+ code?: 'OK' | 'VALIDATION' | 'AUTH_EXPIRED' | 'UPSTREAM_4XX' | 'UPSTREAM_5XX' | 'RATE_LIMIT' | 'UNKNOWN';
6750
+ }
6751
+ interface IntegrationsService {
6752
+ executeTool: (args: {
6753
+ toolSlug: string;
6754
+ connectedAccountId: string;
6755
+ arguments: Record<string, unknown>;
6756
+ }) => Promise<IntegrationExecuteOutcome>;
6757
+ fetchCurrentState?: (args: {
6758
+ toolSlug: string;
6759
+ connectedAccountId: string;
6760
+ arguments: Record<string, unknown>;
6761
+ }) => Promise<Record<string, unknown>>;
6762
+ getEntityDid?: () => string | undefined;
6763
+ /**
6764
+ * Execute a tool on the template author's behalf via an opaque, server-side
6765
+ * binding (delegated blocks). The runner never holds the author's
6766
+ * credential — `bindingId` selects it on the worker. Returns the same
6767
+ * outcome shape as `executeTool`.
6768
+ */
6769
+ executeBinding?: (args: {
6770
+ bindingId: string;
6771
+ toolSlug: string;
6772
+ arguments: Record<string, unknown>;
6773
+ }) => Promise<IntegrationExecuteOutcome>;
6774
+ }
6775
+ interface OracleService {
6776
+ generateWallet: () => Promise<{
6777
+ address: string;
6778
+ did: string;
6779
+ pubKey: string;
6780
+ mnemonic: string;
6781
+ }>;
6782
+ fundWallet: (params: {
6783
+ address: string;
6784
+ amount: number;
6785
+ }) => Promise<{
6786
+ transactionHash: string;
6787
+ }>;
6788
+ createIidDocument: (params: {
6789
+ mnemonic: string;
6790
+ did: string;
6791
+ address: string;
6792
+ pubKey: string;
6793
+ }) => Promise<{
6794
+ did: string;
6795
+ transactionHash: string;
6796
+ }>;
6797
+ registerMatrixAccount: (params: {
6798
+ mnemonic: string;
6799
+ address: string;
6800
+ did: string;
6801
+ pin: string;
6802
+ oracleName: string;
6803
+ avatarUrl?: string;
6804
+ }) => Promise<{
6805
+ matrixUserId: string;
6806
+ matrixAccessToken: string;
6807
+ matrixRoomId: string;
6808
+ matrixDeviceId: string;
6809
+ matrixMnemonic: string;
6810
+ matrixPassword: string;
6811
+ matrixRecoveryPhrase: string;
6812
+ matrixHomeServerUrl: string;
6813
+ }>;
6814
+ createOracleEntity: (params: {
6815
+ mnemonic: string;
6816
+ address: string;
6817
+ did: string;
6818
+ pubKey: string;
6819
+ pin: string;
6820
+ matrixAccessToken: string;
6821
+ matrixRoomId: string;
6822
+ oracleName: string;
6823
+ orgName: string;
6824
+ description: string;
6825
+ location: string;
6826
+ logoUrl: string;
6827
+ coverImageUrl: string;
6828
+ apiUrl: string;
6829
+ price: number;
6830
+ llmModel: string;
6831
+ opening?: string;
6832
+ communicationStyle?: string;
6833
+ capabilities?: string;
6834
+ mcpConfig?: any;
6835
+ parentProtocol?: string;
6836
+ }) => Promise<{
6837
+ entityDid: string;
6838
+ transactionHash: string;
6839
+ /** Multibase-encoded P-256 public key registered as a keyAgreement vm on the oracle entity DID. */
6840
+ encryptionPublicKeyMultibase: string;
6841
+ /** DID verification method id of the P-256 keyAgreement key. */
6842
+ encryptionVerificationMethodId: string;
6843
+ }>;
6844
+ /**
6845
+ * Contract the oracle: ensure the user↔oracle Matrix DM room exists and
6846
+ * the user has joined it. Pure Matrix work — no chain calls, no key setup.
6847
+ * Returns the user↔oracle room id which downstream steps (storeSecrets,
6848
+ * storeConfig) write into.
6849
+ */
6850
+ contract: (params: {
6851
+ oracleEntityDid: string;
6852
+ }) => Promise<{
6853
+ userOracleRoomId: string;
6854
+ userOracleRoomAlias: string;
6855
+ }>;
6856
+ provisionSandbox: (params: {
6857
+ entityDid: string;
6858
+ matrixRoomId: string;
6859
+ }) => Promise<{
6860
+ sandboxUrl: string;
6861
+ status: string;
6862
+ }>;
6863
+ storeSecrets: (params: {
6864
+ matrixRoomId: string;
6865
+ publicKeyMultibase: string;
6866
+ verificationMethodId: string;
6867
+ matrixHomeServerUrl: string;
6868
+ matrixUsername: string;
6869
+ matrixPassword: string;
6870
+ secrets: Record<string, string>;
6871
+ preEncryptedSecrets?: Record<string, string>;
6872
+ }) => Promise<{
6873
+ storedSecrets: string[];
6874
+ roomId: string;
6875
+ freshAccessToken?: string;
6876
+ }>;
6877
+ /** JWE-encrypts a single plaintext value to the oracle's P-256 public key (multibase).
6878
+ * Used by storeSecrets FlowDetail to encrypt user-typed OpenRouter key at-rest. */
6879
+ encryptForOracle: (params: {
6880
+ plaintext: string;
6881
+ publicKeyMultibase: string;
6882
+ }) => Promise<{
6883
+ jwe: string;
6884
+ }>;
6885
+ /** Reads `ixo.room.secret.index` state events from the matrix room and returns the
6886
+ * list of secret names already stored. Used for idempotency checks. */
6887
+ readStoredSecrets: (params: {
6888
+ matrixRoomId: string;
6889
+ }) => Promise<{
6890
+ secretNames: string[];
6891
+ }>;
6892
+ /** Returns the network-derived .env constants (RPC URL, matrix homeserver, etc.)
6893
+ * for the consumer's currently configured network. Used by the storeSecrets
6894
+ * FlowDetail's "Additional Configuration" display section, and merged into the
6895
+ * storeConfig state event by the consumer handler. Must be deterministic per network. */
6896
+ getNetworkConstants: (params: {
6897
+ oracleName: string;
6898
+ }) => Promise<{
6899
+ constants: Record<string, string>;
6900
+ }>;
6901
+ validateMcpServer: (params: {
6902
+ url: string;
6903
+ authType?: 'bearer' | 'api-key' | 'none';
6904
+ authToken?: string;
6905
+ }) => Promise<{
6906
+ success: boolean;
6907
+ tools?: Array<{
6908
+ name: string;
6909
+ description?: string;
6910
+ }>;
6911
+ error?: string;
6912
+ }>;
6913
+ storeConfig: (params: {
6914
+ matrixRoomId: string;
6915
+ config: {
6916
+ oracleName: string;
6917
+ orgName: string;
6918
+ description: string;
6919
+ location: string;
6920
+ price: number;
6921
+ apiUrl: string;
6922
+ entityDid: string;
6923
+ logoUrl: string;
6924
+ llmModel: string;
6925
+ opening?: string;
6926
+ communicationStyle?: string;
6927
+ capabilities?: string;
6928
+ skills?: string[];
6929
+ mcpServers?: Array<{
6930
+ name: string;
6931
+ url: string;
6932
+ description?: string;
6933
+ authEnvVar?: string;
6934
+ }>;
6935
+ matrixUserId?: string;
6936
+ matrixAccountRoomId?: string;
6937
+ oracleAddress?: string;
6938
+ oracleDid?: string;
6939
+ };
6940
+ }) => Promise<{
6941
+ configStored: boolean;
6942
+ roomId: string;
6943
+ }>;
6944
+ deploySetup: (params: {
6945
+ name: string;
6946
+ config: Record<string, any>;
6947
+ roomId: string;
6948
+ secrets?: Record<string, string>;
6949
+ }) => Promise<{
6950
+ setupComplete: boolean;
6951
+ stdout?: string;
6952
+ stderr?: string;
6953
+ }>;
6954
+ deployStart: (params: {
6955
+ name: string;
6956
+ entityDid: string;
6957
+ roomId: string;
6958
+ secrets?: Record<string, string>;
6959
+ }) => Promise<{
6960
+ processId: string;
6961
+ status: string;
6962
+ url?: string;
6963
+ }>;
6964
+ updateOracleDomain: (params: {
6965
+ entityDid: string;
6966
+ newApiUrl: string;
6967
+ }) => Promise<{
6968
+ transactionHash: string;
6969
+ }>;
6970
+ }
6971
+ /**
6972
+ * Carbon credit batch service (IXO-2675). The editor declares the contract
6973
+ * only; the consumer app implements each method (run the owner/admin
6974
+ * reconciliation read, build + broadcast the harvest grant/exec pair and the
6975
+ * retire message, sign via its own wallet/SignX). Both writes are USER-signed
6976
+ * — the editor never signs on the user's behalf.
6977
+ */
6978
+ interface CarbonService {
6979
+ /**
6980
+ * Reconcile the user's owner-side and entity-admin-side batches into the
6981
+ * unified view. Pure read (no signing). Performs provenance recovery for
6982
+ * transferred batches so every `harvestableBatch` carries `entityDid` +
6983
+ * `adminAddress`. See technical doc §3–§4.
6984
+ */
6985
+ loadBatches: (params: {
6986
+ ownerAddress: string;
6987
+ }) => Promise<{
6988
+ harvestableBatches: CarbonHarvestableBatch[];
6989
+ retireableBatches: CarbonRetireableBatch[];
6990
+ totalClaimable: number;
6991
+ totalAvailable: number;
6992
+ totalRetired: number;
6993
+ }>;
6994
+ /**
6995
+ * Harvest (claim) the given batches: per entity, grant the owner authz to
6996
+ * transfer out of the entity admin account, then exec that transfer into
6997
+ * the owner's wallet (ordered pairs, 30-min grant). User-signed. See §5.2.
6998
+ */
6999
+ harvest: (params: {
7000
+ ownerAddress: string;
7001
+ tokens: Array<{
7002
+ id: string;
7003
+ entityDid: string;
7004
+ adminAddress: string;
7005
+ claimable: number;
7006
+ }>;
7007
+ }) => Promise<{
7008
+ transactionHash: string;
7009
+ harvestedBatchIds: string[];
7010
+ harvestedAmount: number;
7011
+ }>;
7012
+ /**
7013
+ * Retire (burn/offset) the given amounts from the owner's wallet. Single
7014
+ * owner-signed `MsgRetireToken`. Irreversible. `jurisdiction` arrives
7015
+ * pre-composed as a string (default "Global"); `reason` defaults to
7016
+ * "offset". See §5.1.
7017
+ */
7018
+ retire: (params: {
7019
+ owner: string;
7020
+ reason?: string;
7021
+ jurisdiction?: string;
7022
+ tokens: Array<{
7023
+ id: string;
7024
+ amount: number;
7025
+ }>;
7026
+ }) => Promise<{
7027
+ transactionHash: string;
7028
+ retiredBatchIds: string[];
7029
+ retiredAmount: number;
7030
+ }>;
7031
+ }
7032
+ /**
7033
+ * Entity (domain) ownership service (IXO-2696). The editor declares the
7034
+ * contract only; the consumer app implements `transfer` — resolve a group
7035
+ * recipient to its DAO controller, ensure the recipient has an IID document,
7036
+ * build + broadcast `MsgTransferEntity`, and sign via its own wallet/SignX.
7037
+ * USER-signed and IRREVERSIBLE — the editor never signs on the user's behalf.
7038
+ */
7039
+ interface EntityService {
7040
+ /**
7041
+ * Transfer ownership of `entityDid` to `recipientDid`. The consumer resolves
7042
+ * a `did:ixo:entity:` group recipient to its `did:ixo:wasm:` controller
7043
+ * (reported back as `recipientResolved` when changed) and creates the
7044
+ * recipient's IID document first if it is missing (`createdRecipientIid`).
7045
+ * `ownerDid`/`ownerAddress` default to the connected user inside the host.
7046
+ * Proof of a real transfer is the returned `transactionHash`.
7047
+ */
7048
+ transfer: (params: {
7049
+ entityDid: string;
7050
+ recipientDid: string;
7051
+ ownerDid?: string;
7052
+ ownerAddress?: string;
7053
+ }) => Promise<{
7054
+ transactionHash: string;
7055
+ recipientResolved?: string;
7056
+ createdRecipientIid?: boolean;
7057
+ }>;
7058
+ }
7059
+ /**
7060
+ * KYC verification service (qi/kyc.verify). The editor declares the contract
7061
+ * only; the consumer app implements each method against its KYC server
7062
+ * (create/read the ComplyCube evaluation, mint the hosted verification URL,
7063
+ * persist the SD-JWT credential to the user's Matrix vault). The server's
7064
+ * status is the single source of truth for the lifecycle
7065
+ * (`verify → review → clear → issuing → issued → complete`, failure states
7066
+ * `rejected|attention|error`, plus `unknown`) — the editor only polls it.
7067
+ *
7068
+ * PII boundary: survey answers flow INTO `initiate` but never back out —
7069
+ * action outputs carry only `credentialCid`, `credentialType`, `protocolId`,
7070
+ * and `status`.
7071
+ */
7072
+ interface KycService {
7073
+ /**
7074
+ * Load the KYC protocol's details form + the user's current server-side
7075
+ * state. `credentialType` is the vault index key of the credential this
7076
+ * protocol issues (e.g. 'kycamllevel1' | 'kycamllevel2'); hosts default it
7077
+ * to level 1 when omitted — `hasExistingCredential` refers to THAT type
7078
+ * only, so a level-2 flow is never satisfied by a level-1 credential.
7079
+ */
7080
+ loadForm(params: {
7081
+ protocolDid: string;
7082
+ credentialType?: string;
7083
+ }): Promise<{
7084
+ protocolId: string;
7085
+ claimCollectionId?: string;
7086
+ deedOfferId?: string;
7087
+ surveyJson: Record<string, unknown>;
7088
+ hasExistingCredential: boolean;
7089
+ /** Non-PII metadata of matching Vault credentials, oldest first. */
7090
+ existingCredentials?: Array<{
7091
+ cid: string;
7092
+ credentialType: string;
7093
+ storedAt?: string;
7094
+ issuerDid?: string;
7095
+ }>;
7096
+ status: string;
7097
+ }>;
7098
+ /** Submit the details form; the server creates the ComplyCube evaluation. */
7099
+ initiate(params: {
7100
+ protocolId: string;
7101
+ claimCollectionId?: string;
7102
+ deedOfferId?: string;
7103
+ data: Record<string, unknown>;
7104
+ }): Promise<{
7105
+ status: string;
7106
+ }>;
7107
+ /** Mint the hosted-webview verification URL for the user's evaluation. */
7108
+ getVerificationUrl(params: {
7109
+ protocolId: string;
7110
+ }): Promise<{
7111
+ url: string;
7112
+ }>;
7113
+ /** Read the current server-side lifecycle status. */
7114
+ getStatus(params: {
7115
+ protocolId: string;
7116
+ }): Promise<{
7117
+ status: string;
7118
+ }>;
7119
+ /**
7120
+ * Save the issued SD-JWT credential to the user's Matrix vault room and
7121
+ * move the server status to `complete`. Idempotent — re-saving an
7122
+ * already-saved credential of the same `credentialType` returns the
7123
+ * existing CID (defaults to level 1 when omitted).
7124
+ */
7125
+ saveCredential(params: {
7126
+ protocolId: string;
7127
+ credentialType?: string;
7128
+ credentialCid?: string;
7129
+ }): Promise<{
7130
+ credentialCid: string;
7131
+ credentialType: string;
7132
+ }>;
7133
+ }
7134
+ interface BlueprintService {
7135
+ execute(params: {
7136
+ action: string;
7137
+ inputs: Record<string, unknown>;
7138
+ actorDid: string;
7139
+ flowId: string;
7140
+ nodeId: string;
7141
+ }): Promise<{
7142
+ receiptRef: string;
7143
+ result?: Record<string, unknown>;
7144
+ }>;
7145
+ }
7146
+ interface FlowRunLifecycleService {
7147
+ start(params: {
7148
+ actorDid: string;
7149
+ flowId: string;
7150
+ flowUri?: string;
7151
+ label?: string;
7152
+ }): Promise<{
7153
+ runId: string;
7154
+ eventId?: string;
7155
+ startedAt?: number;
7156
+ }>;
7157
+ close(params: {
7158
+ actorDid: string;
7159
+ flowId: string;
7160
+ flowUri?: string;
7161
+ runId: string;
7162
+ allowIncomplete?: boolean;
7163
+ }): Promise<{
7164
+ status: 'closed';
7165
+ eventId?: string;
7166
+ closedAt?: number;
7167
+ }>;
7168
+ cancel(params: {
7169
+ actorDid: string;
7170
+ flowId: string;
7171
+ flowUri?: string;
7172
+ runId: string;
7173
+ reason?: string;
7174
+ }): Promise<{
7175
+ status: 'cancelled';
7176
+ eventId?: string;
7177
+ cancelledAt?: number;
7178
+ }>;
7179
+ }
7180
+ /**
7181
+ * The full service contract an action execution context can carry. Composed
7182
+ * from the per-domain service interfaces above so consumers can implement and
7183
+ * type one domain at a time; the runtime shape is unchanged.
7184
+ */
7185
+ interface ActionServices {
7186
+ blueprint?: BlueprintService;
7187
+ /** Explicit session lifecycle capability supplied by browser/headless hosts. */
7188
+ flowRuns?: FlowRunLifecycleService;
7189
+ http?: HttpService;
7190
+ email?: EmailService;
7191
+ notify?: NotifyService;
7192
+ bid?: BidService;
7193
+ claim?: ClaimService;
7194
+ collection?: CollectionService;
7195
+ collectionUsers?: CollectionUsersService;
7196
+ matrix?: MatrixCredentialService;
7197
+ integrations?: IntegrationsService;
7198
+ oracle?: OracleService;
7199
+ carbon?: CarbonService;
7200
+ entity?: EntityService;
7201
+ kyc?: KycService;
7202
+ }
7203
+ interface OutputSchemaField {
7204
+ path: string;
7205
+ displayName: string;
7206
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
7207
+ description?: string;
7208
+ /**
7209
+ * For `type === 'array'`: the shape of each element. Drives item-scoped
7210
+ * reference pickers (e.g. the Xero invoice LineItems iterative mapper,
7211
+ * where each cell refs into `{{item.<field>}}`).
7212
+ */
7213
+ itemSchema?: OutputSchemaField[];
7214
+ }
7215
+ /**
7216
+ * A typed event that an action can emit when it runs.
7217
+ *
7218
+ * Events drive the trigger/listener model: another block can declare a
7219
+ * `block.event` trigger on a (sourceBlockId, eventName) pair, and when this
7220
+ * action emits a matching event, a pending invocation is queued on the
7221
+ * listener block. See `docs/flow-engine/events-and-triggers-plan.md` for the full model.
7222
+ */
7223
+ interface ActionEventDefinition {
7224
+ /** Stable identifier — used in trigger declarations and ref strings. */
7225
+ name: string;
7226
+ /** Human-readable label shown in the trigger picker UI. */
7227
+ displayName: string;
7228
+ /** Short description shown as inline hint in the trigger picker. */
7229
+ description: string;
7230
+ /** Schema of the event payload. Same shape as `outputSchema`. */
7231
+ payloadSchema: OutputSchemaField[];
7232
+ /**
7233
+ * Field paths from `payloadSchema` (in order) shown inline in the
7234
+ * pending-invocation list so the assignee can distinguish queued
7235
+ * invocations at a glance. E.g. `['claimId', 'evaluatedAt']`.
7236
+ */
7237
+ pendingDisplayFields?: string[];
7238
+ }
7239
+ /**
7240
+ * Declares what counts as proof that this action's side effect actually
7241
+ * happened. Enforced centrally by `executeActionBlock`: a run that returns
7242
+ * success without satisfying its proof declaration is recorded as
7243
+ * `state: 'failed'` (code `PROOF_MISSING`), never as `completed`.
7244
+ *
7245
+ * - `{ fields }` — at least one of the listed output paths (dot notation
7246
+ * allowed) must be truthy. Empty arrays and `false` do not count.
7247
+ * - `{ validate }` — custom predicate over the raw output.
7248
+ * - `'none'` — explicit opt-out for actions with no side effect to prove
7249
+ * (pure selection/config actions). Must be stated, not omitted.
7250
+ */
7251
+ type ActionProofDeclaration = {
7252
+ fields: string[];
7253
+ } | {
7254
+ validate: (output: Record<string, unknown>) => boolean;
7255
+ } | 'none';
7256
+ interface ActionRunContext {
7257
+ runId: string;
7258
+ flowId?: string;
7259
+ flowUri?: string;
7260
+ actorDid?: string;
7261
+ nodeId?: string;
7262
+ /** Read-only service capabilities available to `done.check`. */
7263
+ services?: ActionServices;
7264
+ now: number;
7265
+ }
7266
+ interface CompletionCheck {
7267
+ done: boolean | 'unknown';
7268
+ source: string;
7269
+ output?: Record<string, unknown>;
7270
+ reason?: string;
7271
+ }
7272
+ /**
7273
+ * Canonical completion semantics for one run of an action. Every registered
7274
+ * action declares one — see {@link ActionDefinition.done}.
7275
+ */
7276
+ interface ActionDoneContract<TInputs extends Record<string, any> = Record<string, any>> {
7277
+ /** Pure fold used by session summaries and the default close condition. */
7278
+ isDone: (actionState: FlowNodeRuntimeState, runContext: ActionRunContext) => boolean;
7279
+ /** Optional side-effect-free external read used by explicit reconciliation. */
7280
+ check?: (params: {
7281
+ inputs: TInputs;
7282
+ actionState: FlowNodeRuntimeState;
7283
+ ctx: ActionRunContext;
7284
+ }) => Promise<CompletionCheck>;
7285
+ }
7286
+ interface ActionDefinition<TInputs extends Record<string, any> = Record<string, any>> {
7287
+ type: string;
7288
+ /** UCAN-style ability string used by the flow compiler, e.g., "bid/submit". */
7289
+ can?: string;
7290
+ sideEffect: boolean;
7291
+ defaultRequiresConfirmation: boolean;
7292
+ requiredCapability?: string;
7293
+ /**
7294
+ * Who performs the execution once inputs are complete.
7295
+ *
7296
+ * - 'agent' (the default) — a headless orchestrator may run `run()` itself
7297
+ * or delegate it to a capable oracle.
7298
+ * - 'human' — only a human surface (Portal FlowDetail) may execute: the
7299
+ * side effect needs an authority the orchestrator does not hold, e.g. a
7300
+ * chain transaction signed as the entity admin. Orchestrators still
7301
+ * gather inputs and notify the human, but must never run or delegate
7302
+ * the action themselves.
7303
+ */
7304
+ executionOwner?: 'agent' | 'human';
7305
+ /** Proof-of-execution declaration. See {@link ActionProofDeclaration}. */
7306
+ proof: ActionProofDeclaration;
7307
+ /**
7308
+ * How many times this action is meant to run within a single flow.
7309
+ *
7310
+ * - 'once' (the default) — a one-shot step that reaches a terminal
7311
+ * `completed` state and is then Done.
7312
+ * - 'many' — a standing, repeatable capability that can fire any number of
7313
+ * times on a cadence the flow (not the action) decides — e.g. submitting a
7314
+ * claim every month. A repeatable block never latches to a terminal Done:
7315
+ * a `completed` runtime entry means "has fired at least once", and its real
7316
+ * progress is the count of successful runs in the audit trail, not this
7317
+ * single summary entry. Such blocks never withhold the flow.
7318
+ */
7319
+ cardinality?: 'once' | 'many';
7320
+ /**
7321
+ * Canonical completion semantics for a run. Required: every action states
7322
+ * how one of its runs folds to Done, and `isActionDone` consults nothing
7323
+ * else. Most actions are Done when the run reached `completed` and use the
7324
+ * shared {@link doneWhenCompleted} contract; repeatable (`many`) actions use
7325
+ * {@link neverDone}. Declare a bespoke contract when Done-ness depends on an
7326
+ * output field, a quota, or an external system (see `qi/kyc.verify`).
7327
+ */
7328
+ done: ActionDoneContract<TInputs>;
7329
+ /**
7330
+ * How dynamic resolver results combine with the static `events` /
7331
+ * `outputSchema` baselines. 'merge' (the default) dedupes by event name /
7332
+ * field path with the dynamic entry winning; 'replace' hands the resolver
7333
+ * full control of the vocabulary (needed e.g. to hide the baseline until
7334
+ * configuration is complete).
7335
+ */
7336
+ dynamicResolutionMode?: 'merge' | 'replace';
7337
+ inputSchema?: object;
7338
+ /**
7339
+ * Machine-readable mirror of the required-input preamble in `run()`: given a
7340
+ * fully-merged inputs object, returns the names of inputs still missing or
7341
+ * blank (empty array = ready to execute). External orchestrators call this
7342
+ * via `getMissingActionInputs` BEFORE queuing execution so a missing input
7343
+ * becomes a prompt to a human rather than a failed run.
7344
+ *
7345
+ * Only define this when requiredness is conditional — it branches on other
7346
+ * inputs (skip flags, group types, either-of-two-fields) and therefore
7347
+ * cannot be derived from `inputSchema.required`, which is the default
7348
+ * derivation. Keep it directly above `run()` and keep the two in lockstep:
7349
+ * every presence throw in `run()` must be predicted here. Presence only —
7350
+ * value validity (ranges, formats, duplicates) stays in `run()`.
7351
+ */
7352
+ getMissingInputs?: (inputs: TInputs) => string[];
7353
+ /** Static output schema for action types with predictable output (e.g. email.send).
7354
+ * For action types with dynamic output (e.g. http.request), the schema is user-defined in inputs. */
7355
+ outputSchema?: OutputSchemaField[];
7356
+ /**
7357
+ * Typed vocabulary of events this action can emit. Drives the trigger
7358
+ * picker UI and compile-time validation of `block.event` triggers.
7359
+ */
7360
+ events?: ActionEventDefinition[];
7361
+ /**
7362
+ * Optional per-block event resolver. Called with the block's current
7363
+ * template inputs; returns the event vocabulary that applies to this
7364
+ * specific block.
7365
+ *
7366
+ * Use this when the event schema depends on configuration the designer
7367
+ * picks at template time. For example, `qi/claim.submit` only knows the
7368
+ * shape of `surveyAnswers` once a claim collection has been chosen —
7369
+ * returning `[]` until then hides the block from the trigger picker.
7370
+ *
7371
+ * Consumers (trigger picker, flow compiler, event payload picker) prefer
7372
+ * `getDynamicEvents(inputs)` when defined and fall back to static `events`
7373
+ * otherwise. By default the result is MERGED with the static `events`
7374
+ * baseline (deduped by name, dynamic wins). Set
7375
+ * `dynamicResolutionMode: 'replace'` when the resolver must control the
7376
+ * full vocabulary (e.g. returning [] to hide the baseline).
7377
+ */
7378
+ getDynamicEvents?: (inputs: TInputs) => ActionEventDefinition[];
7379
+ /**
7380
+ * Optional per-block output-schema resolver. Symmetric to `getDynamicEvents`
7381
+ * but for `outputSchema` — drives the reference picker for `${block.field}`
7382
+ * refs so survey-derived fields like `output.surveyAnswers.<question>` show
7383
+ * up alongside the static baseline.
7384
+ *
7385
+ * By default the returned array is MERGED with the static `outputSchema`
7386
+ * baseline (deduped by path, dynamic wins); `dynamicResolutionMode:
7387
+ * 'replace'` gives the resolver full control.
7388
+ */
7389
+ getDynamicOutputSchema?: (inputs: TInputs) => OutputSchemaField[];
7390
+ /**
7391
+ * Whether this action can be wired to a `block.event` trigger.
7392
+ * False (the default) for user-interaction-driven actions like forms,
7393
+ * claims, and evaluations — they always run as `manual`. True for actions
7394
+ * where it makes sense for an event to nudge a human assignee to invoke
7395
+ * them (email, http, notify).
7396
+ *
7397
+ * The trigger picker UI is hidden for blocks whose action type has this
7398
+ * set to false.
7399
+ */
7400
+ eligibleForEventTrigger?: boolean;
7401
+ run: (inputs: TInputs, ctx: ActionContext) => Promise<ActionResult>;
7402
+ }
7403
+ /**
7404
+ * Result returned by an action's `run()` function.
7405
+ *
7406
+ * The optional `events` array is the explicit emission surface — actions
7407
+ * declare which named events they're emitting on this particular run, with
7408
+ * the payload by value. The runtime persists these as part of the run record
7409
+ * and the reconciliation loop turns them into pending invocations on
7410
+ * subscribed listener blocks.
7411
+ */
7412
+ interface ActionResult {
7413
+ output: Record<string, any>;
7414
+ events?: Array<{
7415
+ name: string;
7416
+ payload: Record<string, any>;
7417
+ }>;
7418
+ completion?: {
7419
+ state?: 'completed' | 'awaiting_readback';
7420
+ readBack?: Record<string, any>;
7421
+ };
7422
+ }
7423
+
7424
+ /** Top-level Y.Doc map owning the write-once terminal (closed/cancelled) latch per run. */
7425
+ declare const RUNS_TERMINAL_MAP_KEY = "runsTerminal";
7426
+ /**
7427
+ * Whether a record written with `recordRunId` belongs to `sessionRunId`.
7428
+ *
7429
+ * Records written before sessions existed carry no `sessionRunId` at all. They
7430
+ * belong to the unsessioned document, so they match only while the flow is
7431
+ * still unmigrated — migration stamps the real run id onto every one of them,
7432
+ * after which this is a plain equality test and no record is ownerless.
7433
+ *
7434
+ * Every "does this record belong to this session" test goes through here, so
7435
+ * the answer cannot drift between the readers of commands, leases, ledger
7436
+ * entries and invocations.
7437
+ */
7438
+ declare function isRecordInRun(recordRunId: string | undefined, sessionRunId: string): boolean;
7439
+ /**
7440
+ * The run id to report for a record whose own `sessionRunId` may be absent.
7441
+ *
7442
+ * Readers hand back types that require the field, so an untagged record needs
7443
+ * *some* answer. When the caller asked for a specific session the record has
7444
+ * already matched it, so that is the honest owner; otherwise it is unsessioned.
7445
+ * Callers must not substitute a literal here — the sentinel stays private so it
7446
+ * cannot become load-bearing outside this file again.
7447
+ */
7448
+ declare function resolveRecordRunId(recordRunId: string | undefined, requestedRunId?: string): string;
7449
+ /**
7450
+ * Root metadata key describing which runtime layout is authoritative.
7451
+ *
7452
+ * Version 1 is the Phase A coexistence layout: one legacy run plus the flat
7453
+ * `runtime` mirror. Version 2 is the multi-run layout: every caller supplies a
7454
+ * run id and the flat map is neither read nor written.
7455
+ */
7456
+ declare const RUN_STORAGE_VERSION_KEY = "runStorageVersion";
7457
+ type RunStorageVersion = 1 | 2;
7458
+ /**
7459
+ * The Phase A layout. Inferred for a document that carries pre-session history,
7460
+ * or declared by one that pins the key — never a fallback for a document whose
7461
+ * key is simply absent. Production writes only version 2 (migration and
7462
+ * `startRun`); the declared form exists so a caller that must pin the
7463
+ * coexistence layout, chiefly a test exercising the flat-map mirror, can say so
7464
+ * instead of relying on a default that no longer points that way.
7465
+ */
7466
+ declare const LEGACY_RUN_STORAGE_VERSION: RunStorageVersion;
7467
+ /** The Phase B layout used by explicit, parallel runs. */
7468
+ declare const MULTI_RUN_STORAGE_VERSION: RunStorageVersion;
7469
+ /**
7470
+ * Whether {@link adoptLegacyRuntime} may materialise. Read it; never cache it.
7471
+ *
7472
+ * See {@link LEGACY_RUNTIME_ADOPTION_DEFAULT} for the flip condition.
7473
+ */
7474
+ declare function isLegacyRuntimeAdoptionEnabled(): boolean;
7475
+ interface RunMeta {
7476
+ /** Monotonic per-flow sequence number, for humans and ordering. */
7477
+ seq: number;
7478
+ startedAt: number;
7479
+ startedByDid?: string;
7480
+ label?: string;
7481
+ /**
7482
+ * How this run came to exist. `'migrated'` marks the single session that
7483
+ * absorbed a legacy document's pre-session history; it is an ordinary session
7484
+ * in every other respect.
7485
+ */
7486
+ origin?: 'started' | 'migrated';
7487
+ /**
7488
+ * Frozen when the run is created: the sequenced action block ids in this run
7489
+ * plus a hash of the compiled graph.
7490
+ *
7491
+ * **A run without one is not a session.** It is a phantom from a build that
7492
+ * created containers on connect, and the lifecycle refuses to close it rather
7493
+ * than computing a summary against the live document.
7494
+ */
7495
+ manifest?: {
7496
+ blockIds: string[];
7497
+ defHash: string;
7498
+ };
7499
+ }
7500
+ interface RunTerminalRecord {
7501
+ status: 'closed' | 'cancelled';
7502
+ at: number;
7503
+ by?: string;
7504
+ closeInvocationCid?: string;
7505
+ /** Matrix event that won the terminal transition. */
7506
+ terminalEventId?: string;
7507
+ /** Per-block `isDone` snapshotted at close time. Phase B populates it. */
7508
+ summary?: Record<string, boolean>;
7509
+ }
7510
+ /** The runs container. Re-resolve on every call; never cache the result. */
7511
+ declare function getRunsMap(yDoc: Y.Doc): Y.Map<Y.Map<unknown>>;
7512
+ /** The write-once terminal latch map. Re-resolve on every call. */
7513
+ declare function getRunsTerminalMap(yDoc: Y.Doc): Y.Map<RunTerminalRecord>;
7514
+ /**
7515
+ * Read the document's runtime layout without mutating it.
7516
+ *
7517
+ * **Sessions are the default; the Phase A layout is not a fallback.** A missing
7518
+ * version key is not evidence of a legacy document — it is the state of every
7519
+ * document nobody has latched yet, including ones created moments ago by paths
7520
+ * that copy a doc rather than compile one (template instantiation, protocol
7521
+ * import). Treating the absent key as version 1 made those flows demand a
7522
+ * migration that would move nothing.
7523
+ *
7524
+ * So the discriminator is the *presence of pre-session history*, the same
7525
+ * predicate the compiler latches on. Version 1 is reported only for a document
7526
+ * that actually has flat-map history to migrate; everything else is version 2,
7527
+ * whether or not it carries the key. An explicit key always wins — that is what
7528
+ * `migrateFlowToSessions` writes to make the transition permanent, and it is
7529
+ * what keeps a migrated document on version 2 after its history is seeded into
7530
+ * the first session.
7531
+ */
7532
+ declare function getRunStorageVersion(yDoc: Y.Doc): RunStorageVersion;
7533
+ /** Whether flat-map compatibility is still part of this document's interface. */
7534
+ declare function usesLegacyRuntimeCompatibility(yDoc: Y.Doc): boolean;
7535
+ declare class ExplicitRunRequiredError extends Error {
7536
+ constructor(message?: string);
7537
+ }
7538
+ declare class UnknownRunError extends Error {
7539
+ readonly runId: string;
7540
+ constructor(runId: string);
7541
+ }
7542
+ declare class TerminalRunExecutionError extends Error {
7543
+ readonly runId: string;
7544
+ readonly blockId: string;
7545
+ constructor(runId: string, blockId: string);
7546
+ }
7547
+ /** Definition flag shared by manifest construction, execution guards and UI. */
7548
+ declare function isBelowTheLineBlock(block: {
7549
+ props?: Record<string, unknown>;
7550
+ } | null | undefined): boolean;
7551
+ /**
7552
+ * Resolve an execution target without turning the advisory active-run pointer
7553
+ * into authority. Version 2 requires a real, named run supplied by the caller.
7554
+ *
7555
+ * Version 1 is a legacy, unmigrated document. It has no run container and never
7556
+ * gains one from a write: the returned {@link UNSESSIONED_RUN_ID} addresses
7557
+ * nothing, reads resolve to the flat map, and writes go flat-only. That is the
7558
+ * pre-session behaviour, preserved exactly, until the flow is migrated.
7559
+ */
7560
+ declare function resolveRunIdForExecution(yDoc: Y.Doc, requestedRunId?: string): string;
7561
+ /**
7562
+ * Ordinary sequenced actions stop with the run. Explicit below-the-line
7563
+ * actions remain available for post-close work and continue appending history.
7564
+ */
7565
+ declare function assertRunActionExecutionAllowed(yDoc: Y.Doc, runId: string, block: {
7566
+ id?: string;
7567
+ props?: Record<string, unknown>;
7568
+ }): void;
7569
+ /**
7570
+ * Create the run container if it is missing. Transactional, idempotent, and
7571
+ * safe against the concurrent-create race.
7572
+ *
7573
+ * **The race:** two clients concurrently doing `runs.get(id) ?? new Y.Map()`
7574
+ * produce two detached `Y.Map`s. The merge keeps one and *silently discards
7575
+ * everything ever written into the loser*, with no error. Phase A aggravates
7576
+ * this whenever two clients start or migrate the same flow at once.
7577
+ * The in-transaction re-check closes the local window; the flat mirror written
7578
+ * by {@link writeActionState} is the second net that makes the remote window
7579
+ * survivable.
7580
+ *
7581
+ * Returns the LIVE container. **Never cache it across a tick** — a losing merge
7582
+ * orphans the reference and subsequent writes vanish with no error.
7583
+ */
7584
+ declare function ensureRun(yDoc: Y.Doc, runId: string, meta?: Partial<RunMeta>): Y.Map<unknown>;
7585
+ /**
7586
+ * The run's actions map, re-resolved from the doc on every call.
7587
+ * Returns `undefined` if the run does not exist — this is a pure read and must
7588
+ * never write (a read-only viewer calls it).
7589
+ */
7590
+ declare function getRunActionsMap(yDoc: Y.Doc, runId: string): Y.Map<FlowNodeRuntimeState> | undefined;
7591
+ /** Read a run's `meta`. Returns `undefined` when the run does not exist. */
7592
+ declare function getRunMeta(yDoc: Y.Doc, runId: string): RunMeta | undefined;
7593
+ interface MultiRunMigrationResult {
7594
+ actionStates: number;
7595
+ pendingInvocations: number;
7596
+ barrierEntries: number;
7597
+ }
7598
+ /**
7599
+ * Whether this document carries pre-session execution history.
7600
+ *
7601
+ * True means the flat `runtime` map holds at least one real action state, so
7602
+ * migrating produces a session with something in it. Reserved `__`-prefixed
7603
+ * keys (DM dedup) are not history: a flow that only ever sent a notification has
7604
+ * never executed anything.
7605
+ */
7606
+ declare function hasLegacyRuntimeHistory(yDoc: Y.Doc): boolean;
7607
+ /**
7608
+ * Delete the container that pre-migration builds created on every connect.
7609
+ *
7610
+ * Such a container is not a session — it has no frozen manifest, so the
7611
+ * lifecycle cannot close it, yet it is enumerated by every surface that lists
7612
+ * runs and therefore shows up as a phantom the user can neither finish nor
7613
+ * remove. Returns whether anything was deleted.
7614
+ *
7615
+ * Collected when deleting it provably loses nothing:
7616
+ *
7617
+ * - it holds no action states of its own — there is no copy to destroy; or
7618
+ * - the document is version 1, where the dual-write guarantees every state in
7619
+ * the phantom is also in the flat map.
7620
+ *
7621
+ * Under version 2 a container that does hold states is the only copy of them,
7622
+ * so it is left alone regardless of how it got its name. A run bearing a
7623
+ * manifest is a real session and is never touched.
7624
+ *
7625
+ * The empty case is not hypothetical: a pre-session build created this
7626
+ * container on *every connect*, so a flow that was opened but never executed
7627
+ * has a phantom and no flat history — and with sessions as the default that
7628
+ * document is version 2, where the version gate alone would strand the phantom
7629
+ * as an unfinishable, unremovable session.
7630
+ */
7631
+ declare function collectPhantomLegacyRun(yDoc: Y.Doc): boolean;
7632
+ /**
7633
+ * Seed a newly created run with the document's pre-session history: the
7634
+ * freshness winner for every legacy action, plus pending invocations and
7635
+ * partial barriers.
7636
+ *
7637
+ * **Cannot downgrade anything.** The run is created by migration immediately
7638
+ * before this call, so every block resolves with no run entry — rule (a) of
7639
+ * {@link resolveActionState} makes the flat side the winner every time, and
7640
+ * there is nothing on the run side to lose. That is what lets a legacy document
7641
+ * be seeded while the global adoption gate remains closed.
7642
+ *
7643
+ * Does **not** write the version latch: the caller flips it at the end of the
7644
+ * same transaction, after every part of the migration has succeeded.
7645
+ */
7646
+ declare function seedRunFromLegacyRuntime(yDoc: Y.Doc, runId: string): MultiRunMigrationResult;
7647
+ /** Latch the document onto the multi-run layout. */
7648
+ declare function setMultiRunStorage(yDoc: Y.Doc): void;
7649
+ /**
7650
+ * Mark a document as multi-run without migrating anything.
7651
+ *
7652
+ * For newly created documents, which have no legacy history to carry over, and
7653
+ * for tests that build runs explicitly.
7654
+ */
7655
+ declare function enableMultiRunStorage(yDoc: Y.Doc): void;
7656
+ /**
7657
+ * Read a block's action state for a run.
7658
+ *
7659
+ * **Resolves** the run entry against the flat `runtime[blockId]` through
7660
+ * {@link resolveActionState} — it does not merely fall back when the run entry
7661
+ * is missing. A run entry that exists but is *staler* than the flat mirror (an
7662
+ * old tab or a not-yet-upgraded orchestrator finished the block; or the run
7663
+ * entry is the `idle` seed left by `initializeRuntime`) must read as the
7664
+ * advanced value, or the auto-execute gate re-arms and the side effect fires
7665
+ * twice.
7666
+ *
7667
+ * Always returns a fresh copy, never a reference into the doc. Never writes —
7668
+ * safe on a read-only viewer and before the doc has connected. (Convergence is
7669
+ * `adoptLegacyRuntime`'s job, and it is a writer; reads only correct what they
7670
+ * hand back.)
7671
+ *
7672
+ * PHASE A COMPAT — REMOVAL TRIGGER: the flat resolution goes when dual-write
7673
+ * goes (compat register item 2), and only after `adoptLegacyRuntime` has run
7674
+ * against every live room.
7675
+ */
7676
+ declare function readActionState(yDoc: Y.Doc, runId: string, blockId: string): FlowNodeRuntimeState;
7677
+ /**
7678
+ * Enumerate one run through the same interface as {@link readActionState}.
7679
+ *
7680
+ * During Phase A this iterates the union of run and flat keys and resolves each
7681
+ * value through the freshness predicate. During Phase B it reads only the named
7682
+ * run. Consumers use this instead of touching either storage container.
7683
+ */
7684
+ declare function readActionStates(yDoc: Y.Doc, runId: string): Record<string, FlowNodeRuntimeState>;
7685
+ /**
7686
+ * Merge `updates` into a block's action state.
7687
+ *
7688
+ * **ONE transaction, ONE `prev` read.** The returned `prev` is the single
7689
+ * pre-write snapshot the caller must use for completion guards. Two separate
7690
+ * read-modify-write calls (one for the run, one for the mirror) would evaluate
7691
+ * `prev.state !== 'completed'` twice → two run records → two pending
7692
+ * invocations on every downstream listener → **double execution of a
7693
+ * side-effecting action**. That is the single most likely way this project
7694
+ * causes a real double payment, so the contract is enforced here rather than
7695
+ * left to call sites.
7696
+ *
7697
+ * `prev` is the **resolved** value ({@link resolveActionState}), not the raw
7698
+ * run entry. This is load-bearing for the same guard: if an old tab already
7699
+ * completed the block in the flat map while the run still holds the `idle`
7700
+ * seed, a raw `prev` would read `idle`, the guard would fire, and
7701
+ * `step.completed` would be emitted a second time — one pending invocation per
7702
+ * downstream listener, all over again.
7703
+ */
7704
+ declare function writeActionState(yDoc: Y.Doc, runId: string, blockId: string, updates: Partial<FlowNodeRuntimeState>): {
7705
+ prev: FlowNodeRuntimeState;
7706
+ next: FlowNodeRuntimeState;
7707
+ };
7708
+ /**
7709
+ * **Replace** a block's action state in the run AND the flat mirror, in one
7710
+ * transaction. The opposite of {@link writeActionState}: nothing is merged, the
7711
+ * previous value is discarded on both sides.
7712
+ *
7713
+ * This is the primitive every *reset* path must use — flow rebuild, per-node
7714
+ * re-initialisation, the user's "Reset" affordance. A reset that touches only
7715
+ * the flat map is the most dangerous write in Phase A: {@link resolveActionState}
7716
+ * rule (a) makes a surviving `completed` run entry beat the fresh `idle` flat
7717
+ * entry, so the block reads **pre-completed** — a rebuilt flow shows green ticks
7718
+ * for work nobody did in it, and a "Reset" button appears to do nothing. Because
7719
+ * CRDT history is immutable, that wrong state is permanent in a live room.
7720
+ *
7721
+ * Writing the *identical* object to both sides is what makes the pair converge:
7722
+ * the two entries are then indistinguishable, so the predicate falls through to
7723
+ * the deterministic tiebreak and {@link adoptLegacyRuntime} has nothing to
7724
+ * materialise.
7725
+ */
7726
+ declare function resetActionState(yDoc: Y.Doc, runId: string, blockId: string, value?: FlowNodeRuntimeState): void;
7727
+ /**
7728
+ * Delete a block's action state from the run AND the flat mirror, in one
7729
+ * transaction. Used when the block itself is removed from the flow.
7730
+ *
7731
+ * Deleting only the flat entry leaves the run holding the deleted block's last
7732
+ * state; a block re-added under the same id (block ids are deterministic —
7733
+ * `flow_block_<nodeId>`) then reads as already-executed.
7734
+ *
7735
+ * **Never creates the run container.** A delete on a doc that has no run yet is
7736
+ * a no-op on the run side, not a reason to materialise `runs` — a doc that has
7737
+ * never been adopted must not gain a container from a removal.
7738
+ *
7739
+ * Phase A has exactly one run, but this deletes from the *named* run only,
7740
+ * never every run: in Phase B removing a block must not rewrite the history of
7741
+ * runs that already executed it.
7742
+ */
7743
+ declare function deleteActionState(yDoc: Y.Doc, runId: string, blockId: string): void;
7744
+ /**
7745
+ * Drop **all** per-action execution state: every run container, the write-once
7746
+ * terminal latch, and the flat `runtime` map. One transaction.
7747
+ *
7748
+ * This is the full-rebuild wipe. It deletes every run, not just the active one:
7749
+ * a rebuild replaces the definition wholesale, so no run's state is meaningful
7750
+ * against it any more.
7751
+ *
7752
+ * Deliberately narrower than `clearRuntimeForTemplateClone` — it does not touch
7753
+ * `auditTrail`, `invocations`, `pendingInvocations` or `barrierState`, matching
7754
+ * exactly what the rebuild path cleared before runs existed. Widening it further
7755
+ * is a separate behaviour change.
7756
+ *
7757
+ * ## Why the DM dedup map is in scope, and is NOT a widening
7758
+ *
7759
+ * Wiping the flat map wipes the `__dm_notifications` / `__dm_notifications_pending`
7760
+ * keys along with everything else, because those records used to *live* there.
7761
+ * Clearing the flat map and not the dedicated map does not preserve DM state —
7762
+ * it **forks** it, in the one direction that is loudest:
7763
+ *
7764
+ * - an already-deployed client reads only the legacy keys, sees an empty bag,
7765
+ * and re-DMs the assignee of every block in the rebuilt flow;
7766
+ * - a new client reads the union, still sees the pre-rebuild records, and stays
7767
+ * silent.
7768
+ *
7769
+ * So the two generations disagree about who has been notified, which is the
7770
+ * exact split `dmNotificationState`'s dual-write exists to prevent. Clearing
7771
+ * both restores the pre-runs behaviour byte for byte: a full rebuild resets DM
7772
+ * dedup, and both generations agree that it did. `clearRuntimeForTemplateClone`
7773
+ * already clears both for the same reason.
7774
+ */
7775
+ declare function clearAllActionState(yDoc: Y.Doc): void;
7776
+ /**
7777
+ * Resolve every flat `runtime` entry against its run entry and **materialise
7778
+ * the winner into the run**. Returns the number of entries actually written.
7779
+ *
7780
+ * This is the writer half of the freshness contract, and the reason the doc
7781
+ * *converges* rather than merely reading correctly on each peer. Adoption is
7782
+ * **not absent-only**: skipping any key the run already has would make it dead
7783
+ * code the moment `initializeRuntime` seeds `{state:'idle'}` for every block,
7784
+ * and would strand every later flat write — an old tab completing a payment, a
7785
+ * not-yet-upgraded flow-manager finishing a claim, or the mirror of a container
7786
+ * that lost the concurrent-create race — outside the run forever.
7787
+ *
7788
+ * It is still **never a downgrade**: {@link resolveActionState}'s rule (a) means
7789
+ * a staler flat entry (an old tab re-seeding `idle` after a new tab completed
7790
+ * the block) loses, so nothing here can resurrect a pre-execution state on top
7791
+ * of a completed one and re-arm the auto-execute gate.
7792
+ *
7793
+ * **Idempotent by construction.** A materialised value is a copy of the flat
7794
+ * entry, so the next pass resolves the pair via the deterministic tiebreak
7795
+ * (rule (d)) back to `'run'` — no write, and a reported count of zero.
7796
+ *
7797
+ * ## THE ADOPTION GATE (§9.3) — **NOT discharged**
7798
+ *
7799
+ * **Gated, default OFF** — see {@link isLegacyRuntimeAdoptionEnabled} for the
7800
+ * full, cross-repo flip condition. While the gate is closed this is a pure no-op
7801
+ * returning `0`: it does not read, does not open a transaction, and does not
7802
+ * create the `actions` container. The gate is enforced here rather than at the
7803
+ * call sites so that no call site — present or future — can forget it.
7804
+ *
7805
+ * It was once declared discharged on the strength of a grep over `editor/src`.
7806
+ * That is the wrong scope: `flow-manager` is a live writer of flow runtime state
7807
+ * (§9.6), is pinned to a pre-runs editor, and still writes a flat-only `failed`
7808
+ * with no `executedAt` — which this predicate can never materialise. The two
7809
+ * things that keep the gate honest, and why neither alone is enough, are written
7810
+ * out at {@link isLegacyRuntimeAdoptionEnabled}: the flag covers the repos no
7811
+ * test here can see, the guard covers this one.
7812
+ *
7813
+ * - `no-runtime-writer-outside-waist.test.ts` greps the whole of `src/` and
7814
+ * fails on any runtime-map write outside this file's allowlist. Its allowlist
7815
+ * is per-line where feasible, and it must never gain an entry without a §9.3
7816
+ * argument.
7817
+ * - `adoption-live.repro.test.ts` pins the four originally-reproduced defects
7818
+ * (checkbox uncheck, reset-after-failed, read-back proof failure, 50 idempotent
7819
+ * passes) plus the stall — all with the gate explicitly **opened**, because
7820
+ * that is the only configuration in which they are reachable.
7821
+ *
7822
+ * `ensureRun` was never gated: an empty run container is harmless and
7823
+ * idempotent. It is *materialising stale winners* that has to wait.
7824
+ *
7825
+ * PHASE A COMPAT — REMOVAL TRIGGER: Phase B, once `writeActionState` no longer
7826
+ * mirrors to the flat map (compat register item 3).
7827
+ */
7828
+ declare function adoptLegacyRuntime(yDoc: Y.Doc, runId: string): number;
7829
+ /**
7830
+ * Subscribe to every change that can alter what {@link readActionState} returns
7831
+ * for any block. Returns the unsubscribe function.
7832
+ *
7833
+ * **Two sources, not one — this is the "block completed but UI still spinning"
7834
+ * trap.** The flat map is a *flat* `Y.Map`, so a shallow `observe` on it sees
7835
+ * every per-block write. `runs` is a *nested* container, so a shallow `observe`
7836
+ * on it fires only when a whole run is added or replaced — a change to
7837
+ * `runs[runId].actions[blockId]` would never reach the handler at all. That
7838
+ * failure presents as a block that completed in the doc while its UI keeps
7839
+ * spinning, which reads as a Matrix sync problem rather than a code bug, so it
7840
+ * is subscribed here in the waist instead of at each call site.
7841
+ *
7842
+ * - `observeDeep` on `runs` covers per-block action writes **and** the container
7843
+ * replacement that follows a losing concurrent-create merge.
7844
+ * - `observe` on the flat map covers an already-deployed client's write, so it
7845
+ * is visible immediately rather than waiting for an adoption pass.
7846
+ *
7847
+ * Both fire for a dual-write, so handlers must be cheap and idempotent — the
7848
+ * `shallowEqual` gate in `useNodeRuntime` is what keeps the extra fanout free.
7849
+ *
7850
+ * PHASE A COMPAT — REMOVAL TRIGGER: the flat-map subscription goes with the
7851
+ * mirror write and the read resolution (compat register items 1 and 2).
7852
+ */
7853
+ declare function subscribeToActionState(yDoc: Y.Doc, handler: () => void): () => void;
7854
+ /**
7855
+ * The session a surface should show, or `undefined` when the flow has none.
7856
+ *
7857
+ * `undefined` is a real answer, not a failure: a new flow has no session until
7858
+ * an actor starts one, and a legacy flow has none until it is migrated. Read
7859
+ * surfaces must render that state rather than substituting a run id — a
7860
+ * fabricated id is what made an unstarted flow display a phantom session.
7861
+ *
7862
+ * The pointer is advisory and is only honoured when it names a run that
7863
+ * actually exists, so a stale pointer (a cloned template, a deleted run) reads
7864
+ * as "no session" rather than as a missing container.
7865
+ */
7866
+ declare function resolveActiveRunId(yDoc?: Y.Doc): string | undefined;
7867
+ /**
7868
+ * The run id a **read** should resolve against, or `undefined` when there is
7869
+ * nothing to read.
7870
+ *
7871
+ * The read-side counterpart to {@link resolveRunIdForExecution}, which throws
7872
+ * rather than returning nothing — right for a write, wrong for a status panel
7873
+ * or a reference resolver, where "this flow has no session yet" is an ordinary
7874
+ * thing to render.
7875
+ *
7876
+ * A legacy, unmigrated document still has state to show: it lives in the flat
7877
+ * map, and the unsessioned id reaches it.
7878
+ */
7879
+ declare function resolveRunIdForRead(yDoc: Y.Doc, requestedRunId?: string): string | undefined;
7880
+ /**
7881
+ * `FlowRuntimeStateManager` over a run. Drop-in for `createYDocRuntimeManager`.
7882
+ *
7883
+ * **Throws rather than degrading.** `createRuntimeStateManager` silently
7884
+ * returns an in-memory `Map` when it cannot resolve a doc; under runs that
7885
+ * means the action executes, the side effect happens, and nothing persists — so
7886
+ * the next reader sees an un-run block and executes it again. A throw surfaces
7887
+ * as a failed block, which is recoverable; a silent memory manager is not.
7888
+ */
7889
+ declare function createRunScopedRuntimeManager(yDoc: Y.Doc, runId: string): FlowRuntimeStateManager;
7890
+ /**
7891
+ * Duck-typed `{ get(blockId) }` shim for `referenceResolver`'s `options.yRuntime`,
7892
+ * which only ever calls `.get(blockId)`. Returns `undefined` for an unknown
7893
+ * block, exactly as the flat `Y.Map` it replaces does, so every existing
7894
+ * `stored?.output` read behaves identically.
7895
+ *
7896
+ * Resolves from the doc on every `get` — the reader object may safely be
7897
+ * memoised, but the container it reads must not be.
7898
+ *
7899
+ * Uses the same {@link resolveActionState} predicate as {@link readActionState}:
7900
+ * a reference like `{{block.output.txHash}}` must see the same value the block's
7901
+ * own UI does, or a downstream action signs against a run entry that a stale
7902
+ * `idle` seed is hiding.
7903
+ *
7904
+ * PHASE A COMPAT — REMOVAL TRIGGER: compat register item 2.
7905
+ */
7906
+ declare function createRunRuntimeReader(yDoc: Y.Doc, runId: string): {
7907
+ get(blockId: string): FlowNodeRuntimeState | undefined;
7908
+ };
7909
+ /**
7910
+ * {@link createRunRuntimeReader} plus the `.doc` handle, for the `_yRuntime`
7911
+ * slot of a **synthetic editor** — the `{ _yDoc, _yRuntime, document }` object
7912
+ * `actionExecutor` and `readBackReconciler` fabricate when they are driven
7913
+ * headlessly from a Y.Doc.
7914
+ *
7915
+ * Two properties matter:
7916
+ *
7917
+ * 1. **Read-only.** There is no `set`. The headless write path goes through
7918
+ * {@link writeActionState} directly, so there is exactly one duck-typed
7919
+ * handle in the system and it cannot write. A synthetic `_yRuntime` that
7920
+ * was the raw flat `Y.Map` (what these call sites used before Ignition) is a
7921
+ * writer outside this waist by construction.
7922
+ * 2. **`.doc` is present**, because `editor._yRuntime?.doc` is an established
7923
+ * way to reach the Y.Doc in this repo (`useEntities.ts`, `DebugButton.tsx`),
7924
+ * and the shim must not be the thing that breaks it.
7925
+ *
7926
+ * PHASE A COMPAT — REMOVAL TRIGGER: compat register item 2, with the reader.
7927
+ */
7928
+ declare function createRunRuntimeReaderWithDoc(yDoc: Y.Doc, runId: string): {
7929
+ get(blockId: string): FlowNodeRuntimeState | undefined;
7930
+ doc: Y.Doc;
7931
+ };
7932
+
7933
+ /**
7934
+ * # Migrating a pre-session document
7935
+ *
7936
+ * Everything here exists to answer one question about records written before
7937
+ * sessions existed: **which session owns them?**
7938
+ *
7939
+ * The old answer was a hard-coded constant every repo agreed to read as "the
7940
+ * legacy run" (`sessionRunId ?? LEGACY_RUN_ID`). That put a document-shaped
7941
+ * fact in a string literal, so ownership was re-derived, identically and by
7942
+ * hand, in a dozen places across three repositories — and a record's owner
7943
+ * changed meaning if any one of them disagreed.
7944
+ *
7945
+ * Migration answers it once, in the data: every untagged record is stamped with
7946
+ * the id of the session that absorbs the document's history. Afterwards nothing
7947
+ * infers ownership, and no constant needs to survive.
7948
+ *
7949
+ * This is the only module that rewrites history, which is why it is separate
7950
+ * from the waist: `runs.ts` owns *action state*, and nothing there should learn
7951
+ * the shape of an agent lease or an invocation.
7952
+ */
7953
+ /** One counter per container touched, so a migration can report what it moved. */
7954
+ interface StampedRecordCounts {
7955
+ commands: number;
7956
+ leases: number;
7957
+ ledgerEvents: number;
7958
+ invocations: number;
7959
+ runRecords: number;
7960
+ }
7961
+
7962
+ type RunJsonValue = null | string | number | boolean | RunJsonObject | RunJsonValue[];
7963
+ interface RunJsonObject {
7964
+ [key: string]: RunJsonValue;
7965
+ }
7966
+ type LifecycleRunEventInput = {
7967
+ runId: string;
7968
+ kind: 'run.started';
7969
+ payload: {
7970
+ invocationCid?: string;
7971
+ definitionRevision?: string;
7972
+ label?: string;
7973
+ };
7974
+ idempotencyKey: string;
7975
+ ts?: number;
7976
+ blockId?: never;
7977
+ } | {
7978
+ runId: string;
7979
+ kind: 'run.closed';
7980
+ payload: {
7981
+ invocationCid?: string;
7982
+ summary?: RunJsonObject;
7983
+ };
7984
+ idempotencyKey: string;
7985
+ ts?: number;
7986
+ blockId?: never;
7987
+ } | {
7988
+ runId: string;
7989
+ kind: 'run.cancelled';
7990
+ payload: {
7991
+ invocationCid?: string;
7992
+ reason?: string;
7993
+ summary?: RunJsonObject;
7994
+ };
7995
+ idempotencyKey: string;
7996
+ ts?: number;
7997
+ blockId?: never;
7998
+ } | {
7999
+ runId: string;
8000
+ kind: 'definition.changed';
8001
+ payload: {
8002
+ revision: string;
8003
+ previousRevision?: string;
8004
+ changedBlockIds?: string[];
8005
+ summary?: string;
8006
+ };
8007
+ idempotencyKey: string;
8008
+ ts?: number;
8009
+ blockId?: never;
8010
+ };
8011
+ type ActionRunEventInput = {
8012
+ runId: string;
8013
+ blockId: string;
8014
+ kind: 'action.started';
8015
+ payload: {
8016
+ attempt: number;
8017
+ executionId?: string;
8018
+ invocationCid?: string;
8019
+ input?: RunJsonValue;
8020
+ };
8021
+ idempotencyKey: string;
8022
+ ts?: number;
8023
+ } | {
8024
+ runId: string;
8025
+ blockId: string;
8026
+ kind: 'action.output';
8027
+ payload: {
8028
+ attempt: number;
8029
+ executionId?: string;
8030
+ output: RunJsonValue;
8031
+ };
8032
+ idempotencyKey: string;
8033
+ ts?: number;
8034
+ } | {
8035
+ runId: string;
8036
+ blockId: string;
8037
+ kind: 'action.done';
8038
+ payload: {
8039
+ attempt: number;
8040
+ executionId?: string;
8041
+ durationMs?: number;
8042
+ output?: RunJsonValue;
8043
+ };
8044
+ idempotencyKey: string;
8045
+ ts?: number;
8046
+ } | {
8047
+ runId: string;
8048
+ blockId: string;
8049
+ kind: 'action.failed';
8050
+ payload: {
8051
+ attempt: number;
8052
+ executionId?: string;
8053
+ durationMs?: number;
8054
+ error: {
8055
+ message: string;
8056
+ name?: string;
8057
+ code?: string;
8058
+ retryable?: boolean;
8059
+ details?: RunJsonValue;
8060
+ };
8061
+ };
8062
+ idempotencyKey: string;
8063
+ ts?: number;
8064
+ };
8065
+ type RunLogEventInput = {
8066
+ runId: string;
8067
+ blockId?: string;
8068
+ kind: 'log';
8069
+ payload: {
8070
+ level: 'debug' | 'info' | 'warn' | 'error';
8071
+ message: string;
8072
+ data?: RunJsonValue;
8073
+ };
8074
+ idempotencyKey: string;
8075
+ ts?: number;
8076
+ };
8077
+ type RunEventInput = LifecycleRunEventInput | ActionRunEventInput | RunLogEventInput;
8078
+ /** Assignment-compatible with matrix-crdt's IRoomEventLog. */
8079
+ interface RunEventAppender {
8080
+ append(event: RunEventInput): Promise<string>;
8081
+ }
8082
+ type RunLifecycleCapability = 'flow/run.start' | 'flow/run.close';
8083
+ interface RunLifecycleAuthorizationRequest {
8084
+ can: RunLifecycleCapability;
8085
+ with: string;
8086
+ actorDid: string;
8087
+ runId?: string;
8088
+ }
8089
+ interface RunLifecycleAuthorizationDecision {
8090
+ allowed: boolean;
8091
+ reason?: string;
8092
+ invocationCid?: string;
8093
+ }
8094
+ type RunLifecycleAuthorizer = (request: RunLifecycleAuthorizationRequest) => Promise<RunLifecycleAuthorizationDecision> | RunLifecycleAuthorizationDecision;
8095
+ interface RunManifest {
8096
+ blockIds: string[];
8097
+ defHash: string;
8098
+ }
8099
+ interface RunDefinitionBlock {
8100
+ id?: string;
8101
+ type?: string;
8102
+ props?: Record<string, unknown>;
8103
+ children?: RunDefinitionBlock[];
8104
+ }
8105
+ interface RunDefinitionSnapshot {
8106
+ manifest: RunManifest;
8107
+ actionTypes: Record<string, string>;
8108
+ }
8109
+ interface RunSnapshot {
8110
+ id: string;
8111
+ meta: RunMeta;
8112
+ terminal?: RunTerminalRecord;
8113
+ }
8114
+ declare class RunLifecycleAuthorizationError extends Error {
8115
+ readonly capability: RunLifecycleCapability;
8116
+ constructor(capability: RunLifecycleCapability, message: string);
8117
+ }
8118
+ declare class RunNotReadyError extends Error {
8119
+ readonly incompleteBlockIds: string[];
8120
+ constructor(incompleteBlockIds: string[]);
8121
+ }
8122
+ /**
8123
+ * The flow predates sessions and has not been migrated, so it has no session to
8124
+ * act on. Thrown by `startRun` rather than quietly migrating on the caller's
8125
+ * behalf: migration is one-way and changes how every client reads the document,
8126
+ * which is a decision for an actor, not a side effect of pressing Start.
8127
+ */
8128
+ declare class FlowNotMigratedError extends Error {
8129
+ readonly flowUri: string;
8130
+ constructor(flowUri: string);
8131
+ }
8132
+ /**
8133
+ * The run exists but has no frozen manifest, so there is no definition to judge
8134
+ * completeness against.
8135
+ *
8136
+ * Reaching this means the run was created by something other than `startRun` or
8137
+ * `migrateFlowToSessions` — in practice a container left behind by a build that
8138
+ * created one on connect. Computing a summary against the *live* document
8139
+ * instead would let an unstarted flow report work as belonging to a session
8140
+ * nobody opened.
8141
+ */
8142
+ declare class RunNotMigratedError extends Error {
8143
+ readonly runId: string;
8144
+ constructor(runId: string);
8145
+ }
8146
+ declare function computeRunDefinitionHash(definition: unknown): string;
8147
+ /** Convert arbitrary action data into Matrix-event-safe JSON. */
8148
+ declare function toRunJsonValue(value: unknown): RunJsonValue;
8149
+ declare function buildRunDefinitionSnapshot(blocks: RunDefinitionBlock[], definition?: unknown): RunDefinitionSnapshot;
8150
+ declare function createRunUlid(timestamp?: number): string;
8151
+ declare function createRunId(seq: number, timestamp?: number): string;
8152
+ declare function listRuns(yDoc: Y.Doc): RunSnapshot[];
8153
+ declare function listOpenRuns(yDoc: Y.Doc): RunSnapshot[];
8154
+ declare function setAdvisoryActiveRunId(yDoc: Y.Doc, runId: string): void;
8155
+ interface StartRunParams {
8156
+ yDoc: Y.Doc;
8157
+ flowUri: string;
8158
+ actorDid: string;
8159
+ definition: RunDefinitionSnapshot;
8160
+ /** Live block tree used to dispatch authored `trigger: flow.start` actions. */
8161
+ document?: RunDefinitionBlock[];
8162
+ eventLog: RunEventAppender;
8163
+ authorize: RunLifecycleAuthorizer;
8164
+ label?: string;
8165
+ now?: () => number;
8166
+ }
8167
+ interface StartRunResult {
8168
+ run: RunSnapshot;
8169
+ eventId: string;
8170
+ flowStartInvocations: number;
8171
+ }
8172
+ declare function startRun(params: StartRunParams): Promise<StartRunResult>;
8173
+ interface MigrateFlowParams {
8174
+ yDoc: Y.Doc;
8175
+ flowUri: string;
8176
+ actorDid: string;
8177
+ /** Frozen into the migrated session, exactly as `startRun` freezes its own. */
8178
+ definition: RunDefinitionSnapshot;
8179
+ eventLog: RunEventAppender;
8180
+ authorize: RunLifecycleAuthorizer;
8181
+ label?: string;
8182
+ }
8183
+ interface MigrateFlowResult {
8184
+ /** The session that now owns the document's history, or `undefined` when
8185
+ * there was no history to carry and the document was simply latched. */
8186
+ run?: RunSnapshot;
8187
+ eventId?: string;
8188
+ seeded: MultiRunMigrationResult;
8189
+ stamped?: StampedRecordCounts;
8190
+ phantomCollected: boolean;
8191
+ alreadyMigrated: boolean;
8192
+ }
8193
+ /**
8194
+ * Turn a pre-session document into a session-based one, **one way**.
8195
+ *
8196
+ * What already happened in the flow becomes its first session: an ordinary open
8197
+ * run carrying the same action states, pending invocations and partial barriers,
8198
+ * closable and tickable like any other. A document with no history has nothing
8199
+ * to carry, so it is simply latched and the actor starts session 1 normally.
8200
+ *
8201
+ * ## Order matters
8202
+ *
8203
+ * The timeline event is appended **before** anything is written to the document,
8204
+ * exactly as `startRun` does it: a transient Matrix failure must leave the
8205
+ * document completely unchanged rather than latched onto a layout whose history
8206
+ * nobody can see. Everything after it is one transaction, so a document is
8207
+ * never observed half-migrated — history seeded but unlatched, or latched with
8208
+ * records still pointing nowhere.
8209
+ *
8210
+ * Idempotent. A second call sees the latch and returns `alreadyMigrated`.
8211
+ */
8212
+ declare function migrateFlowToSessions(params: MigrateFlowParams): Promise<MigrateFlowResult>;
8213
+ declare function computeRunSummary(yDoc: Y.Doc, runId: string, actionTypes: Record<string, string>, context: Omit<ActionRunContext, 'runId'>): Record<string, boolean>;
8214
+ interface CloseRunParams {
8215
+ yDoc: Y.Doc;
8216
+ flowUri: string;
8217
+ runId: string;
8218
+ actorDid: string;
8219
+ actionTypes: Record<string, string>;
8220
+ eventLog: RunEventAppender;
8221
+ authorize: RunLifecycleAuthorizer;
8222
+ allowIncomplete?: boolean;
8223
+ now?: () => number;
8224
+ }
8225
+ interface FinishRunResult {
8226
+ terminal: RunTerminalRecord;
8227
+ created: boolean;
8228
+ eventId?: string;
8229
+ }
8230
+ declare function closeRun(params: CloseRunParams): Promise<FinishRunResult>;
8231
+ interface CancelRunParams extends Omit<CloseRunParams, 'allowIncomplete'> {
8232
+ reason?: string;
8233
+ }
8234
+ declare function cancelRun(params: CancelRunParams): Promise<FinishRunResult>;
8235
+ interface RunDefinitionDrift {
8236
+ changed: boolean;
8237
+ previousRevision?: string;
8238
+ revision: string;
8239
+ changedBlockIds: string[];
8240
+ }
8241
+ declare function detectRunDefinitionDrift(yDoc: Y.Doc, runId: string, definition: RunDefinitionSnapshot): RunDefinitionDrift;
8242
+ declare function recordRunDefinitionDrift(yDoc: Y.Doc, runId: string, definition: RunDefinitionSnapshot, eventLog: RunEventAppender, now?: number): Promise<RunDefinitionDrift & {
8243
+ eventId?: string;
8244
+ }>;
8245
+ declare function readRunActionStates(yDoc: Y.Doc, runId: string, blockIds: string[]): Record<string, FlowNodeRuntimeState>;
8246
+
5762
8247
  /**
5763
8248
  * Capability types for UCAN-based authorization
5764
8249
  */
@@ -5866,6 +8351,10 @@ interface IxoCollaborativeEditorOptions extends IxoEditorOptions {
5866
8351
  user: IxoCollaborativeUser;
5867
8352
  matrixClient: MatrixClient;
5868
8353
  roomId: string;
8354
+ /** Explicit session used by lifecycle work for this editor surface. */
8355
+ sessionRunId?: string;
8356
+ /** Matrix-backed append surface for the run timeline. */
8357
+ runEventLog?: RunEventAppender;
5869
8358
  /**
5870
8359
  * User permissions for the collaborative document
5871
8360
  * @default { write: false }
@@ -5898,4 +8387,4 @@ interface IxoEditorConfig {
5898
8387
  tableHandles: boolean;
5899
8388
  }
5900
8389
 
5901
- export { type MatrixRoom as $, AuthzExecActionTypes as A, BlocknoteProvider as B, type VoteResponse as C, type DelegationChainValidationResult as D, type VoteInfo as E, type Vote as F, type User as G, type Addr as H, type InvocationStore as I, type Uint128 as J, type Expiration as K, type Status as L, type Threshold as M, type Votes as N, type CosmosMsgForEmpty as O, type ProposalResponse as P, type ProposalAction as Q, type ListProtocolDeedsWithTemplatesParams as R, type StoredDelegation as S, type Timestamp as T, type UcanDelegationStore as U, ValidatorActionType as V, type ProtocolDeedWithTemplates as W, type ProtocolTemplateSummary as X, type ImportProtocolTemplatesToSpaceParams as Y, type ImportProtocolTemplateResult as Z, type MatrixPrivacySettings as _, createMemoryUcanDelegationStore as a, type MatrixSpace as a0, type MatrixSubspace as a1, type MatrixSpaceStructure as a2, type Translate as a3, type FlowNodeRuntimeState as a4, type IxoEditorType as a5, type FlowMetadata as a6, type FlowNode as a7, type DID as a8, type ClaimCollectionURI as a9, type EvaluationStatus as aa, type LinkedClaim as ab, type FlowNodeAuthzExtension as ac, type NodeServiceReport as ad, type NodeState as ae, type ReadBackTerminalState as af, type ActionReadBackMetadata as ag, type FlowNodeBase as ah, type InvocationRequest as ai, type InvocationResult as aj, type ExecutionWithInvocationResult as ak, type FindProofsResult as al, type CreateRootDelegationParams as am, type CreateDelegationParams as an, type CreateInvocationParams as ao, type IxoBlockProps as ap, type VisualizationRenderer as aq, type DynamicListData as ar, type DynamicListDataProvider as as, type DynamicListPanelRenderer as at, type DomainCardRenderer as au, type DomainCardData as av, type UnlMapConfig as aw, createInvocationStore as b, createUcanDelegationStore as c, createMemoryInvocationStore as d, createUcanService as e, type UcanService as f, type UcanServiceConfig as g, type UcanServiceHandlers as h, type UcanCapability as i, type StoredInvocation as j, type DelegationGrant as k, type IxoEditorOptions as l, type IxoEditorTheme as m, type IxoEditorConfig as n, type IxoCollaborativeUser as o, type IxoCollaborativeEditorOptions as p, blockSpecs as q, getExtraSlashMenuItems as r, useBlocknoteHandlers as s, useTranslate as t, useBlocknoteContext as u, StakeType as v, type BlocknoteHandlers as w, type BlocknoteContextValue as x, type BlockRequirements as y, type SingleChoiceProposal as z };
8390
+ export { type ImportProtocolTemplateResult as $, AuthzExecActionTypes as A, BlocknoteProvider as B, type SingleChoiceProposal as C, type DelegationChainValidationResult as D, type VoteResponse as E, type FlowRuntimeStateManager as F, type VoteInfo as G, type Vote as H, type InvocationStore as I, type User as J, type Addr as K, type Uint128 as L, type Expiration as M, type Status as N, type Threshold as O, type ProposalResponse as P, type Votes as Q, type CosmosMsgForEmpty as R, type StoredDelegation as S, type Timestamp as T, type UcanDelegationStore as U, ValidatorActionType as V, type ProposalAction as W, type ListProtocolDeedsWithTemplatesParams as X, type ProtocolDeedWithTemplates as Y, type ProtocolTemplateSummary as Z, type ImportProtocolTemplatesToSpaceParams as _, createUcanDelegationStore as a, assertRunActionExecutionAllowed as a$, type MatrixPrivacySettings as a0, type MatrixRoom as a1, type MatrixSpace as a2, type MatrixSubspace as a3, type MatrixSpaceStructure as a4, type Translate as a5, type FlowNode as a6, type FlowNodeAuthzExtension as a7, type EvaluationStatus as a8, type IxoEditorType as a9, type FlowMetadata as aA, createYDocRuntimeManager as aB, clearRuntimeForTemplateClone as aC, LEGACY_RUN_STORAGE_VERSION as aD, MULTI_RUN_STORAGE_VERSION as aE, RUNS_TERMINAL_MAP_KEY as aF, RUN_STORAGE_VERSION_KEY as aG, adoptLegacyRuntime as aH, clearAllActionState as aI, collectPhantomLegacyRun as aJ, createRunRuntimeReader as aK, createRunRuntimeReaderWithDoc as aL, createRunScopedRuntimeManager as aM, deleteActionState as aN, enableMultiRunStorage as aO, ensureRun as aP, getRunActionsMap as aQ, getRunMeta as aR, getRunsMap as aS, getRunsTerminalMap as aT, getRunStorageVersion as aU, hasLegacyRuntimeHistory as aV, isLegacyRuntimeAdoptionEnabled as aW, isRecordInRun as aX, readActionState as aY, readActionStates as aZ, resetActionState as a_, type PendingInvocation as aa, type ActionServices as ab, type ActionHandlers as ac, type RunEventAppender as ad, type ActionResult as ae, type ActionDefinition as af, type FlowNodeRuntimeState as ag, type IxoBlockProps as ah, type VisualizationRenderer as ai, type DynamicListData as aj, type DynamicListDataProvider as ak, type DynamicListPanelRenderer as al, type DomainCardRenderer as am, type DomainCardData as an, type UnlMapConfig as ao, type ActionDoneContract as ap, type ActionEventDefinition as aq, type OutputSchemaField as ar, type RunEventInput as as, type RunJsonValue as at, type ActionRunContext as au, type CompletionCheck as av, type ActionReadBackMetadata as aw, type ReadBackTerminalState as ax, type ActionProofDeclaration as ay, type RunRecordDetails as az, createMemoryUcanDelegationStore as b, type CollectionService as b$, isBelowTheLineBlock as b0, resolveActiveRunId as b1, resolveRecordRunId as b2, resolveRunIdForExecution as b3, resolveRunIdForRead as b4, seedRunFromLegacyRuntime as b5, setMultiRunStorage as b6, subscribeToActionState as b7, usesLegacyRuntimeCompatibility as b8, writeActionState as b9, RunNotReadyError as bA, type CancelRunParams as bB, type CloseRunParams as bC, type ActionRunEventInput as bD, type FinishRunResult as bE, type MigrateFlowParams as bF, type MigrateFlowResult as bG, type LifecycleRunEventInput as bH, type RunDefinitionBlock as bI, type RunDefinitionDrift as bJ, type RunDefinitionSnapshot as bK, type RunJsonObject as bL, type RunLogEventInput as bM, type RunLifecycleAuthorizationDecision as bN, type RunLifecycleAuthorizationRequest as bO, type RunLifecycleAuthorizer as bP, type RunLifecycleCapability as bQ, type RunManifest as bR, type RunSnapshot as bS, type StartRunParams as bT, type StartRunResult as bU, type ActionContext as bV, type HttpService as bW, type EmailService as bX, type NotifyService as bY, type BidService as bZ, type ClaimService as b_, ExplicitRunRequiredError as ba, TerminalRunExecutionError as bb, UnknownRunError as bc, type RunMeta as bd, type MultiRunMigrationResult as be, type RunStorageVersion as bf, type RunTerminalRecord as bg, buildRunDefinitionSnapshot as bh, cancelRun as bi, closeRun as bj, computeRunDefinitionHash as bk, computeRunSummary as bl, createRunId as bm, createRunUlid as bn, detectRunDefinitionDrift as bo, listOpenRuns as bp, listRuns as bq, migrateFlowToSessions as br, readRunActionStates as bs, recordRunDefinitionDrift as bt, setAdvisoryActiveRunId as bu, startRun as bv, toRunJsonValue as bw, FlowNotMigratedError as bx, RunLifecycleAuthorizationError as by, RunNotMigratedError as bz, createRuntimeStateManager as c, type CollectionUsersService as c0, type MatrixCredentialService as c1, type IntegrationsService as c2, type OracleService as c3, type CarbonService as c4, type EntityService as c5, type FlowRunLifecycleService as c6, appendRunRecord as c7, readRunRecords as c8, getPendingInvocationsMap as c9, countPendingInvocations as ca, getOrCreateBlockPendingMap as cb, readPendingInvocations as cc, queuePendingInvocation as cd, removePendingInvocation as ce, findFailedListenersForSourceRun as cf, replayFailedListenerRun as cg, snapshotInputRefs as ch, computePendingInvocationId as ci, RUN_RECORD_AUDIT_TYPE as cj, type FailedListenerRun as ck, type DID as cl, type ClaimCollectionURI as cm, type LinkedClaim as cn, type NodeServiceReport as co, type NodeState as cp, type FlowNodeBase as cq, type InvocationRequest as cr, type InvocationResult as cs, type ExecutionWithInvocationResult as ct, type FindProofsResult as cu, type CreateRootDelegationParams as cv, type CreateDelegationParams as cw, type CreateInvocationParams as cx, createInvocationStore as d, createMemoryInvocationStore as e, createUcanService as f, type UcanService as g, type UcanServiceConfig as h, type UcanServiceHandlers as i, type UcanCapability as j, type StoredInvocation as k, type DelegationGrant as l, type IxoEditorOptions as m, type IxoEditorTheme as n, type IxoEditorConfig as o, type IxoCollaborativeUser as p, type IxoCollaborativeEditorOptions as q, blockSpecs as r, getExtraSlashMenuItems as s, useBlocknoteHandlers as t, useBlocknoteContext as u, useTranslate as v, StakeType as w, type BlocknoteHandlers as x, type BlocknoteContextValue as y, type BlockRequirements as z };