@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.
- package/dist/{chunk-5D26UG3I.mjs → chunk-F2JSGDES.mjs} +730 -519
- package/dist/chunk-F2JSGDES.mjs.map +1 -0
- package/dist/{chunk-KXKEXO53.mjs → chunk-IQX6H7AK.mjs} +2 -2
- package/dist/{chunk-FM2G22RS.mjs → chunk-ZCRLP7QH.mjs} +581 -512
- package/dist/chunk-ZCRLP7QH.mjs.map +1 -0
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.mjs +2 -2
- package/dist/{graphql-client-B49ND-qp.d.ts → graphql-client-BxmM6bOC.d.ts} +3 -1
- package/dist/{index-Ch49AFng.d.ts → index-DMrZ4EwQ.d.ts} +5 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/mantine/index.d.ts +4 -4
- package/dist/mantine/index.mjs +2 -2
- package/dist/{setup-eMnRk02Q.d.ts → setup-B0la8n04.d.ts} +21 -15
- package/package.json +1 -1
- package/dist/chunk-5D26UG3I.mjs.map +0 -1
- package/dist/chunk-FM2G22RS.mjs.map +0 -1
- /package/dist/{chunk-KXKEXO53.mjs.map → chunk-IQX6H7AK.mjs.map} +0 -0
|
@@ -1904,97 +1904,408 @@ registerDiffResolver("evaluateClaim", {
|
|
|
1904
1904
|
}
|
|
1905
1905
|
});
|
|
1906
1906
|
|
|
1907
|
-
// src/core/
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
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
|
|
1930
|
-
|
|
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
|
|
1933
|
-
|
|
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
|
|
1936
|
-
const
|
|
1937
|
-
|
|
1938
|
-
|
|
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
|
|
1941
|
-
|
|
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
|
|
1944
|
-
|
|
2036
|
+
const revokeDelegation = (cid) => {
|
|
2037
|
+
delegationStore.remove(cid);
|
|
2038
|
+
delegationCache.delete(cid);
|
|
1945
2039
|
};
|
|
1946
|
-
const
|
|
1947
|
-
|
|
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
|
|
1957
|
-
return getAll()
|
|
2043
|
+
const getAllDelegations = () => {
|
|
2044
|
+
return delegationStore.getAll();
|
|
1958
2045
|
};
|
|
1959
|
-
const
|
|
1960
|
-
return
|
|
2046
|
+
const getRootDelegation = () => {
|
|
2047
|
+
return delegationStore.getRoot();
|
|
1961
2048
|
};
|
|
1962
|
-
const
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
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 (
|
|
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
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
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
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
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
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
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
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
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
|
-
|
|
2735
|
-
|
|
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
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2752
|
-
error: "
|
|
2826
|
+
stage: "claim",
|
|
2827
|
+
error: "Execution did not return a claimId for linked claim requirement.",
|
|
2828
|
+
invocationCid
|
|
2753
2829
|
};
|
|
2754
2830
|
}
|
|
2755
|
-
|
|
2756
|
-
const actionResult = await action();
|
|
2831
|
+
if (invocationStore && invocationCid && invocationData) {
|
|
2757
2832
|
const storedInvocation = {
|
|
2758
|
-
cid:
|
|
2759
|
-
invocation:
|
|
2760
|
-
invokerDid:
|
|
2761
|
-
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:
|
|
2841
|
+
proofCids: auth.proofCids || [],
|
|
2842
|
+
claimId: result.claimId
|
|
2767
2843
|
};
|
|
2768
2844
|
invocationStore.add(storedInvocation);
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
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:
|
|
2778
|
-
invocation:
|
|
2779
|
-
invokerDid:
|
|
2780
|
-
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:
|
|
2786
|
-
proofCids:
|
|
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
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
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-
|
|
3059
|
+
//# sourceMappingURL=chunk-F2JSGDES.mjs.map
|