@ixo/editor 3.2.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;
@@ -2346,523 +2657,219 @@ var isNodeActive = (node, runtime) => {
2346
2657
  }
2347
2658
  }
2348
2659
  return { active: true };
2349
- };
2350
-
2351
- // src/core/lib/flowEngine/versionManifest.ts
2352
- var VERSION_MANIFEST = {
2353
- "0.3": {
2354
- version: "0.3",
2355
- label: "Legacy",
2356
- ucanRequired: false,
2357
- delegationRootRequired: false,
2358
- whitelistOnlyAllowed: true,
2359
- unrestrictedAllowed: true,
2360
- executionPath: "legacy",
2361
- authorizationFn: "v1",
2362
- allowedAuthModes: ["anyone", "actors", "capability"],
2363
- ui: {
2364
- showDelegationPanel: false,
2365
- showWhitelistConfig: true,
2366
- showAnyoneConfig: true,
2367
- showMigrationBanner: true,
2368
- requirePinForExecution: false
2369
- },
2370
- description: "Legacy version. UCAN optional, whitelist-only authorization accepted."
2371
- },
2372
- "1.0.0": {
2373
- version: "1.0.0",
2374
- label: "UCAN Required",
2375
- ucanRequired: true,
2376
- delegationRootRequired: true,
2377
- whitelistOnlyAllowed: false,
2378
- unrestrictedAllowed: false,
2379
- executionPath: "invocation",
2380
- authorizationFn: "v2",
2381
- allowedAuthModes: ["capability"],
2382
- ui: {
2383
- showDelegationPanel: true,
2384
- showWhitelistConfig: false,
2385
- showAnyoneConfig: false,
2386
- showMigrationBanner: false,
2387
- requirePinForExecution: true
2388
- },
2389
- description: "UCAN-enforced. Every block execution requires a valid delegation chain."
2390
- }
2391
- };
2392
- var LATEST_VERSION = "1.0.0";
2393
- function getVersionPolicy(version) {
2394
- const policy = VERSION_MANIFEST[version];
2395
- if (!policy) {
2396
- return VERSION_MANIFEST[LATEST_VERSION];
2397
- }
2398
- return policy;
2399
- }
2400
-
2401
- // src/core/lib/flowEngine/authorization.ts
2402
- var isAuthorized = async (blockId, actorDid, ucanService, flowUri, schemaVersion) => {
2403
- if (schemaVersion) {
2404
- const policy = getVersionPolicy(schemaVersion);
2405
- if (!policy.ucanRequired) {
2406
- return { authorized: true };
2407
- }
2408
- }
2409
- const capability = {
2410
- can: "flow/block/execute",
2411
- with: `${flowUri}:${blockId}`
2412
- };
2413
- const result = await ucanService.validateDelegationChain(actorDid, capability);
2414
- if (!result.valid) {
2415
- return {
2416
- authorized: false,
2417
- reason: result.error || "No valid capability chain found"
2418
- };
2419
- }
2420
- const proofCids = result.proofChain?.map((d) => d.cid) || [];
2421
- return {
2422
- authorized: true,
2423
- capabilityId: proofCids[0],
2424
- proofCids
2425
- };
2426
- };
2427
-
2428
- // src/core/lib/flowEngine/executor.ts
2429
- var updateRuntimeAfterSuccess = (node, actorDid, runtime, actionResult, invocationCid, now) => {
2430
- const updates = {
2431
- submittedByDid: actionResult.submittedByDid || actorDid,
2432
- evaluationStatus: actionResult.evaluationStatus || "pending",
2433
- executionTimestamp: now ? now() : Date.now(),
2434
- lastInvocationCid: invocationCid
2435
- };
2436
- if (actionResult.claimId) {
2437
- updates.claimId = actionResult.claimId;
2438
- }
2439
- runtime.update(node.id, updates);
2440
- };
2441
- var executeNode = async ({ node, actorDid, actorType, entityRoomId, context, action, pin }) => {
2442
- const { runtime, ucanService, invocationStore, flowUri, flowId, now } = context;
2443
- const activation = isNodeActive(node, runtime);
2444
- if (!activation.active) {
2445
- return { success: false, stage: "activation", error: activation.reason };
2446
- }
2447
- const auth = await isAuthorized(node.id, actorDid, ucanService, flowUri);
2448
- if (!auth.authorized) {
2449
- return { success: false, stage: "authorization", error: auth.reason };
2450
- }
2451
- if (node.linkedClaim && !node.linkedClaim.collectionId) {
2452
- return { success: false, stage: "claim", error: "Linked claim collection is required but missing." };
2453
- }
2454
- let invocationCid;
2455
- let invocationData;
2456
- if (auth.proofCids && auth.proofCids.length > 0) {
2457
- const capability = {
2458
- can: "flow/block/execute",
2459
- with: `${flowUri}:${node.id}`
2460
- };
2461
- try {
2462
- const invocationResult = await ucanService.createAndValidateInvocation(
2463
- {
2464
- invokerDid: actorDid,
2465
- invokerType: actorType,
2466
- entityRoomId,
2467
- capability,
2468
- proofs: auth.proofCids,
2469
- pin
2470
- },
2471
- flowId,
2472
- node.id
2473
- );
2474
- if (!invocationResult.valid) {
2475
- return {
2476
- success: false,
2477
- stage: "authorization",
2478
- error: `Invocation validation failed: ${invocationResult.error}`
2479
- };
2480
- }
2481
- invocationCid = invocationResult.cid;
2482
- invocationData = invocationResult.invocation;
2483
- } catch (error) {
2484
- const message = error instanceof Error ? error.message : "Failed to create invocation";
2485
- return { success: false, stage: "authorization", error: message };
2486
- }
2487
- }
2488
- try {
2489
- const result = await action();
2490
- if (node.linkedClaim && !result.claimId) {
2491
- if (invocationStore && invocationCid && invocationData) {
2492
- const storedInvocation = {
2493
- cid: invocationCid,
2494
- invocation: invocationData,
2495
- invokerDid: actorDid,
2496
- capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2497
- executedAt: now ? now() : Date.now(),
2498
- flowId,
2499
- blockId: node.id,
2500
- result: "failure",
2501
- error: "Execution did not return a claimId for linked claim requirement.",
2502
- proofCids: auth.proofCids || []
2503
- };
2504
- invocationStore.add(storedInvocation);
2505
- }
2506
- return {
2507
- success: false,
2508
- stage: "claim",
2509
- error: "Execution did not return a claimId for linked claim requirement.",
2510
- invocationCid
2511
- };
2512
- }
2513
- if (invocationStore && invocationCid && invocationData) {
2514
- const storedInvocation = {
2515
- cid: invocationCid,
2516
- invocation: invocationData,
2517
- invokerDid: actorDid,
2518
- capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2519
- executedAt: now ? now() : Date.now(),
2520
- flowId,
2521
- blockId: node.id,
2522
- result: "success",
2523
- proofCids: auth.proofCids || [],
2524
- claimId: result.claimId
2525
- };
2526
- invocationStore.add(storedInvocation);
2527
- }
2528
- updateRuntimeAfterSuccess(node, actorDid, runtime, result, invocationCid || auth.capabilityId, now);
2529
- return {
2530
- success: true,
2531
- stage: "complete",
2532
- result,
2533
- capabilityId: auth.capabilityId,
2534
- invocationCid
2535
- };
2536
- } catch (error) {
2537
- const message = error instanceof Error ? error.message : "Execution failed";
2538
- if (invocationStore && invocationCid && invocationData) {
2539
- const storedInvocation = {
2540
- cid: invocationCid,
2541
- invocation: invocationData,
2542
- invokerDid: actorDid,
2543
- capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
2544
- executedAt: now ? now() : Date.now(),
2545
- flowId,
2546
- blockId: node.id,
2547
- result: "failure",
2548
- error: message,
2549
- proofCids: auth.proofCids || []
2550
- };
2551
- invocationStore.add(storedInvocation);
2552
- }
2553
- return { success: false, stage: "action", error: message, invocationCid };
2554
- }
2555
- };
2556
-
2557
- // src/core/services/ucanService.ts
2558
- import {
2559
- createDelegation as ucanCreateDelegation,
2560
- createInvocation as ucanCreateInvocation,
2561
- serializeDelegation,
2562
- serializeInvocation,
2563
- parseDelegation,
2564
- parseSigner,
2565
- signerFromMnemonic
2566
- } from "@ixo/ucan";
2567
- function toSupportedDID(did) {
2568
- if (did.startsWith("did:ixo:") || did.startsWith("did:key:")) {
2569
- return did;
2570
- }
2571
- return void 0;
2572
- }
2573
- function toUcantoCapabilities(capabilities) {
2574
- return capabilities.map((cap) => ({
2575
- can: cap.can,
2576
- with: cap.with,
2577
- ...cap.nb && { nb: cap.nb }
2578
- }));
2579
- }
2580
- async function getSigner(handlers, did, didType, entityRoomId, pin) {
2581
- const supportedDid = toSupportedDID(did);
2582
- if (handlers.getPrivateKey) {
2583
- const privateKey = await handlers.getPrivateKey({ did, didType, entityRoomId, pin });
2584
- return parseSigner(privateKey, supportedDid);
2585
- }
2586
- if (handlers.getMnemonic) {
2587
- const mnemonic = await handlers.getMnemonic({ did, didType, entityRoomId, pin });
2588
- const result = await signerFromMnemonic(mnemonic, supportedDid);
2589
- return result.signer;
2590
- }
2591
- throw new Error("No signer handler configured (need getPrivateKey or getMnemonic)");
2592
- }
2593
- function getCidFromDelegation(delegation) {
2594
- return delegation.cid.toString();
2595
- }
2596
- var createUcanService = (config) => {
2597
- const { delegationStore, invocationStore, handlers, flowOwnerDid } = config;
2598
- const delegationCache = /* @__PURE__ */ new Map();
2599
- const isConfigured = () => {
2600
- const hasSessionHandlers = !!(handlers.createSignerSession && handlers.signWithSession);
2601
- const hasLegacyHandlers = !!(handlers.getPrivateKey || handlers.getMnemonic);
2602
- return hasSessionHandlers || hasLegacyHandlers;
2603
- };
2604
- const parseDelegationFromStore = async (cid) => {
2605
- if (delegationCache.has(cid)) {
2606
- return delegationCache.get(cid);
2607
- }
2608
- const stored = delegationStore.get(cid);
2609
- if (!stored || !stored.delegation) {
2610
- return null;
2611
- }
2612
- try {
2613
- const delegation = await parseDelegation(stored.delegation);
2614
- delegationCache.set(cid, delegation);
2615
- return delegation;
2616
- } catch {
2617
- return null;
2618
- }
2619
- };
2620
- const getProofDelegations = async (proofCids) => {
2621
- const proofs = [];
2622
- for (const cid of proofCids) {
2623
- const delegation = await parseDelegationFromStore(cid);
2624
- if (delegation) {
2625
- proofs.push(delegation);
2626
- }
2627
- }
2628
- return proofs;
2629
- };
2630
- const createRootDelegation = async (params) => {
2631
- const { flowOwnerDid: ownerDid, issuerType, entityRoomId, flowUri: uri, pin } = params;
2632
- const signer = await getSigner(handlers, ownerDid, issuerType, entityRoomId, pin);
2633
- const capabilities = [{ can: "flow/*", with: uri }];
2634
- const delegation = await ucanCreateDelegation({
2635
- issuer: signer,
2636
- audience: ownerDid,
2637
- capabilities,
2638
- proofs: []
2639
- });
2640
- const serialized = await serializeDelegation(delegation);
2641
- const cid = getCidFromDelegation(delegation);
2642
- const storedDelegation = {
2643
- cid,
2644
- delegation: serialized,
2645
- issuerDid: ownerDid,
2646
- audienceDid: ownerDid,
2647
- capabilities,
2648
- createdAt: Date.now(),
2649
- format: "car",
2650
- proofCids: []
2651
- };
2652
- delegationStore.set(storedDelegation);
2653
- delegationStore.setRootCid(cid);
2654
- delegationCache.set(cid, delegation);
2655
- return storedDelegation;
2656
- };
2657
- const createDelegation = async (params) => {
2658
- const { issuerDid, issuerType, entityRoomId, audience, capabilities, proofs = [], expiration, pin } = params;
2659
- const signer = await getSigner(handlers, issuerDid, issuerType, entityRoomId, pin);
2660
- const proofCids = proofs.length > 0 ? proofs : [delegationStore.getRootCid()].filter(Boolean);
2661
- const proofDelegations = await getProofDelegations(proofCids);
2662
- const delegation = await ucanCreateDelegation({
2663
- issuer: signer,
2664
- audience,
2665
- capabilities: toUcantoCapabilities(capabilities),
2666
- proofs: proofDelegations,
2667
- expiration: expiration ? Math.floor(expiration / 1e3) : void 0
2668
- });
2669
- const serialized = await serializeDelegation(delegation);
2670
- const cid = getCidFromDelegation(delegation);
2671
- const storedDelegation = {
2672
- cid,
2673
- delegation: serialized,
2674
- issuerDid,
2675
- audienceDid: audience,
2676
- capabilities,
2677
- expiration,
2678
- createdAt: Date.now(),
2679
- format: "car",
2680
- proofCids
2681
- };
2682
- delegationStore.set(storedDelegation);
2683
- delegationCache.set(cid, delegation);
2684
- return storedDelegation;
2685
- };
2686
- const revokeDelegation = (cid) => {
2687
- delegationStore.remove(cid);
2688
- delegationCache.delete(cid);
2689
- };
2690
- const getDelegation = (cid) => {
2691
- return delegationStore.get(cid);
2692
- };
2693
- const getAllDelegations = () => {
2694
- return delegationStore.getAll();
2695
- };
2696
- const getRootDelegation = () => {
2697
- return delegationStore.getRoot();
2698
- };
2699
- const findValidProofs = async (audienceDid, capability) => {
2700
- const delegations = delegationStore.getByAudience(audienceDid);
2701
- if (delegations.length === 0) {
2702
- const root = delegationStore.getRoot();
2703
- if (root && root.audienceDid === audienceDid) {
2704
- return { found: true, proofCids: [root.cid] };
2705
- }
2706
- return { found: false, error: "No delegations found for actor" };
2707
- }
2708
- for (const delegation of delegations) {
2709
- const covers = delegation.capabilities.some((c) => {
2710
- if (c.can === capability.can && c.with === capability.with) return true;
2711
- if (c.can === "*" || c.can === "flow/*") return true;
2712
- if (c.can.endsWith("/*")) {
2713
- const prefix = c.can.slice(0, -1);
2714
- if (capability.can.startsWith(prefix)) return true;
2715
- }
2716
- if (c.with === "*") return true;
2717
- if (c.with.endsWith("*")) {
2718
- const prefix = c.with.slice(0, -1);
2719
- if (capability.with.startsWith(prefix)) return true;
2720
- }
2721
- return false;
2722
- });
2723
- if (covers) {
2724
- if (delegation.expiration && delegation.expiration < Date.now()) {
2725
- continue;
2726
- }
2727
- const proofCids = [delegation.cid, ...delegation.proofCids];
2728
- return { found: true, proofCids };
2729
- }
2730
- }
2731
- return { found: false, error: "No valid delegation found for capability" };
2732
- };
2733
- const validateDelegationChain = async (audienceDid, capability) => {
2734
- const proofsResult = await findValidProofs(audienceDid, capability);
2735
- if (!proofsResult.found || !proofsResult.proofCids) {
2736
- return { valid: false, error: proofsResult.error };
2737
- }
2738
- const proofChain = [];
2739
- for (const cid of proofsResult.proofCids) {
2740
- const delegation = delegationStore.get(cid);
2741
- if (!delegation) {
2742
- return { valid: false, error: `Proof delegation ${cid} not found` };
2743
- }
2744
- proofChain.push(delegation);
2745
- }
2746
- for (let i = 0; i < proofChain.length - 1; i++) {
2747
- const current = proofChain[i];
2748
- const parent = proofChain[i + 1];
2749
- if (parent.audienceDid !== current.issuerDid) {
2750
- return {
2751
- valid: false,
2752
- error: `Chain broken: ${parent.cid} audience (${parent.audienceDid}) != ${current.cid} issuer (${current.issuerDid})`
2753
- };
2754
- }
2755
- }
2756
- const root = proofChain[proofChain.length - 1];
2757
- if (root.issuerDid !== flowOwnerDid) {
2758
- return { valid: false, error: `Root issuer ${root.issuerDid} is not flow owner ${flowOwnerDid}` };
2759
- }
2760
- return { valid: true, proofChain };
2761
- };
2762
- const createAndValidateInvocation = async (params, _flowId, _blockId) => {
2763
- const { invokerDid, invokerType, entityRoomId, capability, proofs, pin } = params;
2764
- const validation = await validateDelegationChain(invokerDid, capability);
2765
- if (!validation.valid) {
2766
- return {
2767
- cid: "",
2768
- invocation: "",
2769
- valid: false,
2770
- error: validation.error
2771
- };
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 };
2772
2721
  }
2773
- const signer = await getSigner(handlers, invokerDid, invokerType, entityRoomId, pin);
2774
- const proofDelegations = await getProofDelegations(proofs);
2775
- const ucantoCapability = {
2776
- can: capability.can,
2777
- with: capability.with,
2778
- ...capability.nb && { nb: capability.nb }
2722
+ return {
2723
+ authorized: false,
2724
+ reason: "UCAN service is not configured. This flow version requires UCAN authorization."
2779
2725
  };
2780
- const invocation = await ucanCreateInvocation({
2781
- issuer: signer,
2782
- audience: flowOwnerDid,
2783
- capability: ucantoCapability,
2784
- proofs: proofDelegations
2785
- });
2786
- const serialized = await serializeInvocation(invocation);
2787
- const built = await invocation.buildIPLDView();
2788
- 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) {
2789
2733
  return {
2790
- cid,
2791
- invocation: serialized,
2792
- valid: true
2734
+ authorized: false,
2735
+ reason: result.error || "No valid capability chain found"
2793
2736
  };
2737
+ }
2738
+ const proofCids = result.proofChain?.map((d) => d.cid) || [];
2739
+ return {
2740
+ authorized: true,
2741
+ capabilityId: proofCids[0],
2742
+ proofCids
2794
2743
  };
2795
- const executeWithInvocation = async (params, action, flowId, blockId) => {
2796
- const invocationResult = await createAndValidateInvocation(params, flowId, blockId);
2797
- if (!invocationResult.valid) {
2798
- return {
2799
- success: false,
2800
- invocationCid: invocationResult.cid,
2801
- error: invocationResult.error
2802
- };
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 };
2803
2804
  }
2804
- 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
+ }
2805
2824
  return {
2806
2825
  success: false,
2807
- invocationCid: invocationResult.cid,
2808
- 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
2809
2829
  };
2810
2830
  }
2811
- try {
2812
- const actionResult = await action();
2831
+ if (invocationStore && invocationCid && invocationData) {
2813
2832
  const storedInvocation = {
2814
- cid: invocationResult.cid,
2815
- invocation: invocationResult.invocation,
2816
- invokerDid: params.invokerDid,
2817
- capability: params.capability,
2818
- 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(),
2819
2838
  flowId,
2820
- blockId,
2839
+ blockId: node.id,
2821
2840
  result: "success",
2822
- proofCids: params.proofs
2841
+ proofCids: auth.proofCids || [],
2842
+ claimId: result.claimId
2823
2843
  };
2824
2844
  invocationStore.add(storedInvocation);
2825
- return {
2826
- success: true,
2827
- invocationCid: invocationResult.cid,
2828
- result: actionResult,
2829
- actionResult
2830
- };
2831
- } 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) {
2832
2857
  const storedInvocation = {
2833
- cid: invocationResult.cid,
2834
- invocation: invocationResult.invocation,
2835
- invokerDid: params.invokerDid,
2836
- capability: params.capability,
2837
- 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(),
2838
2863
  flowId,
2839
- blockId,
2864
+ blockId: node.id,
2840
2865
  result: "failure",
2841
- error: error instanceof Error ? error.message : "Unknown error",
2842
- proofCids: params.proofs
2866
+ error: message,
2867
+ proofCids: auth.proofCids || []
2843
2868
  };
2844
2869
  invocationStore.add(storedInvocation);
2845
- return {
2846
- success: false,
2847
- invocationCid: invocationResult.cid,
2848
- error: error instanceof Error ? error.message : "Unknown error"
2849
- };
2850
2870
  }
2851
- };
2852
- return {
2853
- createRootDelegation,
2854
- createDelegation,
2855
- revokeDelegation,
2856
- getDelegation,
2857
- getAllDelegations,
2858
- getRootDelegation,
2859
- createAndValidateInvocation,
2860
- executeWithInvocation,
2861
- validateDelegationChain,
2862
- findValidProofs,
2863
- parseDelegationFromStore,
2864
- isConfigured
2865
- };
2871
+ return { success: false, stage: "action", error: message, invocationCid };
2872
+ }
2866
2873
  };
2867
2874
 
2868
2875
  // src/core/lib/flowEngine/migration.ts
@@ -3035,6 +3042,7 @@ export {
3035
3042
  didToMatrixUserId,
3036
3043
  findOrCreateDMRoom,
3037
3044
  sendDirectMessage,
3045
+ createUcanService,
3038
3046
  createUcanDelegationStore,
3039
3047
  createMemoryUcanDelegationStore,
3040
3048
  createInvocationStore,
@@ -3046,7 +3054,6 @@ export {
3046
3054
  clearRuntimeForTemplateClone,
3047
3055
  isNodeActive,
3048
3056
  isAuthorized,
3049
- executeNode,
3050
- createUcanService
3057
+ executeNode
3051
3058
  };
3052
- //# sourceMappingURL=chunk-3EZI42YS.mjs.map
3059
+ //# sourceMappingURL=chunk-F2JSGDES.mjs.map