@ixo/editor 3.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1904,97 +1904,408 @@ registerDiffResolver("evaluateClaim", {
1904
1904
  }
1905
1905
  });
1906
1906
 
1907
- // src/core/lib/ucanDelegationStore.ts
1908
- var ROOT_DELEGATION_KEY = "__root__";
1909
- var STORE_VERSION_KEY = "__version__";
1910
- var CURRENT_VERSION = 2;
1911
- var isValidEntry = (value) => {
1912
- if (!value || typeof value !== "object") return false;
1913
- const entry = value;
1914
- return entry.v === CURRENT_VERSION && entry.data !== void 0;
1915
- };
1916
- var isReservedKey = (key) => key === ROOT_DELEGATION_KEY || key === STORE_VERSION_KEY;
1917
- var createUcanDelegationStore = (yMap) => {
1918
- const get = (cid) => {
1919
- if (isReservedKey(cid)) return null;
1920
- const raw = yMap.get(cid);
1921
- if (!raw) return null;
1922
- if (isValidEntry(raw)) return raw.data;
1923
- return null;
1924
- };
1925
- const set = (delegation) => {
1926
- const entry = { v: CURRENT_VERSION, data: delegation };
1927
- yMap.set(delegation.cid, entry);
1907
+ // src/core/services/ucanService.ts
1908
+ import {
1909
+ createDelegation as ucanCreateDelegation,
1910
+ createInvocation as ucanCreateInvocation,
1911
+ serializeDelegation,
1912
+ serializeInvocation,
1913
+ parseDelegation,
1914
+ parseSigner,
1915
+ signerFromMnemonic
1916
+ } from "@ixo/ucan";
1917
+ function toSupportedDID(did) {
1918
+ if (did.startsWith("did:ixo:") || did.startsWith("did:key:")) {
1919
+ return did;
1920
+ }
1921
+ return void 0;
1922
+ }
1923
+ function toUcantoCapabilities(capabilities) {
1924
+ return capabilities.map((cap) => ({
1925
+ can: cap.can,
1926
+ with: cap.with,
1927
+ ...cap.nb && { nb: cap.nb }
1928
+ }));
1929
+ }
1930
+ async function getSigner(handlers, did, didType, entityRoomId, pin) {
1931
+ const supportedDid = toSupportedDID(did);
1932
+ if (handlers.getPrivateKey) {
1933
+ const privateKey = await handlers.getPrivateKey({ did, didType, entityRoomId, pin });
1934
+ return parseSigner(privateKey, supportedDid);
1935
+ }
1936
+ if (handlers.getMnemonic) {
1937
+ const mnemonic = await handlers.getMnemonic({ did, didType, entityRoomId, pin });
1938
+ const result = await signerFromMnemonic(mnemonic, supportedDid);
1939
+ return result.signer;
1940
+ }
1941
+ throw new Error("No signer handler configured (need getPrivateKey or getMnemonic)");
1942
+ }
1943
+ function getCidFromDelegation(delegation) {
1944
+ return delegation.cid.toString();
1945
+ }
1946
+ var createUcanService = (config) => {
1947
+ const { delegationStore, invocationStore, handlers, flowOwnerDid } = config;
1948
+ const delegationCache = /* @__PURE__ */ new Map();
1949
+ const isConfigured = () => {
1950
+ const hasSessionHandlers = !!(handlers.createSignerSession && handlers.signWithSession);
1951
+ const hasLegacyHandlers = !!(handlers.getPrivateKey || handlers.getMnemonic);
1952
+ return hasSessionHandlers || hasLegacyHandlers;
1928
1953
  };
1929
- const remove = (cid) => {
1930
- yMap.delete(cid);
1954
+ const parseDelegationFromStore = async (cid) => {
1955
+ if (delegationCache.has(cid)) {
1956
+ return delegationCache.get(cid);
1957
+ }
1958
+ const stored = delegationStore.get(cid);
1959
+ if (!stored || !stored.delegation) {
1960
+ return null;
1961
+ }
1962
+ try {
1963
+ const delegation = await parseDelegation(stored.delegation);
1964
+ delegationCache.set(cid, delegation);
1965
+ return delegation;
1966
+ } catch {
1967
+ return null;
1968
+ }
1931
1969
  };
1932
- const has = (cid) => {
1933
- return yMap.has(cid) && !isReservedKey(cid);
1970
+ const getProofDelegations = async (proofCids) => {
1971
+ const proofs = [];
1972
+ for (const cid of proofCids) {
1973
+ const delegation = await parseDelegationFromStore(cid);
1974
+ if (delegation) {
1975
+ proofs.push(delegation);
1976
+ }
1977
+ }
1978
+ return proofs;
1934
1979
  };
1935
- const getRoot = () => {
1936
- const rootCid = yMap.get(ROOT_DELEGATION_KEY);
1937
- if (!rootCid) return null;
1938
- return get(rootCid);
1980
+ const createRootDelegation = async (params) => {
1981
+ const { flowOwnerDid: ownerDid, issuerType, entityRoomId, flowUri: uri, pin } = params;
1982
+ const signer = await getSigner(handlers, ownerDid, issuerType, entityRoomId, pin);
1983
+ const capabilities = [{ can: "flow/*", with: uri }];
1984
+ const delegation = await ucanCreateDelegation({
1985
+ issuer: signer,
1986
+ audience: ownerDid,
1987
+ capabilities,
1988
+ proofs: []
1989
+ });
1990
+ const serialized = await serializeDelegation(delegation);
1991
+ const cid = getCidFromDelegation(delegation);
1992
+ const storedDelegation = {
1993
+ cid,
1994
+ delegation: serialized,
1995
+ issuerDid: ownerDid,
1996
+ audienceDid: ownerDid,
1997
+ capabilities,
1998
+ createdAt: Date.now(),
1999
+ format: "car",
2000
+ proofCids: []
2001
+ };
2002
+ delegationStore.set(storedDelegation);
2003
+ delegationStore.setRootCid(cid);
2004
+ delegationCache.set(cid, delegation);
2005
+ return storedDelegation;
1939
2006
  };
1940
- const setRootCid = (cid) => {
1941
- yMap.set(ROOT_DELEGATION_KEY, cid);
2007
+ const createDelegation = async (params) => {
2008
+ const { issuerDid, issuerType, entityRoomId, audience, capabilities, proofs = [], expiration, pin } = params;
2009
+ const signer = await getSigner(handlers, issuerDid, issuerType, entityRoomId, pin);
2010
+ const proofCids = proofs.length > 0 ? proofs : [delegationStore.getRootCid()].filter(Boolean);
2011
+ const proofDelegations = await getProofDelegations(proofCids);
2012
+ const delegation = await ucanCreateDelegation({
2013
+ issuer: signer,
2014
+ audience,
2015
+ capabilities: toUcantoCapabilities(capabilities),
2016
+ proofs: proofDelegations,
2017
+ expiration: expiration ? Math.floor(expiration / 1e3) : void 0
2018
+ });
2019
+ const serialized = await serializeDelegation(delegation);
2020
+ const cid = getCidFromDelegation(delegation);
2021
+ const storedDelegation = {
2022
+ cid,
2023
+ delegation: serialized,
2024
+ issuerDid,
2025
+ audienceDid: audience,
2026
+ capabilities,
2027
+ expiration,
2028
+ createdAt: Date.now(),
2029
+ format: "car",
2030
+ proofCids
2031
+ };
2032
+ delegationStore.set(storedDelegation);
2033
+ delegationCache.set(cid, delegation);
2034
+ return storedDelegation;
1942
2035
  };
1943
- const getRootCid = () => {
1944
- return yMap.get(ROOT_DELEGATION_KEY) || null;
2036
+ const revokeDelegation = (cid) => {
2037
+ delegationStore.remove(cid);
2038
+ delegationCache.delete(cid);
1945
2039
  };
1946
- const getAll = () => {
1947
- const delegations = [];
1948
- yMap.forEach((value, key) => {
1949
- if (isReservedKey(key)) return;
1950
- if (isValidEntry(value)) {
1951
- delegations.push(value.data);
1952
- }
1953
- });
1954
- return delegations;
2040
+ const getDelegation = (cid) => {
2041
+ return delegationStore.get(cid);
1955
2042
  };
1956
- const getByAudience = (audienceDid) => {
1957
- return getAll().filter((d) => d.audienceDid === audienceDid);
2043
+ const getAllDelegations = () => {
2044
+ return delegationStore.getAll();
1958
2045
  };
1959
- const getByIssuer = (issuerDid) => {
1960
- return getAll().filter((d) => d.issuerDid === issuerDid);
2046
+ const getRootDelegation = () => {
2047
+ return delegationStore.getRoot();
1961
2048
  };
1962
- const findByCapability = (can, withUri) => {
1963
- return getAll().filter(
1964
- (d) => d.capabilities.some((c) => {
1965
- if (c.can === can && c.with === withUri) return true;
2049
+ const findValidProofs = async (audienceDid, capability) => {
2050
+ const delegations = delegationStore.getByAudience(audienceDid);
2051
+ if (delegations.length === 0) {
2052
+ const root = delegationStore.getRoot();
2053
+ if (root && root.audienceDid === audienceDid) {
2054
+ return { found: true, proofCids: [root.cid] };
2055
+ }
2056
+ return { found: false, error: "No delegations found for actor" };
2057
+ }
2058
+ for (const delegation of delegations) {
2059
+ const covers = delegation.capabilities.some((c) => {
2060
+ if (c.can === capability.can && c.with === capability.with) return true;
1966
2061
  if (c.can === "*" || c.can === "flow/*") return true;
1967
2062
  if (c.can.endsWith("/*")) {
1968
2063
  const prefix = c.can.slice(0, -1);
1969
- if (can.startsWith(prefix)) return true;
2064
+ if (capability.can.startsWith(prefix)) return true;
1970
2065
  }
1971
2066
  if (c.with === "*") return true;
1972
2067
  if (c.with.endsWith("*")) {
1973
2068
  const prefix = c.with.slice(0, -1);
1974
- if (withUri.startsWith(prefix)) return true;
2069
+ if (capability.with.startsWith(prefix)) return true;
1975
2070
  }
1976
2071
  return false;
1977
- })
1978
- );
2072
+ });
2073
+ if (covers) {
2074
+ if (delegation.expiration && delegation.expiration < Date.now()) {
2075
+ continue;
2076
+ }
2077
+ const proofCids = [delegation.cid, ...delegation.proofCids];
2078
+ return { found: true, proofCids };
2079
+ }
2080
+ }
2081
+ return { found: false, error: "No valid delegation found for capability" };
1979
2082
  };
1980
- return {
1981
- get,
1982
- set,
1983
- remove,
1984
- has,
1985
- getRoot,
1986
- setRootCid,
1987
- getRootCid,
1988
- getAll,
1989
- getByAudience,
1990
- getByIssuer,
1991
- findByCapability
2083
+ const validateDelegationChain = async (audienceDid, capability) => {
2084
+ const proofsResult = await findValidProofs(audienceDid, capability);
2085
+ if (!proofsResult.found || !proofsResult.proofCids) {
2086
+ return { valid: false, error: proofsResult.error };
2087
+ }
2088
+ const proofChain = [];
2089
+ for (const cid of proofsResult.proofCids) {
2090
+ const delegation = delegationStore.get(cid);
2091
+ if (!delegation) {
2092
+ return { valid: false, error: `Proof delegation ${cid} not found` };
2093
+ }
2094
+ proofChain.push(delegation);
2095
+ }
2096
+ for (let i = 0; i < proofChain.length - 1; i++) {
2097
+ const current = proofChain[i];
2098
+ const parent = proofChain[i + 1];
2099
+ if (parent.audienceDid !== current.issuerDid) {
2100
+ return {
2101
+ valid: false,
2102
+ error: `Chain broken: ${parent.cid} audience (${parent.audienceDid}) != ${current.cid} issuer (${current.issuerDid})`
2103
+ };
2104
+ }
2105
+ }
2106
+ const root = proofChain[proofChain.length - 1];
2107
+ if (root.issuerDid !== flowOwnerDid) {
2108
+ return { valid: false, error: `Root issuer ${root.issuerDid} is not flow owner ${flowOwnerDid}` };
2109
+ }
2110
+ return { valid: true, proofChain };
1992
2111
  };
1993
- };
1994
- var createMemoryUcanDelegationStore = () => {
1995
- const store = /* @__PURE__ */ new Map();
1996
- const get = (cid) => {
1997
- if (isReservedKey(cid)) return null;
2112
+ const createAndValidateInvocation = async (params, _flowId, _blockId) => {
2113
+ const { invokerDid, invokerType, entityRoomId, capability, proofs, pin } = params;
2114
+ const validation = await validateDelegationChain(invokerDid, capability);
2115
+ if (!validation.valid) {
2116
+ return {
2117
+ cid: "",
2118
+ invocation: "",
2119
+ valid: false,
2120
+ error: validation.error
2121
+ };
2122
+ }
2123
+ const signer = await getSigner(handlers, invokerDid, invokerType, entityRoomId, pin);
2124
+ const proofDelegations = await getProofDelegations(proofs);
2125
+ const ucantoCapability = {
2126
+ can: capability.can,
2127
+ with: capability.with,
2128
+ ...capability.nb && { nb: capability.nb }
2129
+ };
2130
+ const invocation = await ucanCreateInvocation({
2131
+ issuer: signer,
2132
+ audience: flowOwnerDid,
2133
+ capability: ucantoCapability,
2134
+ proofs: proofDelegations
2135
+ });
2136
+ const serialized = await serializeInvocation(invocation);
2137
+ const built = await invocation.buildIPLDView();
2138
+ const cid = built.cid.toString();
2139
+ return {
2140
+ cid,
2141
+ invocation: serialized,
2142
+ valid: true
2143
+ };
2144
+ };
2145
+ const executeWithInvocation = async (params, action, flowId, blockId) => {
2146
+ const invocationResult = await createAndValidateInvocation(params, flowId, blockId);
2147
+ if (!invocationResult.valid) {
2148
+ return {
2149
+ success: false,
2150
+ invocationCid: invocationResult.cid,
2151
+ error: invocationResult.error
2152
+ };
2153
+ }
2154
+ if (invocationStore.hasBeenInvoked(invocationResult.cid)) {
2155
+ return {
2156
+ success: false,
2157
+ invocationCid: invocationResult.cid,
2158
+ error: "Invocation has already been used (replay attack prevented)"
2159
+ };
2160
+ }
2161
+ try {
2162
+ const actionResult = await action();
2163
+ const storedInvocation = {
2164
+ cid: invocationResult.cid,
2165
+ invocation: invocationResult.invocation,
2166
+ invokerDid: params.invokerDid,
2167
+ capability: params.capability,
2168
+ executedAt: Date.now(),
2169
+ flowId,
2170
+ blockId,
2171
+ result: "success",
2172
+ proofCids: params.proofs
2173
+ };
2174
+ invocationStore.add(storedInvocation);
2175
+ return {
2176
+ success: true,
2177
+ invocationCid: invocationResult.cid,
2178
+ result: actionResult,
2179
+ actionResult
2180
+ };
2181
+ } catch (error) {
2182
+ const storedInvocation = {
2183
+ cid: invocationResult.cid,
2184
+ invocation: invocationResult.invocation,
2185
+ invokerDid: params.invokerDid,
2186
+ capability: params.capability,
2187
+ executedAt: Date.now(),
2188
+ flowId,
2189
+ blockId,
2190
+ result: "failure",
2191
+ error: error instanceof Error ? error.message : "Unknown error",
2192
+ proofCids: params.proofs
2193
+ };
2194
+ invocationStore.add(storedInvocation);
2195
+ return {
2196
+ success: false,
2197
+ invocationCid: invocationResult.cid,
2198
+ error: error instanceof Error ? error.message : "Unknown error"
2199
+ };
2200
+ }
2201
+ };
2202
+ return {
2203
+ createRootDelegation,
2204
+ createDelegation,
2205
+ revokeDelegation,
2206
+ getDelegation,
2207
+ getAllDelegations,
2208
+ getRootDelegation,
2209
+ createAndValidateInvocation,
2210
+ executeWithInvocation,
2211
+ validateDelegationChain,
2212
+ findValidProofs,
2213
+ parseDelegationFromStore,
2214
+ isConfigured
2215
+ };
2216
+ };
2217
+
2218
+ // src/core/lib/ucanDelegationStore.ts
2219
+ var ROOT_DELEGATION_KEY = "__root__";
2220
+ var STORE_VERSION_KEY = "__version__";
2221
+ var CURRENT_VERSION = 2;
2222
+ var isValidEntry = (value) => {
2223
+ if (!value || typeof value !== "object") return false;
2224
+ const entry = value;
2225
+ return entry.v === CURRENT_VERSION && entry.data !== void 0;
2226
+ };
2227
+ var isReservedKey = (key) => key === ROOT_DELEGATION_KEY || key === STORE_VERSION_KEY;
2228
+ var createUcanDelegationStore = (yMap) => {
2229
+ const get = (cid) => {
2230
+ if (isReservedKey(cid)) return null;
2231
+ const raw = yMap.get(cid);
2232
+ if (!raw) return null;
2233
+ if (isValidEntry(raw)) return raw.data;
2234
+ return null;
2235
+ };
2236
+ const set = (delegation) => {
2237
+ const entry = { v: CURRENT_VERSION, data: delegation };
2238
+ yMap.set(delegation.cid, entry);
2239
+ };
2240
+ const remove = (cid) => {
2241
+ yMap.delete(cid);
2242
+ };
2243
+ const has = (cid) => {
2244
+ return yMap.has(cid) && !isReservedKey(cid);
2245
+ };
2246
+ const getRoot = () => {
2247
+ const rootCid = yMap.get(ROOT_DELEGATION_KEY);
2248
+ if (!rootCid) return null;
2249
+ return get(rootCid);
2250
+ };
2251
+ const setRootCid = (cid) => {
2252
+ yMap.set(ROOT_DELEGATION_KEY, cid);
2253
+ };
2254
+ const getRootCid = () => {
2255
+ return yMap.get(ROOT_DELEGATION_KEY) || null;
2256
+ };
2257
+ const getAll = () => {
2258
+ const delegations = [];
2259
+ yMap.forEach((value, key) => {
2260
+ if (isReservedKey(key)) return;
2261
+ if (isValidEntry(value)) {
2262
+ delegations.push(value.data);
2263
+ }
2264
+ });
2265
+ return delegations;
2266
+ };
2267
+ const getByAudience = (audienceDid) => {
2268
+ return getAll().filter((d) => d.audienceDid === audienceDid);
2269
+ };
2270
+ const getByIssuer = (issuerDid) => {
2271
+ return getAll().filter((d) => d.issuerDid === issuerDid);
2272
+ };
2273
+ const findByCapability = (can, withUri) => {
2274
+ return getAll().filter(
2275
+ (d) => d.capabilities.some((c) => {
2276
+ if (c.can === can && c.with === withUri) return true;
2277
+ if (c.can === "*" || c.can === "flow/*") return true;
2278
+ if (c.can.endsWith("/*")) {
2279
+ const prefix = c.can.slice(0, -1);
2280
+ if (can.startsWith(prefix)) return true;
2281
+ }
2282
+ if (c.with === "*") return true;
2283
+ if (c.with.endsWith("*")) {
2284
+ const prefix = c.with.slice(0, -1);
2285
+ if (withUri.startsWith(prefix)) return true;
2286
+ }
2287
+ return false;
2288
+ })
2289
+ );
2290
+ };
2291
+ return {
2292
+ get,
2293
+ set,
2294
+ remove,
2295
+ has,
2296
+ getRoot,
2297
+ setRootCid,
2298
+ getRootCid,
2299
+ getAll,
2300
+ getByAudience,
2301
+ getByIssuer,
2302
+ findByCapability
2303
+ };
2304
+ };
2305
+ var createMemoryUcanDelegationStore = () => {
2306
+ const store = /* @__PURE__ */ new Map();
2307
+ const get = (cid) => {
2308
+ if (isReservedKey(cid)) return null;
1998
2309
  const raw = store.get(cid);
1999
2310
  if (!raw) return null;
2000
2311
  if (isValidEntry(raw)) return raw.data;
@@ -2341,473 +2652,372 @@ var isNodeActive = (node, runtime) => {
2341
2652
  if (!upstreamActor) {
2342
2653
  return { active: false, reason: "Upstream submission actor is unknown." };
2343
2654
  }
2344
- if (!upstreamState.lastInvocationCid) {
2345
- return { active: false, reason: "Upstream execution has no invocation proof." };
2346
- }
2347
- }
2348
- return { active: true };
2349
- };
2350
-
2351
- // src/core/lib/flowEngine/authorization.ts
2352
- var isAuthorized = async (blockId, actorDid, ucanService, flowUri) => {
2353
- const capability = {
2354
- can: "flow/block/execute",
2355
- with: `${flowUri}:${blockId}`
2356
- };
2357
- const result = await ucanService.validateDelegationChain(actorDid, capability);
2358
- if (!result.valid) {
2359
- return {
2360
- authorized: false,
2361
- reason: result.error || "No valid capability chain found"
2362
- };
2363
- }
2364
- const proofCids = result.proofChain?.map((d) => d.cid) || [];
2365
- return {
2366
- authorized: true,
2367
- capabilityId: proofCids[0],
2368
- proofCids
2369
- };
2370
- };
2371
-
2372
- // src/core/lib/flowEngine/executor.ts
2373
- var updateRuntimeAfterSuccess = (node, actorDid, runtime, actionResult, invocationCid, now) => {
2374
- const updates = {
2375
- submittedByDid: actionResult.submittedByDid || actorDid,
2376
- evaluationStatus: actionResult.evaluationStatus || "pending",
2377
- executionTimestamp: now ? now() : Date.now(),
2378
- lastInvocationCid: invocationCid
2379
- };
2380
- if (actionResult.claimId) {
2381
- updates.claimId = actionResult.claimId;
2382
- }
2383
- runtime.update(node.id, updates);
2384
- };
2385
- var executeNode = async ({ node, actorDid, actorType, entityRoomId, context, action, pin }) => {
2386
- const { runtime, ucanService, invocationStore, flowUri, flowId, now } = context;
2387
- const activation = isNodeActive(node, runtime);
2388
- if (!activation.active) {
2389
- return { success: false, stage: "activation", error: activation.reason };
2390
- }
2391
- const auth = await isAuthorized(node.id, actorDid, ucanService, flowUri);
2392
- if (!auth.authorized) {
2393
- return { success: false, stage: "authorization", error: auth.reason };
2394
- }
2395
- if (node.linkedClaim && !node.linkedClaim.collectionId) {
2396
- return { success: false, stage: "claim", error: "Linked claim collection is required but missing." };
2397
- }
2398
- let invocationCid;
2399
- let invocationData;
2400
- if (auth.proofCids && auth.proofCids.length > 0) {
2401
- const capability = {
2402
- can: "flow/block/execute",
2403
- with: `${flowUri}:${node.id}`
2404
- };
2405
- try {
2406
- const invocationResult = await ucanService.createAndValidateInvocation(
2407
- {
2408
- invokerDid: actorDid,
2409
- invokerType: actorType,
2410
- entityRoomId,
2411
- capability,
2412
- proofs: auth.proofCids,
2413
- pin
2414
- },
2415
- flowId,
2416
- node.id
2417
- );
2418
- if (!invocationResult.valid) {
2419
- return {
2420
- success: false,
2421
- stage: "authorization",
2422
- error: `Invocation validation failed: ${invocationResult.error}`
2423
- };
2424
- }
2425
- invocationCid = invocationResult.cid;
2426
- invocationData = invocationResult.invocation;
2427
- } catch (error) {
2428
- const message = error instanceof Error ? error.message : "Failed to create invocation";
2429
- return { success: false, stage: "authorization", error: message };
2430
- }
2431
- }
2432
- try {
2433
- const result = await action();
2434
- if (node.linkedClaim && !result.claimId) {
2435
- if (invocationStore && invocationCid && invocationData) {
2436
- const storedInvocation = {
2437
- cid: invocationCid,
2438
- invocation: invocationData,
2439
- invokerDid: actorDid,
2440
- capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2441
- executedAt: now ? now() : Date.now(),
2442
- flowId,
2443
- blockId: node.id,
2444
- result: "failure",
2445
- error: "Execution did not return a claimId for linked claim requirement.",
2446
- proofCids: auth.proofCids || []
2447
- };
2448
- invocationStore.add(storedInvocation);
2449
- }
2450
- return {
2451
- success: false,
2452
- stage: "claim",
2453
- error: "Execution did not return a claimId for linked claim requirement.",
2454
- invocationCid
2455
- };
2456
- }
2457
- if (invocationStore && invocationCid && invocationData) {
2458
- const storedInvocation = {
2459
- cid: invocationCid,
2460
- invocation: invocationData,
2461
- invokerDid: actorDid,
2462
- capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2463
- executedAt: now ? now() : Date.now(),
2464
- flowId,
2465
- blockId: node.id,
2466
- result: "success",
2467
- proofCids: auth.proofCids || [],
2468
- claimId: result.claimId
2469
- };
2470
- invocationStore.add(storedInvocation);
2471
- }
2472
- updateRuntimeAfterSuccess(node, actorDid, runtime, result, invocationCid || auth.capabilityId, now);
2473
- return {
2474
- success: true,
2475
- stage: "complete",
2476
- result,
2477
- capabilityId: auth.capabilityId,
2478
- invocationCid
2479
- };
2480
- } catch (error) {
2481
- const message = error instanceof Error ? error.message : "Execution failed";
2482
- if (invocationStore && invocationCid && invocationData) {
2483
- const storedInvocation = {
2484
- cid: invocationCid,
2485
- invocation: invocationData,
2486
- invokerDid: actorDid,
2487
- capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2488
- executedAt: now ? now() : Date.now(),
2489
- flowId,
2490
- blockId: node.id,
2491
- result: "failure",
2492
- error: message,
2493
- proofCids: auth.proofCids || []
2494
- };
2495
- invocationStore.add(storedInvocation);
2496
- }
2497
- return { success: false, stage: "action", error: message, invocationCid };
2498
- }
2499
- };
2500
-
2501
- // src/core/services/ucanService.ts
2502
- import {
2503
- createDelegation as ucanCreateDelegation,
2504
- createInvocation as ucanCreateInvocation,
2505
- serializeDelegation,
2506
- serializeInvocation,
2507
- parseDelegation,
2508
- parseSigner,
2509
- signerFromMnemonic
2510
- } from "@ixo/ucan";
2511
- function toSupportedDID(did) {
2512
- if (did.startsWith("did:ixo:") || did.startsWith("did:key:")) {
2513
- return did;
2514
- }
2515
- return void 0;
2516
- }
2517
- function toUcantoCapabilities(capabilities) {
2518
- return capabilities.map((cap) => ({
2519
- can: cap.can,
2520
- with: cap.with,
2521
- ...cap.nb && { nb: cap.nb }
2522
- }));
2523
- }
2524
- async function getSigner(handlers, did, didType, entityRoomId, pin) {
2525
- const supportedDid = toSupportedDID(did);
2526
- if (handlers.getPrivateKey) {
2527
- const privateKey = await handlers.getPrivateKey({ did, didType, entityRoomId, pin });
2528
- return parseSigner(privateKey, supportedDid);
2529
- }
2530
- if (handlers.getMnemonic) {
2531
- const mnemonic = await handlers.getMnemonic({ did, didType, entityRoomId, pin });
2532
- const result = await signerFromMnemonic(mnemonic, supportedDid);
2533
- return result.signer;
2534
- }
2535
- throw new Error("No signer handler configured (need getPrivateKey or getMnemonic)");
2536
- }
2537
- function getCidFromDelegation(delegation) {
2538
- return delegation.cid.toString();
2539
- }
2540
- var createUcanService = (config) => {
2541
- const { delegationStore, invocationStore, handlers, flowOwnerDid } = config;
2542
- const delegationCache = /* @__PURE__ */ new Map();
2543
- const isConfigured = () => {
2544
- const hasSessionHandlers = !!(handlers.createSignerSession && handlers.signWithSession);
2545
- const hasLegacyHandlers = !!(handlers.getPrivateKey || handlers.getMnemonic);
2546
- return hasSessionHandlers || hasLegacyHandlers;
2547
- };
2548
- const parseDelegationFromStore = async (cid) => {
2549
- if (delegationCache.has(cid)) {
2550
- return delegationCache.get(cid);
2551
- }
2552
- const stored = delegationStore.get(cid);
2553
- if (!stored || !stored.delegation) {
2554
- return null;
2555
- }
2556
- try {
2557
- const delegation = await parseDelegation(stored.delegation);
2558
- delegationCache.set(cid, delegation);
2559
- return delegation;
2560
- } catch {
2561
- return null;
2562
- }
2563
- };
2564
- const getProofDelegations = async (proofCids) => {
2565
- const proofs = [];
2566
- for (const cid of proofCids) {
2567
- const delegation = await parseDelegationFromStore(cid);
2568
- if (delegation) {
2569
- proofs.push(delegation);
2570
- }
2571
- }
2572
- return proofs;
2573
- };
2574
- const createRootDelegation = async (params) => {
2575
- const { flowOwnerDid: ownerDid, issuerType, entityRoomId, flowUri: uri, pin } = params;
2576
- const signer = await getSigner(handlers, ownerDid, issuerType, entityRoomId, pin);
2577
- const capabilities = [{ can: "flow/*", with: uri }];
2578
- const delegation = await ucanCreateDelegation({
2579
- issuer: signer,
2580
- audience: ownerDid,
2581
- capabilities,
2582
- proofs: []
2583
- });
2584
- const serialized = await serializeDelegation(delegation);
2585
- const cid = getCidFromDelegation(delegation);
2586
- const storedDelegation = {
2587
- cid,
2588
- delegation: serialized,
2589
- issuerDid: ownerDid,
2590
- audienceDid: ownerDid,
2591
- capabilities,
2592
- createdAt: Date.now(),
2593
- format: "car",
2594
- proofCids: []
2595
- };
2596
- delegationStore.set(storedDelegation);
2597
- delegationStore.setRootCid(cid);
2598
- delegationCache.set(cid, delegation);
2599
- return storedDelegation;
2600
- };
2601
- const createDelegation = async (params) => {
2602
- const { issuerDid, issuerType, entityRoomId, audience, capabilities, proofs = [], expiration, pin } = params;
2603
- const signer = await getSigner(handlers, issuerDid, issuerType, entityRoomId, pin);
2604
- const proofCids = proofs.length > 0 ? proofs : [delegationStore.getRootCid()].filter(Boolean);
2605
- const proofDelegations = await getProofDelegations(proofCids);
2606
- const delegation = await ucanCreateDelegation({
2607
- issuer: signer,
2608
- audience,
2609
- capabilities: toUcantoCapabilities(capabilities),
2610
- proofs: proofDelegations,
2611
- expiration: expiration ? Math.floor(expiration / 1e3) : void 0
2612
- });
2613
- const serialized = await serializeDelegation(delegation);
2614
- const cid = getCidFromDelegation(delegation);
2615
- const storedDelegation = {
2616
- cid,
2617
- delegation: serialized,
2618
- issuerDid,
2619
- audienceDid: audience,
2620
- capabilities,
2621
- expiration,
2622
- createdAt: Date.now(),
2623
- format: "car",
2624
- proofCids
2625
- };
2626
- delegationStore.set(storedDelegation);
2627
- delegationCache.set(cid, delegation);
2628
- return storedDelegation;
2629
- };
2630
- const revokeDelegation = (cid) => {
2631
- delegationStore.remove(cid);
2632
- delegationCache.delete(cid);
2633
- };
2634
- const getDelegation = (cid) => {
2635
- return delegationStore.get(cid);
2636
- };
2637
- const getAllDelegations = () => {
2638
- return delegationStore.getAll();
2639
- };
2640
- const getRootDelegation = () => {
2641
- return delegationStore.getRoot();
2642
- };
2643
- const findValidProofs = async (audienceDid, capability) => {
2644
- const delegations = delegationStore.getByAudience(audienceDid);
2645
- if (delegations.length === 0) {
2646
- const root = delegationStore.getRoot();
2647
- if (root && root.audienceDid === audienceDid) {
2648
- return { found: true, proofCids: [root.cid] };
2649
- }
2650
- return { found: false, error: "No delegations found for actor" };
2651
- }
2652
- for (const delegation of delegations) {
2653
- const covers = delegation.capabilities.some((c) => {
2654
- if (c.can === capability.can && c.with === capability.with) return true;
2655
- if (c.can === "*" || c.can === "flow/*") return true;
2656
- if (c.can.endsWith("/*")) {
2657
- const prefix = c.can.slice(0, -1);
2658
- if (capability.can.startsWith(prefix)) return true;
2659
- }
2660
- if (c.with === "*") return true;
2661
- if (c.with.endsWith("*")) {
2662
- const prefix = c.with.slice(0, -1);
2663
- if (capability.with.startsWith(prefix)) return true;
2664
- }
2665
- return false;
2666
- });
2667
- if (covers) {
2668
- if (delegation.expiration && delegation.expiration < Date.now()) {
2669
- continue;
2670
- }
2671
- const proofCids = [delegation.cid, ...delegation.proofCids];
2672
- return { found: true, proofCids };
2673
- }
2674
- }
2675
- return { found: false, error: "No valid delegation found for capability" };
2676
- };
2677
- const validateDelegationChain = async (audienceDid, capability) => {
2678
- const proofsResult = await findValidProofs(audienceDid, capability);
2679
- if (!proofsResult.found || !proofsResult.proofCids) {
2680
- return { valid: false, error: proofsResult.error };
2681
- }
2682
- const proofChain = [];
2683
- for (const cid of proofsResult.proofCids) {
2684
- const delegation = delegationStore.get(cid);
2685
- if (!delegation) {
2686
- return { valid: false, error: `Proof delegation ${cid} not found` };
2687
- }
2688
- proofChain.push(delegation);
2689
- }
2690
- for (let i = 0; i < proofChain.length - 1; i++) {
2691
- const current = proofChain[i];
2692
- const parent = proofChain[i + 1];
2693
- if (parent.audienceDid !== current.issuerDid) {
2694
- return {
2695
- valid: false,
2696
- error: `Chain broken: ${parent.cid} audience (${parent.audienceDid}) != ${current.cid} issuer (${current.issuerDid})`
2697
- };
2698
- }
2699
- }
2700
- const root = proofChain[proofChain.length - 1];
2701
- if (root.issuerDid !== flowOwnerDid) {
2702
- return { valid: false, error: `Root issuer ${root.issuerDid} is not flow owner ${flowOwnerDid}` };
2703
- }
2704
- return { valid: true, proofChain };
2705
- };
2706
- const createAndValidateInvocation = async (params, _flowId, _blockId) => {
2707
- const { invokerDid, invokerType, entityRoomId, capability, proofs, pin } = params;
2708
- const validation = await validateDelegationChain(invokerDid, capability);
2709
- if (!validation.valid) {
2710
- return {
2711
- cid: "",
2712
- invocation: "",
2713
- valid: false,
2714
- error: validation.error
2715
- };
2655
+ if (!upstreamState.lastInvocationCid) {
2656
+ return { active: false, reason: "Upstream execution has no invocation proof." };
2716
2657
  }
2717
- const signer = await getSigner(handlers, invokerDid, invokerType, entityRoomId, pin);
2718
- const proofDelegations = await getProofDelegations(proofs);
2719
- const ucantoCapability = {
2720
- can: capability.can,
2721
- with: capability.with,
2722
- ...capability.nb && { nb: capability.nb }
2658
+ }
2659
+ return { active: true };
2660
+ };
2661
+
2662
+ // src/core/lib/flowEngine/versionManifest.ts
2663
+ var VERSION_MANIFEST = {
2664
+ "0.3": {
2665
+ version: "0.3",
2666
+ label: "Legacy",
2667
+ ucanRequired: false,
2668
+ delegationRootRequired: false,
2669
+ whitelistOnlyAllowed: true,
2670
+ unrestrictedAllowed: true,
2671
+ executionPath: "legacy",
2672
+ authorizationFn: "v1",
2673
+ allowedAuthModes: ["anyone", "actors", "capability"],
2674
+ ui: {
2675
+ showDelegationPanel: false,
2676
+ showWhitelistConfig: true,
2677
+ showAnyoneConfig: true,
2678
+ showMigrationBanner: true,
2679
+ requirePinForExecution: false
2680
+ },
2681
+ description: "Legacy version. UCAN optional, whitelist-only authorization accepted."
2682
+ },
2683
+ "1.0.0": {
2684
+ version: "1.0.0",
2685
+ label: "UCAN Required",
2686
+ ucanRequired: true,
2687
+ delegationRootRequired: true,
2688
+ whitelistOnlyAllowed: false,
2689
+ unrestrictedAllowed: false,
2690
+ executionPath: "invocation",
2691
+ authorizationFn: "v2",
2692
+ allowedAuthModes: ["capability"],
2693
+ ui: {
2694
+ showDelegationPanel: true,
2695
+ showWhitelistConfig: false,
2696
+ showAnyoneConfig: false,
2697
+ showMigrationBanner: false,
2698
+ requirePinForExecution: true
2699
+ },
2700
+ description: "UCAN-enforced. Every block execution requires a valid delegation chain."
2701
+ }
2702
+ };
2703
+ var LATEST_VERSION = "1.0.0";
2704
+ function getVersionPolicy(version) {
2705
+ const policy = VERSION_MANIFEST[version];
2706
+ if (!policy) {
2707
+ return VERSION_MANIFEST[LATEST_VERSION];
2708
+ }
2709
+ return policy;
2710
+ }
2711
+
2712
+ // src/core/lib/flowEngine/authorization.ts
2713
+ var isAuthorized = async (blockId, actorDid, ucanService, flowUri, schemaVersion) => {
2714
+ const policy = schemaVersion ? getVersionPolicy(schemaVersion) : null;
2715
+ if (policy && !policy.ucanRequired) {
2716
+ return { authorized: true };
2717
+ }
2718
+ if (!ucanService) {
2719
+ if (!policy) {
2720
+ return { authorized: true };
2721
+ }
2722
+ return {
2723
+ authorized: false,
2724
+ reason: "UCAN service is not configured. This flow version requires UCAN authorization."
2723
2725
  };
2724
- const invocation = await ucanCreateInvocation({
2725
- issuer: signer,
2726
- audience: flowOwnerDid,
2727
- capability: ucantoCapability,
2728
- proofs: proofDelegations
2729
- });
2730
- const serialized = await serializeInvocation(invocation);
2731
- const built = await invocation.buildIPLDView();
2732
- const cid = built.cid.toString();
2726
+ }
2727
+ const capability = {
2728
+ can: "flow/block/execute",
2729
+ with: `${flowUri}:${blockId}`
2730
+ };
2731
+ const result = await ucanService.validateDelegationChain(actorDid, capability);
2732
+ if (!result.valid) {
2733
2733
  return {
2734
- cid,
2735
- invocation: serialized,
2736
- valid: true
2734
+ authorized: false,
2735
+ reason: result.error || "No valid capability chain found"
2737
2736
  };
2737
+ }
2738
+ const proofCids = result.proofChain?.map((d) => d.cid) || [];
2739
+ return {
2740
+ authorized: true,
2741
+ capabilityId: proofCids[0],
2742
+ proofCids
2738
2743
  };
2739
- const executeWithInvocation = async (params, action, flowId, blockId) => {
2740
- const invocationResult = await createAndValidateInvocation(params, flowId, blockId);
2741
- if (!invocationResult.valid) {
2742
- return {
2743
- success: false,
2744
- invocationCid: invocationResult.cid,
2745
- error: invocationResult.error
2746
- };
2744
+ };
2745
+
2746
+ // src/core/lib/flowEngine/executor.ts
2747
+ var updateRuntimeAfterSuccess = (node, actorDid, runtime, actionResult, invocationCid, now) => {
2748
+ const updates = {
2749
+ submittedByDid: actionResult.submittedByDid || actorDid,
2750
+ evaluationStatus: actionResult.evaluationStatus || "pending",
2751
+ executionTimestamp: now ? now() : Date.now(),
2752
+ lastInvocationCid: invocationCid
2753
+ };
2754
+ if (actionResult.claimId) {
2755
+ updates.claimId = actionResult.claimId;
2756
+ }
2757
+ runtime.update(node.id, updates);
2758
+ };
2759
+ var executeNode = async ({ node, actorDid, actorType, entityRoomId, context, action, pin }) => {
2760
+ const { runtime, ucanService, invocationStore, flowUri, flowId, schemaVersion, now } = context;
2761
+ const activation = isNodeActive(node, runtime);
2762
+ if (!activation.active) {
2763
+ return { success: false, stage: "activation", error: activation.reason };
2764
+ }
2765
+ const auth = await isAuthorized(node.id, actorDid, ucanService, flowUri, schemaVersion);
2766
+ if (!auth.authorized) {
2767
+ return { success: false, stage: "authorization", error: auth.reason };
2768
+ }
2769
+ if (node.linkedClaim && !node.linkedClaim.collectionId) {
2770
+ return { success: false, stage: "claim", error: "Linked claim collection is required but missing." };
2771
+ }
2772
+ let invocationCid;
2773
+ let invocationData;
2774
+ if (ucanService && auth.proofCids && auth.proofCids.length > 0) {
2775
+ const capability = {
2776
+ can: "flow/block/execute",
2777
+ with: `${flowUri}:${node.id}`
2778
+ };
2779
+ try {
2780
+ const invocationResult = await ucanService.createAndValidateInvocation(
2781
+ {
2782
+ invokerDid: actorDid,
2783
+ invokerType: actorType,
2784
+ entityRoomId,
2785
+ capability,
2786
+ proofs: auth.proofCids,
2787
+ pin
2788
+ },
2789
+ flowId,
2790
+ node.id
2791
+ );
2792
+ if (!invocationResult.valid) {
2793
+ return {
2794
+ success: false,
2795
+ stage: "authorization",
2796
+ error: `Invocation validation failed: ${invocationResult.error}`
2797
+ };
2798
+ }
2799
+ invocationCid = invocationResult.cid;
2800
+ invocationData = invocationResult.invocation;
2801
+ } catch (error) {
2802
+ const message = error instanceof Error ? error.message : "Failed to create invocation";
2803
+ return { success: false, stage: "authorization", error: message };
2747
2804
  }
2748
- if (invocationStore.hasBeenInvoked(invocationResult.cid)) {
2805
+ }
2806
+ try {
2807
+ const result = await action();
2808
+ if (node.linkedClaim && !result.claimId) {
2809
+ if (invocationStore && invocationCid && invocationData) {
2810
+ const storedInvocation = {
2811
+ cid: invocationCid,
2812
+ invocation: invocationData,
2813
+ invokerDid: actorDid,
2814
+ capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2815
+ executedAt: now ? now() : Date.now(),
2816
+ flowId,
2817
+ blockId: node.id,
2818
+ result: "failure",
2819
+ error: "Execution did not return a claimId for linked claim requirement.",
2820
+ proofCids: auth.proofCids || []
2821
+ };
2822
+ invocationStore.add(storedInvocation);
2823
+ }
2749
2824
  return {
2750
2825
  success: false,
2751
- invocationCid: invocationResult.cid,
2752
- error: "Invocation has already been used (replay attack prevented)"
2826
+ stage: "claim",
2827
+ error: "Execution did not return a claimId for linked claim requirement.",
2828
+ invocationCid
2753
2829
  };
2754
2830
  }
2755
- try {
2756
- const actionResult = await action();
2831
+ if (invocationStore && invocationCid && invocationData) {
2757
2832
  const storedInvocation = {
2758
- cid: invocationResult.cid,
2759
- invocation: invocationResult.invocation,
2760
- invokerDid: params.invokerDid,
2761
- capability: params.capability,
2762
- executedAt: Date.now(),
2833
+ cid: invocationCid,
2834
+ invocation: invocationData,
2835
+ invokerDid: actorDid,
2836
+ capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2837
+ executedAt: now ? now() : Date.now(),
2763
2838
  flowId,
2764
- blockId,
2839
+ blockId: node.id,
2765
2840
  result: "success",
2766
- proofCids: params.proofs
2841
+ proofCids: auth.proofCids || [],
2842
+ claimId: result.claimId
2767
2843
  };
2768
2844
  invocationStore.add(storedInvocation);
2769
- return {
2770
- success: true,
2771
- invocationCid: invocationResult.cid,
2772
- result: actionResult,
2773
- actionResult
2774
- };
2775
- } catch (error) {
2845
+ }
2846
+ updateRuntimeAfterSuccess(node, actorDid, runtime, result, invocationCid || auth.capabilityId, now);
2847
+ return {
2848
+ success: true,
2849
+ stage: "complete",
2850
+ result,
2851
+ capabilityId: auth.capabilityId,
2852
+ invocationCid
2853
+ };
2854
+ } catch (error) {
2855
+ const message = error instanceof Error ? error.message : "Execution failed";
2856
+ if (invocationStore && invocationCid && invocationData) {
2776
2857
  const storedInvocation = {
2777
- cid: invocationResult.cid,
2778
- invocation: invocationResult.invocation,
2779
- invokerDid: params.invokerDid,
2780
- capability: params.capability,
2781
- executedAt: Date.now(),
2858
+ cid: invocationCid,
2859
+ invocation: invocationData,
2860
+ invokerDid: actorDid,
2861
+ capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2862
+ executedAt: now ? now() : Date.now(),
2782
2863
  flowId,
2783
- blockId,
2864
+ blockId: node.id,
2784
2865
  result: "failure",
2785
- error: error instanceof Error ? error.message : "Unknown error",
2786
- proofCids: params.proofs
2866
+ error: message,
2867
+ proofCids: auth.proofCids || []
2787
2868
  };
2788
2869
  invocationStore.add(storedInvocation);
2789
- return {
2790
- success: false,
2791
- invocationCid: invocationResult.cid,
2792
- error: error instanceof Error ? error.message : "Unknown error"
2793
- };
2794
2870
  }
2795
- };
2796
- return {
2797
- createRootDelegation,
2798
- createDelegation,
2799
- revokeDelegation,
2800
- getDelegation,
2801
- getAllDelegations,
2802
- getRootDelegation,
2803
- createAndValidateInvocation,
2804
- executeWithInvocation,
2805
- validateDelegationChain,
2806
- findValidProofs,
2807
- parseDelegationFromStore,
2808
- isConfigured
2809
- };
2871
+ return { success: false, stage: "action", error: message, invocationCid };
2872
+ }
2873
+ };
2874
+
2875
+ // src/core/lib/flowEngine/migration.ts
2876
+ var MIGRATION_REGISTRY = {};
2877
+ function registerMigration(definition) {
2878
+ const key = `${definition.from}->${definition.to}`;
2879
+ MIGRATION_REGISTRY[key] = definition;
2880
+ }
2881
+
2882
+ // src/core/lib/flowEngine/migrations/v0_3_to_v1_0_0.ts
2883
+ var NON_EXECUTABLE_BLOCK_TYPES = /* @__PURE__ */ new Set(["paragraph", "heading", "bulletListItem", "numberedListItem", "image", "table"]);
2884
+ function hasDelegationForBlock(ctx, blockId) {
2885
+ const delegations = ctx.ucanService.getAllDelegations();
2886
+ const resourceUri = `${ctx.flowUri}:${blockId}`;
2887
+ return delegations.some((d) => d.capabilities.some((c) => c.can === "flow/block/execute" && c.with === resourceUri));
2888
+ }
2889
+ var migration_0_3_to_1_0_0 = {
2890
+ from: "0.3",
2891
+ to: "1.0.0",
2892
+ preconditions: [
2893
+ {
2894
+ id: "has_flow_owner",
2895
+ description: "Flow must have a flowOwnerDid set",
2896
+ check: (ctx) => {
2897
+ const ownerDid = ctx.editor.getFlowOwnerDid?.() || ctx.flowOwnerDid;
2898
+ return !!ownerDid;
2899
+ },
2900
+ blocking: true
2901
+ },
2902
+ {
2903
+ id: "is_owner",
2904
+ description: "Only the flow owner can initiate migration",
2905
+ check: (ctx) => {
2906
+ const ownerDid = ctx.editor.getFlowOwnerDid?.() || ctx.flowOwnerDid;
2907
+ return ctx.actorDid === ownerDid;
2908
+ },
2909
+ blocking: true
2910
+ },
2911
+ {
2912
+ id: "ucan_service_available",
2913
+ description: "UCAN service must be configured",
2914
+ check: (ctx) => {
2915
+ return !!ctx.ucanService && ctx.ucanService.isConfigured();
2916
+ },
2917
+ blocking: true
2918
+ }
2919
+ ],
2920
+ async analyze(ctx) {
2921
+ const items = [];
2922
+ const blocks = ctx.editor.document;
2923
+ const rootDelegation = ctx.ucanService.getRootDelegation();
2924
+ if (!rootDelegation) {
2925
+ items.push({
2926
+ id: "__root_delegation__",
2927
+ nodeId: "",
2928
+ type: "create_root_delegation",
2929
+ status: "pending",
2930
+ requiresUserAction: true,
2931
+ description: "Create root delegation for flow owner"
2932
+ });
2933
+ }
2934
+ if (blocks) {
2935
+ for (const block of blocks) {
2936
+ if (NON_EXECUTABLE_BLOCK_TYPES.has(block.type)) continue;
2937
+ if (!hasDelegationForBlock(ctx, block.id)) {
2938
+ items.push({
2939
+ id: `node_delegation_${block.id}`,
2940
+ nodeId: block.id,
2941
+ type: "create_node_delegation",
2942
+ status: "pending",
2943
+ requiresUserAction: true,
2944
+ description: `Create delegation for block "${block.type}" (${block.id})`
2945
+ });
2946
+ }
2947
+ }
2948
+ }
2949
+ return items;
2950
+ },
2951
+ async executeItem(ctx, item) {
2952
+ try {
2953
+ switch (item.type) {
2954
+ case "create_root_delegation": {
2955
+ await ctx.ucanService.createRootDelegation({
2956
+ flowOwnerDid: ctx.flowOwnerDid,
2957
+ issuerType: ctx.actorType,
2958
+ entityRoomId: ctx.entityRoomId,
2959
+ flowUri: ctx.flowUri,
2960
+ pin: ctx.pin
2961
+ });
2962
+ return { success: true };
2963
+ }
2964
+ case "create_node_delegation":
2965
+ case "backfill_capability": {
2966
+ const capability = {
2967
+ can: "flow/block/execute",
2968
+ with: `${ctx.flowUri}:${item.nodeId}`
2969
+ };
2970
+ await ctx.ucanService.createDelegation({
2971
+ issuerDid: ctx.flowOwnerDid,
2972
+ issuerType: ctx.actorType,
2973
+ entityRoomId: ctx.entityRoomId,
2974
+ audience: ctx.flowOwnerDid,
2975
+ // Owner delegates to self initially; actors get sub-delegations
2976
+ capabilities: [capability],
2977
+ pin: ctx.pin
2978
+ });
2979
+ return { success: true };
2980
+ }
2981
+ default:
2982
+ return { success: false, error: `Unknown work item type: ${item.type}` };
2983
+ }
2984
+ } catch (err) {
2985
+ const message = err instanceof Error ? err.message : String(err);
2986
+ return { success: false, error: message };
2987
+ }
2988
+ },
2989
+ async postValidate(ctx) {
2990
+ const errors = [];
2991
+ const blocks = ctx.editor.document;
2992
+ const rootDelegation = ctx.ucanService.getRootDelegation();
2993
+ if (!rootDelegation) {
2994
+ errors.push("Root delegation is missing after migration");
2995
+ }
2996
+ if (blocks) {
2997
+ for (const block of blocks) {
2998
+ if (NON_EXECUTABLE_BLOCK_TYPES.has(block.type)) continue;
2999
+ const requiredCapability = {
3000
+ can: "flow/block/execute",
3001
+ with: `${ctx.flowUri}:${block.id}`
3002
+ };
3003
+ const validation = await ctx.ucanService.validateDelegationChain(ctx.flowOwnerDid, requiredCapability);
3004
+ if (!validation.valid) {
3005
+ errors.push(`Block "${block.type}" (${block.id}): delegation chain invalid \u2014 ${validation.error || "unknown error"}`);
3006
+ }
3007
+ }
3008
+ }
3009
+ return { valid: errors.length === 0, errors };
3010
+ },
3011
+ finalize(ctx) {
3012
+ const root = ctx.editor._yRoot;
3013
+ if (!root) {
3014
+ throw new Error("Cannot finalize: editor _yRoot not available");
3015
+ }
3016
+ root.set("schema_version", "1.0.0");
3017
+ root.set("@context", "https://ixo.world/flow/1.0");
3018
+ }
2810
3019
  };
3020
+ registerMigration(migration_0_3_to_1_0_0);
2811
3021
 
2812
3022
  export {
2813
3023
  resolveActionType,
@@ -2832,17 +3042,18 @@ export {
2832
3042
  didToMatrixUserId,
2833
3043
  findOrCreateDMRoom,
2834
3044
  sendDirectMessage,
3045
+ createUcanService,
2835
3046
  createUcanDelegationStore,
2836
3047
  createMemoryUcanDelegationStore,
2837
3048
  createInvocationStore,
2838
3049
  createMemoryInvocationStore,
3050
+ LATEST_VERSION,
2839
3051
  buildAuthzFromProps,
2840
3052
  buildFlowNodeFromBlock,
2841
3053
  createRuntimeStateManager,
2842
3054
  clearRuntimeForTemplateClone,
2843
3055
  isNodeActive,
2844
3056
  isAuthorized,
2845
- executeNode,
2846
- createUcanService
3057
+ executeNode
2847
3058
  };
2848
- //# sourceMappingURL=chunk-5D26UG3I.mjs.map
3059
+ //# sourceMappingURL=chunk-F2JSGDES.mjs.map