@ixo/editor 3.0.0-beta.2 → 3.0.0-beta.21
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/capabilityValidation-B3NRVwYZ.d.ts +406 -0
- package/dist/chunk-3RYZSIC2.mjs +3020 -0
- package/dist/chunk-3RYZSIC2.mjs.map +1 -0
- package/dist/{chunk-HHEGZUQF.mjs → chunk-4344EQ47.mjs} +13331 -12621
- package/dist/chunk-4344EQ47.mjs.map +1 -0
- package/dist/chunk-VU34HOXM.mjs +36 -0
- package/dist/chunk-VU34HOXM.mjs.map +1 -0
- package/dist/cid-6O646X2I.mjs +9 -0
- package/dist/cid-6O646X2I.mjs.map +1 -0
- package/dist/core/index.d.ts +201 -0
- package/dist/core/index.mjs +59 -0
- package/dist/core/index.mjs.map +1 -0
- package/dist/graphql-client-b82luVYe.d.ts +2857 -0
- package/dist/index-CnqA4qDa.d.ts +2592 -0
- package/dist/index.d.ts +5 -149
- package/dist/index.mjs +14 -8
- package/dist/index.mjs.map +1 -1
- package/dist/mantine/index.d.ts +9 -3
- package/dist/mantine/index.mjs +10 -3
- package/package.json +9 -1
- package/style-core.css +47 -1
- package/style-mantine.css +47 -1
- package/style.css +47 -1
- package/dist/chunk-HHEGZUQF.mjs.map +0 -1
- package/dist/graphql-client-Dv0q3wZe.d.ts +0 -5302
|
@@ -0,0 +1,3020 @@
|
|
|
1
|
+
// src/core/lib/actionRegistry/registry.ts
|
|
2
|
+
var actions = /* @__PURE__ */ new Map();
|
|
3
|
+
function registerAction(definition) {
|
|
4
|
+
actions.set(definition.type, definition);
|
|
5
|
+
}
|
|
6
|
+
function getAction(type) {
|
|
7
|
+
return actions.get(type);
|
|
8
|
+
}
|
|
9
|
+
function getAllActions() {
|
|
10
|
+
return Array.from(actions.values());
|
|
11
|
+
}
|
|
12
|
+
function hasAction(type) {
|
|
13
|
+
return actions.has(type);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/core/lib/actionRegistry/adapters.ts
|
|
17
|
+
function buildServicesFromHandlers(handlers) {
|
|
18
|
+
return {
|
|
19
|
+
http: {
|
|
20
|
+
request: async (params) => {
|
|
21
|
+
const fetchOptions = {
|
|
22
|
+
method: params.method,
|
|
23
|
+
headers: { "Content-Type": "application/json", ...params.headers }
|
|
24
|
+
};
|
|
25
|
+
if (params.method !== "GET" && params.body) {
|
|
26
|
+
fetchOptions.body = typeof params.body === "string" ? params.body : JSON.stringify(params.body);
|
|
27
|
+
}
|
|
28
|
+
const res = await fetch(params.url, fetchOptions);
|
|
29
|
+
const data = await res.json().catch(() => ({}));
|
|
30
|
+
const responseHeaders = {};
|
|
31
|
+
res.headers.forEach((value, key) => {
|
|
32
|
+
responseHeaders[key] = value;
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
status: res.status,
|
|
36
|
+
headers: responseHeaders,
|
|
37
|
+
data
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
email: handlers?.sendEmail ? {
|
|
42
|
+
send: async (params) => {
|
|
43
|
+
const result = await handlers.sendEmail(params);
|
|
44
|
+
return {
|
|
45
|
+
messageId: result.id || "",
|
|
46
|
+
sentAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
} : void 0,
|
|
50
|
+
notify: handlers?.sendNotification ? {
|
|
51
|
+
send: async (params) => {
|
|
52
|
+
const result = await handlers.sendNotification(params);
|
|
53
|
+
return {
|
|
54
|
+
messageId: result.messageId,
|
|
55
|
+
sentAt: result.timestamp || (/* @__PURE__ */ new Date()).toISOString()
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
} : void 0,
|
|
59
|
+
bid: handlers?.submitBid && handlers?.approveBid && handlers?.rejectBid && handlers?.approveServiceAgentApplication && handlers?.approveEvaluatorApplication ? {
|
|
60
|
+
submitBid: async (params) => handlers.submitBid(params),
|
|
61
|
+
approveBid: async (params) => handlers.approveBid(params),
|
|
62
|
+
rejectBid: async (params) => handlers.rejectBid(params),
|
|
63
|
+
approveServiceAgentApplication: async (params) => handlers.approveServiceAgentApplication(params),
|
|
64
|
+
approveEvaluatorApplication: async (params) => handlers.approveEvaluatorApplication(params)
|
|
65
|
+
} : void 0,
|
|
66
|
+
claim: handlers?.requestPin && handlers?.submitClaim && handlers?.evaluateClaim && handlers?.getCurrentUser ? {
|
|
67
|
+
requestPin: async (config) => handlers.requestPin(config),
|
|
68
|
+
submitClaim: async (params) => handlers.submitClaim(params),
|
|
69
|
+
evaluateClaim: async (granteeAddress, did, payload) => handlers.evaluateClaim(granteeAddress, did, payload),
|
|
70
|
+
getCurrentUser: () => handlers.getCurrentUser(),
|
|
71
|
+
createUdid: handlers?.createUdid ? async (params) => handlers.createUdid(params) : void 0
|
|
72
|
+
} : void 0,
|
|
73
|
+
matrix: handlers?.storeMatrixCredential ? {
|
|
74
|
+
storeCredential: async (params) => handlers.storeMatrixCredential(params)
|
|
75
|
+
} : void 0
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/core/lib/actionRegistry/actions/httpRequest.ts
|
|
80
|
+
registerAction({
|
|
81
|
+
type: "http.request",
|
|
82
|
+
sideEffect: false,
|
|
83
|
+
defaultRequiresConfirmation: false,
|
|
84
|
+
run: async (inputs, ctx) => {
|
|
85
|
+
const { url, method = "GET", headers = {}, body } = inputs;
|
|
86
|
+
const requestFn = ctx.services.http?.request;
|
|
87
|
+
if (requestFn) {
|
|
88
|
+
const result = await requestFn({ url, method, headers, body });
|
|
89
|
+
return {
|
|
90
|
+
output: {
|
|
91
|
+
status: result.status,
|
|
92
|
+
data: result.data,
|
|
93
|
+
response: JSON.stringify(result.data, null, 2)
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const fetchOptions = {
|
|
98
|
+
method,
|
|
99
|
+
headers: { "Content-Type": "application/json", ...headers }
|
|
100
|
+
};
|
|
101
|
+
if (method !== "GET" && body) {
|
|
102
|
+
fetchOptions.body = typeof body === "string" ? body : JSON.stringify(body);
|
|
103
|
+
}
|
|
104
|
+
const response = await fetch(url, fetchOptions);
|
|
105
|
+
const data = await response.json().catch(() => ({}));
|
|
106
|
+
return {
|
|
107
|
+
output: {
|
|
108
|
+
status: response.status,
|
|
109
|
+
data,
|
|
110
|
+
response: JSON.stringify(data, null, 2)
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// src/core/lib/actionRegistry/actions/emailSend.ts
|
|
117
|
+
registerAction({
|
|
118
|
+
type: "email.send",
|
|
119
|
+
sideEffect: true,
|
|
120
|
+
defaultRequiresConfirmation: true,
|
|
121
|
+
requiredCapability: "email/send",
|
|
122
|
+
outputSchema: [
|
|
123
|
+
{ path: "messageId", displayName: "Message ID", type: "string", description: "The unique ID of the sent email" },
|
|
124
|
+
{ path: "sentAt", displayName: "Sent At", type: "string", description: "Timestamp when the email was sent" }
|
|
125
|
+
],
|
|
126
|
+
run: async (inputs, ctx) => {
|
|
127
|
+
if (!ctx.services.email) {
|
|
128
|
+
throw new Error("Email service not configured");
|
|
129
|
+
}
|
|
130
|
+
const { to, subject, template, templateName, templateVersion, variables, cc, bcc, replyTo } = inputs;
|
|
131
|
+
const resolvedTemplate = template || templateName;
|
|
132
|
+
if (!resolvedTemplate) throw new Error("No template selected");
|
|
133
|
+
if (!to) throw new Error("Recipient (to) is required");
|
|
134
|
+
let resolvedVariables = variables;
|
|
135
|
+
if (typeof resolvedVariables === "string") {
|
|
136
|
+
try {
|
|
137
|
+
resolvedVariables = JSON.parse(resolvedVariables);
|
|
138
|
+
} catch {
|
|
139
|
+
resolvedVariables = {};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const result = await ctx.services.email.send({
|
|
143
|
+
to,
|
|
144
|
+
subject,
|
|
145
|
+
template: resolvedTemplate,
|
|
146
|
+
templateVersion,
|
|
147
|
+
variables: resolvedVariables,
|
|
148
|
+
cc,
|
|
149
|
+
bcc,
|
|
150
|
+
replyTo
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
output: {
|
|
154
|
+
messageId: result.messageId,
|
|
155
|
+
sentAt: result.sentAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// src/core/lib/actionRegistry/actions/humanCheckbox.ts
|
|
162
|
+
registerAction({
|
|
163
|
+
type: "human.checkbox.set",
|
|
164
|
+
sideEffect: true,
|
|
165
|
+
defaultRequiresConfirmation: false,
|
|
166
|
+
requiredCapability: "flow/execute",
|
|
167
|
+
run: async (inputs) => {
|
|
168
|
+
const checked = inputs.checked !== void 0 ? !!inputs.checked : true;
|
|
169
|
+
return { output: { checked } };
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// src/core/lib/actionRegistry/actions/humanForm.ts
|
|
174
|
+
function normalizeAnswers(rawAnswers) {
|
|
175
|
+
if (rawAnswers == null) {
|
|
176
|
+
return {};
|
|
177
|
+
}
|
|
178
|
+
if (typeof rawAnswers === "string") {
|
|
179
|
+
try {
|
|
180
|
+
const parsed = JSON.parse(rawAnswers);
|
|
181
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
182
|
+
throw new Error();
|
|
183
|
+
}
|
|
184
|
+
return parsed;
|
|
185
|
+
} catch {
|
|
186
|
+
throw new Error("answers must be a valid JSON object");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (typeof rawAnswers !== "object" || Array.isArray(rawAnswers)) {
|
|
190
|
+
throw new Error("answers must be an object");
|
|
191
|
+
}
|
|
192
|
+
return rawAnswers;
|
|
193
|
+
}
|
|
194
|
+
function registerFormSubmitAction(type) {
|
|
195
|
+
registerAction({
|
|
196
|
+
type,
|
|
197
|
+
sideEffect: true,
|
|
198
|
+
defaultRequiresConfirmation: false,
|
|
199
|
+
requiredCapability: "flow/execute",
|
|
200
|
+
outputSchema: [
|
|
201
|
+
{ path: "form.answers", displayName: "Form Answers JSON", type: "string", description: "JSON stringified form answers, matching form block runtime output." },
|
|
202
|
+
{ path: "answers", displayName: "Form Answers", type: "object", description: "Parsed form answers object for convenience." }
|
|
203
|
+
],
|
|
204
|
+
run: async (inputs) => {
|
|
205
|
+
const answers = normalizeAnswers(inputs.answers ?? inputs.form?.answers);
|
|
206
|
+
const answersJson = JSON.stringify(answers);
|
|
207
|
+
return {
|
|
208
|
+
output: {
|
|
209
|
+
form: {
|
|
210
|
+
answers: answersJson
|
|
211
|
+
},
|
|
212
|
+
answers
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
registerFormSubmitAction("form.submit");
|
|
219
|
+
registerFormSubmitAction("human.form.submit");
|
|
220
|
+
|
|
221
|
+
// src/core/lib/actionRegistry/actions/notificationPush.ts
|
|
222
|
+
registerAction({
|
|
223
|
+
type: "notification.push",
|
|
224
|
+
sideEffect: true,
|
|
225
|
+
defaultRequiresConfirmation: true,
|
|
226
|
+
requiredCapability: "notify/send",
|
|
227
|
+
run: async (inputs, ctx) => {
|
|
228
|
+
if (!ctx.services.notify) {
|
|
229
|
+
throw new Error("Notification service not configured");
|
|
230
|
+
}
|
|
231
|
+
const { channel, to, cc, bcc, subject, body, bodyType, from, replyTo } = inputs;
|
|
232
|
+
if (!to || Array.isArray(to) && to.length === 0) {
|
|
233
|
+
throw new Error("At least one recipient is required");
|
|
234
|
+
}
|
|
235
|
+
const result = await ctx.services.notify.send({
|
|
236
|
+
channel,
|
|
237
|
+
to: Array.isArray(to) ? to : [to],
|
|
238
|
+
cc,
|
|
239
|
+
bcc,
|
|
240
|
+
subject,
|
|
241
|
+
body,
|
|
242
|
+
bodyType,
|
|
243
|
+
from,
|
|
244
|
+
replyTo
|
|
245
|
+
});
|
|
246
|
+
return {
|
|
247
|
+
output: {
|
|
248
|
+
messageId: result.messageId,
|
|
249
|
+
sentAt: result.sentAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// src/core/lib/actionRegistry/actions/bid.ts
|
|
256
|
+
function normalizeBidRole(role) {
|
|
257
|
+
const normalized = String(role || "").trim().toLowerCase();
|
|
258
|
+
if (normalized === "service_agent" || normalized === "sa") return "SA";
|
|
259
|
+
if (normalized === "evaluation_agent" || normalized === "ea") return "EA";
|
|
260
|
+
throw new Error("Invalid bid role. Expected service_agent or evaluation_agent");
|
|
261
|
+
}
|
|
262
|
+
registerAction({
|
|
263
|
+
type: "bid",
|
|
264
|
+
sideEffect: true,
|
|
265
|
+
defaultRequiresConfirmation: true,
|
|
266
|
+
requiredCapability: "flow/block/execute",
|
|
267
|
+
outputSchema: [
|
|
268
|
+
{ path: "bidId", displayName: "Bid ID", type: "string", description: "The submitted bid identifier" },
|
|
269
|
+
{ path: "collectionId", displayName: "Collection ID", type: "string", description: "Claim collection identifier" },
|
|
270
|
+
{ path: "role", displayName: "Role", type: "string", description: "Submitted role (service_agent or evaluation_agent)" },
|
|
271
|
+
{ path: "submitterDid", displayName: "Submitter DID", type: "string", description: "Actor DID that submitted the bid" },
|
|
272
|
+
{ path: "deedDid", displayName: "Deed DID", type: "string", description: "Deed identifier if provided" }
|
|
273
|
+
],
|
|
274
|
+
run: async (inputs, ctx) => {
|
|
275
|
+
const service = ctx.services.bid;
|
|
276
|
+
if (!service) {
|
|
277
|
+
throw new Error("Bid service not configured");
|
|
278
|
+
}
|
|
279
|
+
const collectionId = String(inputs.collectionId || "").trim();
|
|
280
|
+
const roleInput = String(inputs.role || "").trim();
|
|
281
|
+
let surveyAnswers = inputs.surveyAnswers;
|
|
282
|
+
const deedDid = String(inputs.deedDid || "").trim();
|
|
283
|
+
if (!collectionId) throw new Error("collectionId is required");
|
|
284
|
+
if (!roleInput) throw new Error("role is required");
|
|
285
|
+
if (typeof surveyAnswers === "string") {
|
|
286
|
+
try {
|
|
287
|
+
surveyAnswers = JSON.parse(surveyAnswers);
|
|
288
|
+
} catch {
|
|
289
|
+
throw new Error("surveyAnswers must be a valid JSON object");
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (!surveyAnswers || typeof surveyAnswers !== "object" || Array.isArray(surveyAnswers)) {
|
|
293
|
+
throw new Error("surveyAnswers must be an object");
|
|
294
|
+
}
|
|
295
|
+
const chainRole = normalizeBidRole(roleInput);
|
|
296
|
+
const submission = await service.submitBid({
|
|
297
|
+
collectionId,
|
|
298
|
+
role: chainRole,
|
|
299
|
+
surveyAnswers
|
|
300
|
+
});
|
|
301
|
+
const bidId = String(submission?.claimId || submission?.bidId || submission?.id || "");
|
|
302
|
+
if (!bidId) {
|
|
303
|
+
throw new Error("submitBid returned no bid identifier");
|
|
304
|
+
}
|
|
305
|
+
return {
|
|
306
|
+
output: {
|
|
307
|
+
bidId,
|
|
308
|
+
collectionId,
|
|
309
|
+
role: roleInput,
|
|
310
|
+
submitterDid: ctx.actorDid || "",
|
|
311
|
+
deedDid
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// src/core/lib/actionRegistry/actions/evaluateBid.ts
|
|
318
|
+
function normalizeDecision(value) {
|
|
319
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
320
|
+
if (normalized === "approve" || normalized === "reject") {
|
|
321
|
+
return normalized;
|
|
322
|
+
}
|
|
323
|
+
throw new Error("decision must be either approve or reject");
|
|
324
|
+
}
|
|
325
|
+
function isServiceAgentRole(role) {
|
|
326
|
+
const normalized = String(role || "").trim().toLowerCase();
|
|
327
|
+
return normalized === "service_agent" || normalized === "sa";
|
|
328
|
+
}
|
|
329
|
+
function isEvaluationAgentRole(role) {
|
|
330
|
+
const normalized = String(role || "").trim().toLowerCase();
|
|
331
|
+
return normalized === "evaluation_agent" || normalized === "ea";
|
|
332
|
+
}
|
|
333
|
+
registerAction({
|
|
334
|
+
type: "evaluateBid",
|
|
335
|
+
sideEffect: true,
|
|
336
|
+
defaultRequiresConfirmation: true,
|
|
337
|
+
requiredCapability: "flow/block/execute",
|
|
338
|
+
outputSchema: [
|
|
339
|
+
{ path: "bidId", displayName: "Bid ID", type: "string", description: "Evaluated bid identifier" },
|
|
340
|
+
{ path: "decision", displayName: "Decision", type: "string", description: "approve or reject" },
|
|
341
|
+
{ path: "status", displayName: "Status", type: "string", description: "approved or rejected" },
|
|
342
|
+
{ path: "evaluatedByDid", displayName: "Evaluated By DID", type: "string", description: "Actor DID that evaluated the bid" },
|
|
343
|
+
{ path: "evaluatedAt", displayName: "Evaluated At", type: "string", description: "ISO timestamp of evaluation" },
|
|
344
|
+
{ path: "reason", displayName: "Reason", type: "string", description: "Rejection reason when decision is reject" },
|
|
345
|
+
{ path: "collectionId", displayName: "Collection ID", type: "string", description: "Claim collection identifier" },
|
|
346
|
+
{ path: "role", displayName: "Role", type: "string", description: "Applicant role" },
|
|
347
|
+
{ path: "deedDid", displayName: "Deed DID", type: "string", description: "Deed identifier" },
|
|
348
|
+
{ path: "applicantDid", displayName: "Applicant DID", type: "string", description: "Applicant DID" },
|
|
349
|
+
{ path: "applicantAddress", displayName: "Applicant Address", type: "string", description: "Applicant wallet address" }
|
|
350
|
+
],
|
|
351
|
+
run: async (inputs, ctx) => {
|
|
352
|
+
const service = ctx.services.bid;
|
|
353
|
+
if (!service) {
|
|
354
|
+
throw new Error("Bid service not configured");
|
|
355
|
+
}
|
|
356
|
+
const decision = normalizeDecision(inputs.decision);
|
|
357
|
+
const bidId = String(inputs.bidId || "").trim();
|
|
358
|
+
const collectionId = String(inputs.collectionId || "").trim();
|
|
359
|
+
const deedDid = String(inputs.deedDid || "").trim();
|
|
360
|
+
const role = String(inputs.role || "").trim();
|
|
361
|
+
const applicantDid = String(inputs.applicantDid || "").trim();
|
|
362
|
+
const applicantAddress = String(inputs.applicantAddress || "").trim();
|
|
363
|
+
if (!bidId) throw new Error("bidId is required");
|
|
364
|
+
if (!collectionId) throw new Error("collectionId is required");
|
|
365
|
+
if (!deedDid) throw new Error("deedDid is required");
|
|
366
|
+
if (!role) throw new Error("role is required");
|
|
367
|
+
if (!applicantDid) throw new Error("applicantDid is required");
|
|
368
|
+
if (!applicantAddress) throw new Error("applicantAddress is required");
|
|
369
|
+
if (decision === "approve") {
|
|
370
|
+
const adminAddress = String(inputs.adminAddress || "").trim();
|
|
371
|
+
if (!adminAddress) {
|
|
372
|
+
throw new Error("adminAddress is required when decision is approve");
|
|
373
|
+
}
|
|
374
|
+
if (isServiceAgentRole(role)) {
|
|
375
|
+
await service.approveServiceAgentApplication({
|
|
376
|
+
adminAddress,
|
|
377
|
+
collectionId,
|
|
378
|
+
agentQuota: 30,
|
|
379
|
+
deedDid,
|
|
380
|
+
currentUserAddress: applicantAddress
|
|
381
|
+
});
|
|
382
|
+
} else if (isEvaluationAgentRole(role)) {
|
|
383
|
+
let maxAmounts = inputs.maxAmounts;
|
|
384
|
+
if (typeof maxAmounts === "string") {
|
|
385
|
+
try {
|
|
386
|
+
maxAmounts = JSON.parse(maxAmounts);
|
|
387
|
+
} catch {
|
|
388
|
+
throw new Error("maxAmounts must be valid JSON when provided");
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
await service.approveEvaluatorApplication({
|
|
392
|
+
adminAddress,
|
|
393
|
+
collectionId,
|
|
394
|
+
deedDid,
|
|
395
|
+
evaluatorAddress: applicantAddress,
|
|
396
|
+
agentQuota: 10,
|
|
397
|
+
maxAmounts: Array.isArray(maxAmounts) ? maxAmounts : void 0
|
|
398
|
+
});
|
|
399
|
+
} else {
|
|
400
|
+
throw new Error("Invalid role for evaluation. Expected service_agent or evaluation_agent");
|
|
401
|
+
}
|
|
402
|
+
await service.approveBid({
|
|
403
|
+
bidId,
|
|
404
|
+
collectionId,
|
|
405
|
+
did: applicantDid
|
|
406
|
+
});
|
|
407
|
+
} else {
|
|
408
|
+
const reason = String(inputs.reason || "").trim();
|
|
409
|
+
if (!reason) {
|
|
410
|
+
throw new Error("reason is required when decision is reject");
|
|
411
|
+
}
|
|
412
|
+
await service.rejectBid({
|
|
413
|
+
bidId,
|
|
414
|
+
collectionId,
|
|
415
|
+
did: deedDid,
|
|
416
|
+
reason
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
output: {
|
|
421
|
+
bidId,
|
|
422
|
+
decision,
|
|
423
|
+
status: decision === "approve" ? "approved" : "rejected",
|
|
424
|
+
evaluatedByDid: ctx.actorDid || "",
|
|
425
|
+
evaluatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
426
|
+
reason: decision === "reject" ? String(inputs.reason || "") : "",
|
|
427
|
+
collectionId,
|
|
428
|
+
role,
|
|
429
|
+
deedDid,
|
|
430
|
+
applicantDid,
|
|
431
|
+
applicantAddress
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
// src/core/lib/actionRegistry/actions/claim.ts
|
|
438
|
+
registerAction({
|
|
439
|
+
type: "claim",
|
|
440
|
+
sideEffect: true,
|
|
441
|
+
defaultRequiresConfirmation: true,
|
|
442
|
+
requiredCapability: "flow/block/execute",
|
|
443
|
+
outputSchema: [
|
|
444
|
+
{ path: "claimId", displayName: "Claim ID", type: "string", description: "The submitted claim identifier" },
|
|
445
|
+
{ path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "Submission transaction hash" },
|
|
446
|
+
{ path: "collectionId", displayName: "Collection ID", type: "string", description: "Claim collection identifier" },
|
|
447
|
+
{ path: "deedDid", displayName: "Deed DID", type: "string", description: "Deed identifier" },
|
|
448
|
+
{ path: "submittedByDid", displayName: "Submitted By DID", type: "string", description: "Actor DID that submitted the claim" },
|
|
449
|
+
{ path: "submittedAt", displayName: "Submitted At", type: "string", description: "ISO timestamp of submission" }
|
|
450
|
+
],
|
|
451
|
+
run: async (inputs, ctx) => {
|
|
452
|
+
const service = ctx.services.claim;
|
|
453
|
+
if (!service) {
|
|
454
|
+
throw new Error("Claim service not configured");
|
|
455
|
+
}
|
|
456
|
+
const deedDid = String(inputs.deedDid || "").trim();
|
|
457
|
+
const collectionId = String(inputs.collectionId || "").trim();
|
|
458
|
+
const adminAddress = String(inputs.adminAddress || "").trim();
|
|
459
|
+
if (!deedDid) throw new Error("deedDid is required");
|
|
460
|
+
if (!collectionId) throw new Error("collectionId is required");
|
|
461
|
+
if (!adminAddress) throw new Error("adminAddress is required");
|
|
462
|
+
let surveyAnswers = inputs.surveyAnswers;
|
|
463
|
+
if (typeof surveyAnswers === "string") {
|
|
464
|
+
try {
|
|
465
|
+
surveyAnswers = JSON.parse(surveyAnswers);
|
|
466
|
+
} catch {
|
|
467
|
+
throw new Error("surveyAnswers must be valid JSON");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (!surveyAnswers || typeof surveyAnswers !== "object" || Array.isArray(surveyAnswers)) {
|
|
471
|
+
throw new Error("surveyAnswers must be an object");
|
|
472
|
+
}
|
|
473
|
+
let pin = String(inputs.pin || "").trim();
|
|
474
|
+
if (!pin) {
|
|
475
|
+
pin = await service.requestPin({
|
|
476
|
+
title: "Verify Identity",
|
|
477
|
+
description: "Enter your PIN to submit the claim",
|
|
478
|
+
submitText: "Verify"
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
if (!pin) {
|
|
482
|
+
throw new Error("PIN is required to submit claim");
|
|
483
|
+
}
|
|
484
|
+
const result = await service.submitClaim({
|
|
485
|
+
surveyData: surveyAnswers,
|
|
486
|
+
deedDid,
|
|
487
|
+
collectionId,
|
|
488
|
+
adminAddress,
|
|
489
|
+
pin
|
|
490
|
+
});
|
|
491
|
+
const claimId = String(result?.claimId || result?.id || "");
|
|
492
|
+
if (!claimId) {
|
|
493
|
+
throw new Error("submitClaim returned no claim identifier");
|
|
494
|
+
}
|
|
495
|
+
return {
|
|
496
|
+
output: {
|
|
497
|
+
claimId,
|
|
498
|
+
transactionHash: String(result?.transactionHash || ""),
|
|
499
|
+
collectionId,
|
|
500
|
+
deedDid,
|
|
501
|
+
submittedByDid: ctx.actorDid || "",
|
|
502
|
+
submittedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// src/core/lib/actionRegistry/actions/evaluateClaim.ts
|
|
509
|
+
function normalizeDecision2(value) {
|
|
510
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
511
|
+
if (normalized === "approve" || normalized === "reject") {
|
|
512
|
+
return normalized;
|
|
513
|
+
}
|
|
514
|
+
throw new Error("decision must be either approve or reject");
|
|
515
|
+
}
|
|
516
|
+
function toStatus(decision) {
|
|
517
|
+
return decision === "approve" ? 1 : 2;
|
|
518
|
+
}
|
|
519
|
+
function isEvaluatorRole(role) {
|
|
520
|
+
const normalized = String(role || "").trim().toLowerCase();
|
|
521
|
+
return normalized === "ea" || normalized === "evaluation_agent";
|
|
522
|
+
}
|
|
523
|
+
registerAction({
|
|
524
|
+
type: "evaluateClaim",
|
|
525
|
+
sideEffect: true,
|
|
526
|
+
defaultRequiresConfirmation: true,
|
|
527
|
+
requiredCapability: "flow/block/execute",
|
|
528
|
+
outputSchema: [
|
|
529
|
+
{ path: "claimId", displayName: "Claim ID", type: "string", description: "Evaluated claim identifier" },
|
|
530
|
+
{ path: "decision", displayName: "Decision", type: "string", description: "approve or reject" },
|
|
531
|
+
{ path: "status", displayName: "Status", type: "string", description: "approved or rejected" },
|
|
532
|
+
{ path: "verificationProof", displayName: "Verification Proof", type: "string", description: "UDID URL proof if generated" },
|
|
533
|
+
{ path: "collectionId", displayName: "Collection ID", type: "string", description: "Claim collection identifier" },
|
|
534
|
+
{ path: "deedDid", displayName: "Deed DID", type: "string", description: "Deed identifier" },
|
|
535
|
+
{ path: "evaluatedByDid", displayName: "Evaluated By DID", type: "string", description: "Actor DID that evaluated the claim" },
|
|
536
|
+
{ path: "evaluatedAt", displayName: "Evaluated At", type: "string", description: "ISO timestamp of evaluation" }
|
|
537
|
+
],
|
|
538
|
+
run: async (inputs, ctx) => {
|
|
539
|
+
const service = ctx.services.claim;
|
|
540
|
+
if (!service) {
|
|
541
|
+
throw new Error("Claim service not configured");
|
|
542
|
+
}
|
|
543
|
+
const decision = normalizeDecision2(inputs.decision);
|
|
544
|
+
const claimId = String(inputs.claimId || "").trim();
|
|
545
|
+
const collectionId = String(inputs.collectionId || "").trim();
|
|
546
|
+
const deedDid = String(inputs.deedDid || "").trim();
|
|
547
|
+
const adminAddress = String(inputs.adminAddress || "").trim();
|
|
548
|
+
if (!claimId) throw new Error("claimId is required");
|
|
549
|
+
if (!collectionId) throw new Error("collectionId is required");
|
|
550
|
+
if (!deedDid) throw new Error("deedDid is required");
|
|
551
|
+
if (!adminAddress) throw new Error("adminAddress is required");
|
|
552
|
+
const handlers = ctx.handlers;
|
|
553
|
+
const actorAddress = String(ctx.actorDid || service.getCurrentUser?.()?.address || "").trim();
|
|
554
|
+
if (!actorAddress) {
|
|
555
|
+
throw new Error("Unable to resolve actor address for evaluator authorization");
|
|
556
|
+
}
|
|
557
|
+
if (typeof handlers?.getUserRoles !== "function") {
|
|
558
|
+
throw new Error("Evaluator authorization check unavailable (getUserRoles handler missing)");
|
|
559
|
+
}
|
|
560
|
+
const roles = await handlers.getUserRoles({
|
|
561
|
+
userAddress: actorAddress,
|
|
562
|
+
adminAddress,
|
|
563
|
+
deedDid,
|
|
564
|
+
collectionIds: [collectionId]
|
|
565
|
+
});
|
|
566
|
+
const roleForCollection = Array.isArray(roles) ? roles.find((r) => r?.collectionId === collectionId)?.role : void 0;
|
|
567
|
+
if (!isEvaluatorRole(roleForCollection)) {
|
|
568
|
+
throw new Error("Not authorized: evaluator role required to evaluate claims for this collection");
|
|
569
|
+
}
|
|
570
|
+
let amount = inputs.amount;
|
|
571
|
+
if (typeof amount === "string" && amount.trim()) {
|
|
572
|
+
try {
|
|
573
|
+
amount = JSON.parse(amount);
|
|
574
|
+
} catch {
|
|
575
|
+
throw new Error("amount must be valid JSON when provided as string");
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
const normalizeCoin = (coin) => {
|
|
579
|
+
if (!coin || typeof coin !== "object" || Array.isArray(coin)) return null;
|
|
580
|
+
const denom = String(coin.denom || "").trim();
|
|
581
|
+
const tokenAmount = String(coin.amount || "").trim();
|
|
582
|
+
if (!denom || !tokenAmount) return null;
|
|
583
|
+
return { denom, amount: tokenAmount };
|
|
584
|
+
};
|
|
585
|
+
let normalizedAmounts;
|
|
586
|
+
if (Array.isArray(amount)) {
|
|
587
|
+
normalizedAmounts = amount.map(normalizeCoin).filter((coin) => !!coin);
|
|
588
|
+
if (normalizedAmounts.length !== amount.length) {
|
|
589
|
+
throw new Error("amount must contain valid coin objects with denom and amount");
|
|
590
|
+
}
|
|
591
|
+
} else if (amount != null) {
|
|
592
|
+
const coin = normalizeCoin(amount);
|
|
593
|
+
if (!coin) {
|
|
594
|
+
throw new Error("amount must be a coin object or an array of coin objects");
|
|
595
|
+
}
|
|
596
|
+
normalizedAmounts = [coin];
|
|
597
|
+
}
|
|
598
|
+
let verificationProof = String(inputs.verificationProof || "").trim();
|
|
599
|
+
const shouldCreateUdid = Boolean(inputs.createUdid);
|
|
600
|
+
if (!verificationProof && shouldCreateUdid && service.createUdid) {
|
|
601
|
+
const pin = await service.requestPin({
|
|
602
|
+
title: "Sign Evaluation Result",
|
|
603
|
+
description: "Enter your PIN to sign the evaluation UDID",
|
|
604
|
+
submitText: "Sign"
|
|
605
|
+
});
|
|
606
|
+
if (!pin) {
|
|
607
|
+
throw new Error("PIN is required to sign evaluation proof");
|
|
608
|
+
}
|
|
609
|
+
const udid = await service.createUdid({
|
|
610
|
+
claimCid: claimId,
|
|
611
|
+
deedDid,
|
|
612
|
+
collectionId,
|
|
613
|
+
capabilityCid: String(inputs.capabilityCid || deedDid),
|
|
614
|
+
rubricAuthority: String(inputs.rubricAuthority || deedDid),
|
|
615
|
+
rubricId: String(inputs.rubricId || deedDid),
|
|
616
|
+
outcome: toStatus(decision),
|
|
617
|
+
tag: decision === "approve" ? "approved" : "rejected",
|
|
618
|
+
issuerType: "user",
|
|
619
|
+
pin,
|
|
620
|
+
traceCid: inputs.traceCid,
|
|
621
|
+
items: inputs.items,
|
|
622
|
+
patch: inputs.patch
|
|
623
|
+
});
|
|
624
|
+
verificationProof = String(udid?.url || udid?.cid || "");
|
|
625
|
+
}
|
|
626
|
+
const currentUser = service.getCurrentUser();
|
|
627
|
+
const granteeAddress = String(inputs.granteeAddress || currentUser?.address || "").trim();
|
|
628
|
+
if (!granteeAddress) {
|
|
629
|
+
throw new Error("granteeAddress could not be resolved");
|
|
630
|
+
}
|
|
631
|
+
await service.evaluateClaim(granteeAddress, deedDid, {
|
|
632
|
+
claimId,
|
|
633
|
+
collectionId,
|
|
634
|
+
adminAddress,
|
|
635
|
+
status: toStatus(decision),
|
|
636
|
+
verificationProof,
|
|
637
|
+
amount: normalizedAmounts && normalizedAmounts.length > 0 ? normalizedAmounts.length === 1 ? normalizedAmounts[0] : normalizedAmounts : void 0
|
|
638
|
+
});
|
|
639
|
+
return {
|
|
640
|
+
output: {
|
|
641
|
+
claimId,
|
|
642
|
+
decision,
|
|
643
|
+
status: decision === "approve" ? "approved" : "rejected",
|
|
644
|
+
verificationProof,
|
|
645
|
+
collectionId,
|
|
646
|
+
deedDid,
|
|
647
|
+
evaluatedByDid: ctx.actorDid || granteeAddress,
|
|
648
|
+
evaluatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
// src/core/lib/actionRegistry/actions/proposalCreate.ts
|
|
655
|
+
registerAction({
|
|
656
|
+
type: "proposal.create",
|
|
657
|
+
sideEffect: true,
|
|
658
|
+
defaultRequiresConfirmation: true,
|
|
659
|
+
requiredCapability: "flow/block/execute",
|
|
660
|
+
outputSchema: [
|
|
661
|
+
{ path: "proposalId", displayName: "Proposal ID", type: "string", description: "The on-chain proposal identifier" },
|
|
662
|
+
{ path: "status", displayName: "Proposal Status", type: "string", description: "Current proposal status (open, passed, rejected, executed, etc.)" },
|
|
663
|
+
{ path: "proposalContractAddress", displayName: "Proposal Contract Address", type: "string", description: "The proposal module contract address" },
|
|
664
|
+
{ path: "coreAddress", displayName: "Core Address", type: "string", description: "The DAO core contract address" },
|
|
665
|
+
{ path: "createdAt", displayName: "Created At", type: "string", description: "ISO timestamp of proposal creation" }
|
|
666
|
+
],
|
|
667
|
+
run: async (inputs, ctx) => {
|
|
668
|
+
const handlers = ctx.handlers;
|
|
669
|
+
if (!handlers) {
|
|
670
|
+
throw new Error("Handlers not available");
|
|
671
|
+
}
|
|
672
|
+
const coreAddress = String(inputs.coreAddress || "").trim();
|
|
673
|
+
const title = String(inputs.title || "").trim();
|
|
674
|
+
const description = String(inputs.description || "").trim();
|
|
675
|
+
if (!coreAddress) throw new Error("coreAddress is required");
|
|
676
|
+
if (!title) throw new Error("title is required");
|
|
677
|
+
if (!description) throw new Error("description is required");
|
|
678
|
+
let actions2 = [];
|
|
679
|
+
if (inputs.actions) {
|
|
680
|
+
if (typeof inputs.actions === "string") {
|
|
681
|
+
try {
|
|
682
|
+
actions2 = JSON.parse(inputs.actions);
|
|
683
|
+
} catch {
|
|
684
|
+
throw new Error("actions must be valid JSON array");
|
|
685
|
+
}
|
|
686
|
+
} else if (Array.isArray(inputs.actions)) {
|
|
687
|
+
actions2 = inputs.actions;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
const { preProposalContractAddress } = await handlers.getPreProposalContractAddress({
|
|
691
|
+
coreAddress
|
|
692
|
+
});
|
|
693
|
+
const { groupContractAddress } = await handlers.getGroupContractAddress({
|
|
694
|
+
coreAddress
|
|
695
|
+
});
|
|
696
|
+
const { proposalContractAddress } = await handlers.getProposalContractAddress({
|
|
697
|
+
coreAddress
|
|
698
|
+
});
|
|
699
|
+
const params = {
|
|
700
|
+
preProposalContractAddress,
|
|
701
|
+
title,
|
|
702
|
+
description,
|
|
703
|
+
actions: actions2.length > 0 ? actions2 : void 0,
|
|
704
|
+
coreAddress,
|
|
705
|
+
groupContractAddress
|
|
706
|
+
};
|
|
707
|
+
const proposalId = await handlers.createProposal(params);
|
|
708
|
+
return {
|
|
709
|
+
output: {
|
|
710
|
+
proposalId: String(proposalId),
|
|
711
|
+
status: "open",
|
|
712
|
+
proposalContractAddress: proposalContractAddress || "",
|
|
713
|
+
coreAddress,
|
|
714
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
// src/core/lib/actionRegistry/actions/proposalVote.ts
|
|
721
|
+
registerAction({
|
|
722
|
+
type: "proposal.vote",
|
|
723
|
+
sideEffect: true,
|
|
724
|
+
defaultRequiresConfirmation: true,
|
|
725
|
+
requiredCapability: "flow/block/execute",
|
|
726
|
+
outputSchema: [
|
|
727
|
+
{ path: "vote", displayName: "Vote", type: "string", description: "The vote cast (yes, no, no_with_veto, abstain)" },
|
|
728
|
+
{ path: "rationale", displayName: "Rationale", type: "string", description: "Optional rationale provided with the vote" },
|
|
729
|
+
{ path: "proposalId", displayName: "Proposal ID", type: "string", description: "The proposal that was voted on" },
|
|
730
|
+
{ path: "votedAt", displayName: "Voted At", type: "string", description: "ISO timestamp of when the vote was cast" }
|
|
731
|
+
],
|
|
732
|
+
run: async (inputs, ctx) => {
|
|
733
|
+
const handlers = ctx.handlers;
|
|
734
|
+
if (!handlers) {
|
|
735
|
+
throw new Error("Handlers not available");
|
|
736
|
+
}
|
|
737
|
+
const proposalId = Number(inputs.proposalId);
|
|
738
|
+
const vote = String(inputs.vote || "").trim();
|
|
739
|
+
const rationale = String(inputs.rationale || "").trim();
|
|
740
|
+
const proposalContractAddress = String(inputs.proposalContractAddress || "").trim();
|
|
741
|
+
if (!proposalId || isNaN(proposalId)) throw new Error("proposalId is required");
|
|
742
|
+
if (!vote) throw new Error("vote is required");
|
|
743
|
+
if (!proposalContractAddress) throw new Error("proposalContractAddress is required");
|
|
744
|
+
const validVotes = ["yes", "no", "no_with_veto", "abstain"];
|
|
745
|
+
if (!validVotes.includes(vote)) {
|
|
746
|
+
throw new Error(`vote must be one of: ${validVotes.join(", ")}`);
|
|
747
|
+
}
|
|
748
|
+
await handlers.vote({
|
|
749
|
+
proposalId,
|
|
750
|
+
vote,
|
|
751
|
+
rationale: rationale || void 0,
|
|
752
|
+
proposalContractAddress
|
|
753
|
+
});
|
|
754
|
+
return {
|
|
755
|
+
output: {
|
|
756
|
+
vote,
|
|
757
|
+
rationale: rationale || "",
|
|
758
|
+
proposalId: String(proposalId),
|
|
759
|
+
votedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
// src/core/lib/actionRegistry/actions/protocolSelect.ts
|
|
766
|
+
registerAction({
|
|
767
|
+
type: "protocol.select",
|
|
768
|
+
sideEffect: false,
|
|
769
|
+
defaultRequiresConfirmation: false,
|
|
770
|
+
outputSchema: [
|
|
771
|
+
{ path: "selectedProtocolDid", displayName: "Selected Protocol DID", type: "string", description: "DID of the selected protocol" },
|
|
772
|
+
{ path: "selectedProtocolName", displayName: "Selected Protocol Name", type: "string", description: "Display name of the selected protocol" },
|
|
773
|
+
{ path: "selectedProtocolType", displayName: "Selected Protocol Type", type: "string", description: "Type of the selected protocol" }
|
|
774
|
+
],
|
|
775
|
+
run: async (inputs, _ctx) => {
|
|
776
|
+
const selectedProtocolDid = String(inputs.selectedProtocolDid || "").trim();
|
|
777
|
+
const selectedProtocolName = String(inputs.selectedProtocolName || "").trim();
|
|
778
|
+
const selectedProtocolType = String(inputs.selectedProtocolType || "").trim();
|
|
779
|
+
if (!selectedProtocolDid) throw new Error("selectedProtocolDid is required");
|
|
780
|
+
return {
|
|
781
|
+
output: {
|
|
782
|
+
selectedProtocolDid,
|
|
783
|
+
selectedProtocolName,
|
|
784
|
+
selectedProtocolType
|
|
785
|
+
}
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
// src/mantine/blocks/domainCreator/utils/buildVerifiableCredential.ts
|
|
791
|
+
var DOMAIN_CARD_CONTEXT = [
|
|
792
|
+
"https://w3id.org/ixo/context/v1",
|
|
793
|
+
{
|
|
794
|
+
schema: "https://schema.org/",
|
|
795
|
+
ixo: "https://w3id.org/ixo/vocab/v1",
|
|
796
|
+
prov: "http://www.w3.org/ns/prov#",
|
|
797
|
+
proj: "http://www.w3.org/ns/project#",
|
|
798
|
+
id: "@id",
|
|
799
|
+
type: "@type",
|
|
800
|
+
"@protected": true
|
|
801
|
+
}
|
|
802
|
+
];
|
|
803
|
+
var DOMAIN_CARD_SCHEMA = {
|
|
804
|
+
id: "https://w3id.org/ixo/protocol/schema/v1#domainCard",
|
|
805
|
+
type: "JsonSchema"
|
|
806
|
+
};
|
|
807
|
+
function toISOString(dateInput, fallback = /* @__PURE__ */ new Date()) {
|
|
808
|
+
if (!dateInput) {
|
|
809
|
+
return fallback.toISOString();
|
|
810
|
+
}
|
|
811
|
+
if (dateInput instanceof Date) {
|
|
812
|
+
return dateInput.toISOString();
|
|
813
|
+
}
|
|
814
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(dateInput)) {
|
|
815
|
+
return (/* @__PURE__ */ new Date(dateInput + "T00:00:00.000Z")).toISOString();
|
|
816
|
+
}
|
|
817
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(dateInput)) {
|
|
818
|
+
return (/* @__PURE__ */ new Date(dateInput + ":00.000Z")).toISOString();
|
|
819
|
+
}
|
|
820
|
+
const parsed = new Date(dateInput);
|
|
821
|
+
if (!isNaN(parsed.getTime())) {
|
|
822
|
+
return parsed.toISOString();
|
|
823
|
+
}
|
|
824
|
+
return fallback.toISOString();
|
|
825
|
+
}
|
|
826
|
+
function getDefaultValidUntil(validFrom) {
|
|
827
|
+
const fromDate = new Date(validFrom);
|
|
828
|
+
const untilDate = new Date(fromDate);
|
|
829
|
+
untilDate.setFullYear(untilDate.getFullYear() + 5);
|
|
830
|
+
return untilDate.toISOString();
|
|
831
|
+
}
|
|
832
|
+
function buildVerifiableCredential(params) {
|
|
833
|
+
const { entityDid, issuerDid, credentialSubject, validFrom, validUntil } = params;
|
|
834
|
+
const validFromISO = toISOString(validFrom);
|
|
835
|
+
const validUntilISO = validUntil ? toISOString(validUntil) : getDefaultValidUntil(validFromISO);
|
|
836
|
+
return {
|
|
837
|
+
"@context": DOMAIN_CARD_CONTEXT,
|
|
838
|
+
id: `${entityDid}#dmn`,
|
|
839
|
+
type: ["VerifiableCredential", "ixo:DomainCard"],
|
|
840
|
+
issuer: {
|
|
841
|
+
id: issuerDid
|
|
842
|
+
},
|
|
843
|
+
validFrom: validFromISO,
|
|
844
|
+
validUntil: validUntilISO,
|
|
845
|
+
credentialSchema: DOMAIN_CARD_SCHEMA,
|
|
846
|
+
credentialSubject: {
|
|
847
|
+
...credentialSubject,
|
|
848
|
+
// Ensure the subject ID matches the entity DID
|
|
849
|
+
id: entityDid
|
|
850
|
+
}
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
function buildDomainCardLinkedResource(params) {
|
|
854
|
+
return {
|
|
855
|
+
id: `${params.entityDid}#dmn`,
|
|
856
|
+
type: "domainCard",
|
|
857
|
+
proof: params.cid,
|
|
858
|
+
right: "",
|
|
859
|
+
encrypted: "false",
|
|
860
|
+
mediaType: "application/json",
|
|
861
|
+
description: params.description || "Domain Card",
|
|
862
|
+
serviceEndpoint: params.serviceEndpoint
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// src/mantine/blocks/domainCreatorSign/utils/buildLinkedEntityResource.ts
|
|
867
|
+
function parseLinkedEntities(entitiesString) {
|
|
868
|
+
if (!entitiesString || entitiesString === "[]") return [];
|
|
869
|
+
try {
|
|
870
|
+
return JSON.parse(entitiesString);
|
|
871
|
+
} catch {
|
|
872
|
+
return [];
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
function buildGovernanceGroupLinkedEntities(linkedEntities) {
|
|
876
|
+
return linkedEntities.filter((entity) => entity.type === "governanceGroup" && entity.coreAddress).map((entity) => ({
|
|
877
|
+
id: entity.coreAddress,
|
|
878
|
+
type: "group",
|
|
879
|
+
relationship: "governs",
|
|
880
|
+
service: ""
|
|
881
|
+
}));
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// src/core/lib/actionRegistry/actions/domainSign.ts
|
|
885
|
+
registerAction({
|
|
886
|
+
type: "domain.sign",
|
|
887
|
+
sideEffect: true,
|
|
888
|
+
defaultRequiresConfirmation: true,
|
|
889
|
+
requiredCapability: "flow/block/execute",
|
|
890
|
+
outputSchema: [
|
|
891
|
+
{ path: "entityDid", displayName: "Entity DID", type: "string", description: "The DID of the newly created domain entity" },
|
|
892
|
+
{ path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "The on-chain transaction hash for domain creation" }
|
|
893
|
+
],
|
|
894
|
+
run: async (inputs, ctx) => {
|
|
895
|
+
const handlers = ctx.handlers;
|
|
896
|
+
if (!handlers) {
|
|
897
|
+
throw new Error("Handlers not available");
|
|
898
|
+
}
|
|
899
|
+
if (!handlers.requestPin) throw new Error("requestPin handler not available");
|
|
900
|
+
if (!handlers.signCredential) throw new Error("signCredential handler not implemented");
|
|
901
|
+
if (!handlers.publicFileUpload) throw new Error("publicFileUpload handler not available");
|
|
902
|
+
if (!handlers.createDomain) throw new Error("createDomain handler not implemented");
|
|
903
|
+
let domainCardData;
|
|
904
|
+
if (typeof inputs.domainCardData === "string") {
|
|
905
|
+
try {
|
|
906
|
+
domainCardData = JSON.parse(inputs.domainCardData);
|
|
907
|
+
} catch {
|
|
908
|
+
throw new Error("domainCardData must be valid JSON");
|
|
909
|
+
}
|
|
910
|
+
} else if (inputs.domainCardData && typeof inputs.domainCardData === "object") {
|
|
911
|
+
domainCardData = inputs.domainCardData;
|
|
912
|
+
} else {
|
|
913
|
+
throw new Error("domainCardData is required");
|
|
914
|
+
}
|
|
915
|
+
if (!domainCardData?.credentialSubject?.name) {
|
|
916
|
+
throw new Error("domainCardData is missing or invalid (credentialSubject.name required)");
|
|
917
|
+
}
|
|
918
|
+
const extractEntityType = (type) => type.replace(/^schema:/i, "").toLowerCase();
|
|
919
|
+
const entityType = String(inputs.entityType || "").trim() || (domainCardData.credentialSubject?.type?.[0] ? extractEntityType(domainCardData.credentialSubject.type[0]) : "dao");
|
|
920
|
+
const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
|
|
921
|
+
if (!issuerDid) throw new Error("Unable to determine issuer DID");
|
|
922
|
+
const entityDidPlaceholder = "did:ixo:entity:pending";
|
|
923
|
+
const validFrom = domainCardData.validFrom || (/* @__PURE__ */ new Date()).toISOString();
|
|
924
|
+
const validUntil = domainCardData.validUntil || (() => {
|
|
925
|
+
const d = /* @__PURE__ */ new Date();
|
|
926
|
+
d.setFullYear(d.getFullYear() + 100);
|
|
927
|
+
return d.toISOString();
|
|
928
|
+
})();
|
|
929
|
+
const credentialSubject = {
|
|
930
|
+
...domainCardData.credentialSubject,
|
|
931
|
+
id: entityDidPlaceholder
|
|
932
|
+
};
|
|
933
|
+
const unsignedCredential = buildVerifiableCredential({
|
|
934
|
+
entityDid: entityDidPlaceholder,
|
|
935
|
+
issuerDid,
|
|
936
|
+
credentialSubject,
|
|
937
|
+
validFrom,
|
|
938
|
+
validUntil
|
|
939
|
+
});
|
|
940
|
+
const pin = await handlers.requestPin({
|
|
941
|
+
title: "Sign Domain Card",
|
|
942
|
+
description: "Enter your PIN to sign the Domain Card credential",
|
|
943
|
+
submitText: "Sign"
|
|
944
|
+
});
|
|
945
|
+
const { signedCredential } = await handlers.signCredential({
|
|
946
|
+
issuerDid,
|
|
947
|
+
issuerType: "user",
|
|
948
|
+
credential: unsignedCredential,
|
|
949
|
+
pin
|
|
950
|
+
});
|
|
951
|
+
const credentialBlob = new Blob([JSON.stringify(signedCredential, null, 2)], {
|
|
952
|
+
type: "application/json"
|
|
953
|
+
});
|
|
954
|
+
const credentialFile = new File([credentialBlob], "domainCard.json", {
|
|
955
|
+
type: "application/json"
|
|
956
|
+
});
|
|
957
|
+
const uploadResult = await handlers.publicFileUpload(credentialFile);
|
|
958
|
+
const domainCardLinkedResource = buildDomainCardLinkedResource({
|
|
959
|
+
entityDid: entityDidPlaceholder,
|
|
960
|
+
cid: uploadResult.cid,
|
|
961
|
+
serviceEndpoint: uploadResult.url,
|
|
962
|
+
description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
|
|
963
|
+
});
|
|
964
|
+
let linkedEntitiesData = [];
|
|
965
|
+
if (inputs.linkedEntities) {
|
|
966
|
+
if (typeof inputs.linkedEntities === "string") {
|
|
967
|
+
try {
|
|
968
|
+
linkedEntitiesData = JSON.parse(inputs.linkedEntities);
|
|
969
|
+
} catch {
|
|
970
|
+
}
|
|
971
|
+
} else if (Array.isArray(inputs.linkedEntities)) {
|
|
972
|
+
linkedEntitiesData = inputs.linkedEntities;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
const governanceGroupLinkedEntities = buildGovernanceGroupLinkedEntities(parseLinkedEntities(JSON.stringify(linkedEntitiesData)));
|
|
976
|
+
const endDate = domainCardData.endDate || validUntil;
|
|
977
|
+
const { entityDid: newEntityDid, transactionHash } = await handlers.createDomain({
|
|
978
|
+
entityType,
|
|
979
|
+
linkedResource: [domainCardLinkedResource],
|
|
980
|
+
linkedEntity: governanceGroupLinkedEntities.length > 0 ? governanceGroupLinkedEntities : void 0,
|
|
981
|
+
startDate: validFrom,
|
|
982
|
+
endDate
|
|
983
|
+
});
|
|
984
|
+
return {
|
|
985
|
+
output: {
|
|
986
|
+
entityDid: newEntityDid,
|
|
987
|
+
transactionHash
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
|
|
993
|
+
// src/mantine/blocks/domainCreator/utils/transformSurveyToCredentialSubject.ts
|
|
994
|
+
function extractPanelDynamicItems(surveyData, panelName, itemMapper) {
|
|
995
|
+
const items = surveyData[panelName];
|
|
996
|
+
if (!Array.isArray(items)) return [];
|
|
997
|
+
return items.map(itemMapper).filter((item) => item !== null);
|
|
998
|
+
}
|
|
999
|
+
function parseCommaSeparated(value) {
|
|
1000
|
+
if (!value || typeof value !== "string") return [];
|
|
1001
|
+
return value.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1002
|
+
}
|
|
1003
|
+
function parseLanguageCodes(value) {
|
|
1004
|
+
return parseCommaSeparated(value);
|
|
1005
|
+
}
|
|
1006
|
+
function buildImageObject(url) {
|
|
1007
|
+
if (!url) return null;
|
|
1008
|
+
return {
|
|
1009
|
+
type: "schema:ImageObject",
|
|
1010
|
+
id: url,
|
|
1011
|
+
contentUrl: url
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
function transformSurveyToCredentialSubject(surveyData, entityDid) {
|
|
1015
|
+
const types = [];
|
|
1016
|
+
if (surveyData["type_1"]) types.push(`ixo:${surveyData["type_1"]}`);
|
|
1017
|
+
if (surveyData["type_2"]) types.push(surveyData["type_2"]);
|
|
1018
|
+
const additionalType = [];
|
|
1019
|
+
if (surveyData["daoType"]) additionalType.push(surveyData["daoType"]);
|
|
1020
|
+
const alternateNames = extractPanelDynamicItems(surveyData, "pannel_schema:alternateName", (item) => item["schema:alternateName"] || null);
|
|
1021
|
+
const sameAsUrls = extractPanelDynamicItems(surveyData, "schema:sameAs", (item) => item["schema:sameAs.url"] || null);
|
|
1022
|
+
const logoUrl = surveyData["ixo:imageLogo_url"] || surveyData["ixo:imageLogo"]?.[0]?.content;
|
|
1023
|
+
const logo = buildImageObject(logoUrl);
|
|
1024
|
+
const profileImageUrl = surveyData["ixo:imageProfile_url"] || surveyData["ixo:imageProfile"]?.[0]?.content;
|
|
1025
|
+
const profileImage = buildImageObject(profileImageUrl);
|
|
1026
|
+
const keywords = parseCommaSeparated(surveyData["schema:keywords"]);
|
|
1027
|
+
const knowsAbout = extractPanelDynamicItems(surveyData, "pannel_ixo:knowsAbout", (item) => item["ixo:knowsAbout"] || null);
|
|
1028
|
+
const hasAddressData = surveyData["schema:streetAddress"] || surveyData["schema:addressLocality"] || surveyData["schema:addressRegion"] || surveyData["schema:postalCode"] || surveyData["schema:addressCountry"];
|
|
1029
|
+
const address = hasAddressData ? {
|
|
1030
|
+
type: "schema:PostalAddress",
|
|
1031
|
+
streetAddress: surveyData["schema:streetAddress"] || void 0,
|
|
1032
|
+
addressLocality: surveyData["schema:addressLocality"] || void 0,
|
|
1033
|
+
addressRegion: surveyData["schema:addressRegion"] || void 0,
|
|
1034
|
+
postalCode: surveyData["schema:postalCode"] || void 0,
|
|
1035
|
+
addressCountry: surveyData["schema:addressCountry"] || void 0
|
|
1036
|
+
} : void 0;
|
|
1037
|
+
const areaServed = surveyData["schema:AdministrativeArea"] ? {
|
|
1038
|
+
type: "schema:AdministrativeArea",
|
|
1039
|
+
name: surveyData["schema:AdministrativeArea"]
|
|
1040
|
+
} : void 0;
|
|
1041
|
+
const contactPoints = extractPanelDynamicItems(surveyData, "pannel:schema_contactPoint", (item) => {
|
|
1042
|
+
if (!item["schema:contactType"] && !item["schema:email"] && !item["schema:telephone"]) return null;
|
|
1043
|
+
return {
|
|
1044
|
+
type: "schema:ContactPoint",
|
|
1045
|
+
contactType: item["schema:contactType"] || "general",
|
|
1046
|
+
email: item["schema:email"] || void 0,
|
|
1047
|
+
telephone: item["schema:telephone"] || void 0,
|
|
1048
|
+
availableLanguage: parseLanguageCodes(item["schema:availableLanguage"])
|
|
1049
|
+
};
|
|
1050
|
+
});
|
|
1051
|
+
const hasParts = extractPanelDynamicItems(surveyData, "schema:hasPart", (item) => {
|
|
1052
|
+
if (!item["schema:hasPart.name"] && !item["schema:hasPart.id"]) return null;
|
|
1053
|
+
return {
|
|
1054
|
+
type: "schema:CreativeWork",
|
|
1055
|
+
id: item["schema:hasPart.id"] || void 0,
|
|
1056
|
+
name: item["schema:hasPart.name"] || void 0,
|
|
1057
|
+
description: item["schema:hasPart.description"] || void 0,
|
|
1058
|
+
url: item["schema:hasPart.url"] || void 0,
|
|
1059
|
+
creator: item["schema:hasPart.creator.name"] ? {
|
|
1060
|
+
type: "schema:Organization",
|
|
1061
|
+
name: item["schema:hasPart.creator.name"]
|
|
1062
|
+
} : void 0
|
|
1063
|
+
};
|
|
1064
|
+
});
|
|
1065
|
+
const subjectOf = extractPanelDynamicItems(surveyData, "schema:subjectOf", (item) => {
|
|
1066
|
+
if (!item["schema:subjectOf.name"]) return null;
|
|
1067
|
+
return {
|
|
1068
|
+
type: "schema:CreativeWork",
|
|
1069
|
+
name: item["schema:subjectOf.name"],
|
|
1070
|
+
url: item["schema:subjectOf.url"] || void 0,
|
|
1071
|
+
author: item["schema:subjectOf.author.name"] ? {
|
|
1072
|
+
type: "schema:Organisation",
|
|
1073
|
+
name: item["schema:subjectOf.author.name"]
|
|
1074
|
+
} : void 0
|
|
1075
|
+
};
|
|
1076
|
+
});
|
|
1077
|
+
const composition = hasParts.length > 0 || subjectOf.length > 0 ? {
|
|
1078
|
+
type: "schema:Collection",
|
|
1079
|
+
hasPart: hasParts.length > 0 ? hasParts : void 0,
|
|
1080
|
+
subjectOf: subjectOf.length > 0 ? subjectOf : void 0
|
|
1081
|
+
} : void 0;
|
|
1082
|
+
const makesOffer = extractPanelDynamicItems(surveyData, "schema:makesOffer", (item) => {
|
|
1083
|
+
if (!item["schema:itemOffered.name"]) return null;
|
|
1084
|
+
return {
|
|
1085
|
+
type: "schema:Offer",
|
|
1086
|
+
itemOffered: {
|
|
1087
|
+
type: item["schema:itemOffered.type"] === "service" ? "schema:Service" : "schema:Product",
|
|
1088
|
+
name: item["schema:itemOffered.name"] || void 0,
|
|
1089
|
+
description: item["schema:itemOffered.description"] || void 0,
|
|
1090
|
+
url: item["schema:itemOffered.url"] || void 0
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
});
|
|
1094
|
+
const memberOf = extractPanelDynamicItems(surveyData, "schema:memberOf", (item) => {
|
|
1095
|
+
if (!item["schema:memberOf.name"]) return null;
|
|
1096
|
+
return {
|
|
1097
|
+
type: "schema:Organization",
|
|
1098
|
+
name: item["schema:memberOf.name"]
|
|
1099
|
+
};
|
|
1100
|
+
});
|
|
1101
|
+
const wasAssociatedWith = extractPanelDynamicItems(surveyData, "schema:wasAssociatedWith", (item) => {
|
|
1102
|
+
if (!item["schema:wasAssociatedWith.name"]) return null;
|
|
1103
|
+
return {
|
|
1104
|
+
type: "schema:Organization",
|
|
1105
|
+
name: item["schema:wasAssociatedWith.name"],
|
|
1106
|
+
url: item["schema:wasAssociatedWith.url"] || void 0
|
|
1107
|
+
};
|
|
1108
|
+
});
|
|
1109
|
+
const funding = extractPanelDynamicItems(surveyData, "schema:funding", (item) => {
|
|
1110
|
+
if (!item["schema:funder.name"]) return null;
|
|
1111
|
+
return {
|
|
1112
|
+
type: "schema:MonetaryGrant",
|
|
1113
|
+
funder: {
|
|
1114
|
+
type: "schema:Organization",
|
|
1115
|
+
name: item["schema:funder.name"]
|
|
1116
|
+
},
|
|
1117
|
+
amount: item["schema:amount.value"] || item["schema:amount.currency"] ? {
|
|
1118
|
+
type: "schema:MonetaryAmount",
|
|
1119
|
+
currency: item["schema:amount.currency"] || "USD",
|
|
1120
|
+
value: item["schema:amount.value"] || "0"
|
|
1121
|
+
} : void 0
|
|
1122
|
+
};
|
|
1123
|
+
});
|
|
1124
|
+
const relationships = memberOf.length > 0 || wasAssociatedWith.length > 0 || funding.length > 0 ? {
|
|
1125
|
+
memberOf: memberOf.length > 0 ? memberOf : void 0,
|
|
1126
|
+
"prov:wasAssociatedWith": wasAssociatedWith.length > 0 ? wasAssociatedWith : void 0,
|
|
1127
|
+
funding: funding.length > 0 ? funding : void 0
|
|
1128
|
+
} : void 0;
|
|
1129
|
+
const agents = extractPanelDynamicItems(surveyData, "ixo:agentCard", (item) => {
|
|
1130
|
+
if (!item["ixo:agentCard.name"] && !item["ixo:agentCard.id"]) return null;
|
|
1131
|
+
return {
|
|
1132
|
+
type: "ixo:AgentCard",
|
|
1133
|
+
id: item["ixo:agentCard.id"] || void 0,
|
|
1134
|
+
name: item["ixo:agentCard.name"] || void 0,
|
|
1135
|
+
description: item["ixo:agentCard.description"] || void 0
|
|
1136
|
+
};
|
|
1137
|
+
});
|
|
1138
|
+
const credentials = extractPanelDynamicItems(surveyData, "ixo:verifiableCredential", (item) => {
|
|
1139
|
+
if (!item["schema:Name"] && !item["schema:ID"]) return null;
|
|
1140
|
+
return {
|
|
1141
|
+
type: "VerifiableCredential",
|
|
1142
|
+
id: item["schema:ID"] || void 0,
|
|
1143
|
+
name: item["schema:Name"] || void 0,
|
|
1144
|
+
description: item["schema:description"] || void 0
|
|
1145
|
+
};
|
|
1146
|
+
});
|
|
1147
|
+
const attributes = extractPanelDynamicItems(surveyData, "ixo:attribute", (item) => {
|
|
1148
|
+
if (!item["schema:name_2"]) return null;
|
|
1149
|
+
return {
|
|
1150
|
+
"@type": "ixo:Attribute",
|
|
1151
|
+
"@id": item["schema:ID_2"] || `attribute:${item["schema:name_2"].replace(/\s+/g, "_").toLowerCase()}`,
|
|
1152
|
+
name: item["schema:name_2"],
|
|
1153
|
+
value: item["schema:description_2"] || ""
|
|
1154
|
+
};
|
|
1155
|
+
});
|
|
1156
|
+
const projects = extractPanelDynamicItems(surveyData, "pannel_proj:project", (item) => {
|
|
1157
|
+
if (!item["proj:project.name"]) return null;
|
|
1158
|
+
const objectives = extractPanelDynamicItems(item, "proj:project.hadObjective", (objItem) => objItem["proj:hadObjective"] || null);
|
|
1159
|
+
const projectFunding = extractPanelDynamicItems(item, "proj:wasFundedThrough", (fundItem) => ({
|
|
1160
|
+
type: "proj:FundingAssociation",
|
|
1161
|
+
moneyAmount: fundItem["proj:moneyAmount"] || void 0,
|
|
1162
|
+
moneyCurrency: fundItem["proj:moneyCurrency"] || void 0,
|
|
1163
|
+
agent: fundItem["prov.agent.name"] || fundItem["prov:agent.id"] ? {
|
|
1164
|
+
type: "prov:Agent",
|
|
1165
|
+
id: fundItem["prov:agent.id"] || void 0,
|
|
1166
|
+
name: fundItem["prov.agent.name"] || void 0
|
|
1167
|
+
} : void 0
|
|
1168
|
+
}));
|
|
1169
|
+
return {
|
|
1170
|
+
type: "proj:Project",
|
|
1171
|
+
name: item["proj:project.name"],
|
|
1172
|
+
description: item["proj:project.description"] || void 0,
|
|
1173
|
+
hadObjective: objectives.length > 0 ? objectives : void 0,
|
|
1174
|
+
plannedStart: item["proj:plannedStart"] || void 0,
|
|
1175
|
+
plannedEnd: item["proj:plannedEnd"] || void 0,
|
|
1176
|
+
wasFundedThrough: projectFunding.length > 0 ? projectFunding : void 0
|
|
1177
|
+
};
|
|
1178
|
+
});
|
|
1179
|
+
const project = projects.length > 0 ? projects[0] : void 0;
|
|
1180
|
+
const seedQueries = extractPanelDynamicItems(surveyData, "ixo:ResearchProfile", (item) => item["ixo:seedQueries"] || null);
|
|
1181
|
+
const citations = extractPanelDynamicItems(surveyData, "schema:creativeWork", (item) => {
|
|
1182
|
+
if (!item["schema:creativeWork.name"]) return null;
|
|
1183
|
+
return {
|
|
1184
|
+
type: "schema:CreativeWork",
|
|
1185
|
+
name: item["schema:creativeWork.name"],
|
|
1186
|
+
url: item["schema:creativeWork.url"] || void 0,
|
|
1187
|
+
publisher: item["schema:creativeWork.publisher"] || void 0,
|
|
1188
|
+
datePublished: item["schema:creativeWork.datePublished"] || void 0
|
|
1189
|
+
};
|
|
1190
|
+
});
|
|
1191
|
+
const researchProfile = seedQueries.length > 0 || citations.length > 0 ? {
|
|
1192
|
+
type: "ixo:ResearchProfile",
|
|
1193
|
+
"ixo:seedQueries": seedQueries.length > 0 ? seedQueries : void 0,
|
|
1194
|
+
citation: citations.length > 0 ? citations : void 0,
|
|
1195
|
+
dateModified: (/* @__PURE__ */ new Date()).toISOString()
|
|
1196
|
+
} : void 0;
|
|
1197
|
+
const credentialSubject = {
|
|
1198
|
+
id: entityDid,
|
|
1199
|
+
type: types.length > 0 ? types : ["ixo:dao"],
|
|
1200
|
+
name: surveyData["schema:name"] || "",
|
|
1201
|
+
description: surveyData["schema.description"] || ""
|
|
1202
|
+
};
|
|
1203
|
+
if (additionalType.length > 0) credentialSubject.additionalType = additionalType;
|
|
1204
|
+
if (alternateNames.length > 0) credentialSubject.alternateName = alternateNames;
|
|
1205
|
+
if (surveyData["schema:url"]) credentialSubject.url = surveyData["schema:url"];
|
|
1206
|
+
if (sameAsUrls.length > 0) credentialSubject.sameAs = sameAsUrls;
|
|
1207
|
+
if (logo) credentialSubject.logo = logo;
|
|
1208
|
+
if (profileImage) credentialSubject.image = [profileImage];
|
|
1209
|
+
if (keywords.length > 0) credentialSubject.keywords = keywords;
|
|
1210
|
+
if (knowsAbout.length > 0) credentialSubject.knowsAbout = knowsAbout;
|
|
1211
|
+
if (address) credentialSubject.address = address;
|
|
1212
|
+
if (areaServed) credentialSubject.areaServed = areaServed;
|
|
1213
|
+
if (contactPoints.length > 0) credentialSubject.contactPoint = contactPoints;
|
|
1214
|
+
if (composition) credentialSubject.composition = composition;
|
|
1215
|
+
if (makesOffer.length > 0) credentialSubject.makesOffer = makesOffer;
|
|
1216
|
+
if (relationships) credentialSubject.relationships = relationships;
|
|
1217
|
+
if (agents.length > 0) credentialSubject.agents = agents;
|
|
1218
|
+
if (credentials.length > 0) credentialSubject.credentials = credentials;
|
|
1219
|
+
if (attributes.length > 0) credentialSubject.attributes = attributes;
|
|
1220
|
+
if (project) credentialSubject.project = project;
|
|
1221
|
+
if (researchProfile) credentialSubject.researchProfile = researchProfile;
|
|
1222
|
+
return credentialSubject;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// src/mantine/blocks/domainCreator/utils/extractSurveyAnswersTemplate.ts
|
|
1226
|
+
function extractFieldsFromElements(elements, fields) {
|
|
1227
|
+
for (const element of elements) {
|
|
1228
|
+
if (element.type === "panel" && element.elements) {
|
|
1229
|
+
extractFieldsFromElements(element.elements, fields);
|
|
1230
|
+
continue;
|
|
1231
|
+
}
|
|
1232
|
+
if (element.type === "paneldynamic" && element.name) {
|
|
1233
|
+
fields[element.name] = [];
|
|
1234
|
+
if (element.templateElements) {
|
|
1235
|
+
extractFieldsFromElements(element.templateElements, fields);
|
|
1236
|
+
}
|
|
1237
|
+
continue;
|
|
1238
|
+
}
|
|
1239
|
+
if (element.name && element.type !== "panel") {
|
|
1240
|
+
switch (element.type) {
|
|
1241
|
+
case "boolean":
|
|
1242
|
+
fields[element.name] = false;
|
|
1243
|
+
break;
|
|
1244
|
+
case "checkbox":
|
|
1245
|
+
fields[element.name] = [];
|
|
1246
|
+
break;
|
|
1247
|
+
case "file":
|
|
1248
|
+
fields[element.name] = [];
|
|
1249
|
+
break;
|
|
1250
|
+
default:
|
|
1251
|
+
fields[element.name] = "";
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
if (element.elements) {
|
|
1255
|
+
extractFieldsFromElements(element.elements, fields);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
function extractSurveyAnswersTemplate(surveyDef) {
|
|
1260
|
+
const fields = {};
|
|
1261
|
+
for (const page of surveyDef.pages) {
|
|
1262
|
+
extractFieldsFromElements(page.elements, fields);
|
|
1263
|
+
}
|
|
1264
|
+
return fields;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
// src/core/lib/actionRegistry/actions/domainCreate.ts
|
|
1268
|
+
registerAction({
|
|
1269
|
+
type: "domain.create",
|
|
1270
|
+
sideEffect: true,
|
|
1271
|
+
defaultRequiresConfirmation: true,
|
|
1272
|
+
requiredCapability: "flow/block/execute",
|
|
1273
|
+
outputSchema: [
|
|
1274
|
+
{ path: "entityDid", displayName: "Entity DID", type: "string", description: "The created domain entity DID" },
|
|
1275
|
+
{ path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "Blockchain transaction hash" },
|
|
1276
|
+
{ path: "credentialId", displayName: "Credential ID", type: "string", description: "The uploaded domain card credential identifier (CID)" },
|
|
1277
|
+
{ path: "entityType", displayName: "Entity Type", type: "string", description: "The type of domain entity created" }
|
|
1278
|
+
],
|
|
1279
|
+
run: async (inputs, ctx) => {
|
|
1280
|
+
const handlers = ctx.handlers;
|
|
1281
|
+
if (!handlers) throw new Error("Handlers not available");
|
|
1282
|
+
if (!handlers.signCredential) throw new Error("signCredential handler not implemented");
|
|
1283
|
+
if (!handlers.publicFileUpload) throw new Error("publicFileUpload handler not available");
|
|
1284
|
+
if (!handlers.createDomain) throw new Error("createDomain handler not implemented");
|
|
1285
|
+
if (!handlers.requestPin) throw new Error("requestPin handler not available");
|
|
1286
|
+
const configEntityType = String(inputs.entityType || "dao").trim();
|
|
1287
|
+
let surveyData = {};
|
|
1288
|
+
if (inputs.surveyData) {
|
|
1289
|
+
if (typeof inputs.surveyData === "string") {
|
|
1290
|
+
try {
|
|
1291
|
+
surveyData = JSON.parse(inputs.surveyData);
|
|
1292
|
+
} catch {
|
|
1293
|
+
throw new Error("surveyData must be valid JSON");
|
|
1294
|
+
}
|
|
1295
|
+
} else if (typeof inputs.surveyData === "object" && !Array.isArray(inputs.surveyData)) {
|
|
1296
|
+
surveyData = inputs.surveyData;
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
|
|
1300
|
+
if (!issuerDid) throw new Error("Unable to determine issuer DID");
|
|
1301
|
+
const entityDid = "did:ixo:entity:pending";
|
|
1302
|
+
const credentialSubject = transformSurveyToCredentialSubject(surveyData, entityDid);
|
|
1303
|
+
const unsignedCredential = buildVerifiableCredential({
|
|
1304
|
+
entityDid,
|
|
1305
|
+
issuerDid,
|
|
1306
|
+
credentialSubject,
|
|
1307
|
+
validFrom: surveyData["schema:validFrom"] || (/* @__PURE__ */ new Date()).toISOString(),
|
|
1308
|
+
validUntil: surveyData["schema:validUntil"]
|
|
1309
|
+
});
|
|
1310
|
+
const pin = await handlers.requestPin({
|
|
1311
|
+
title: "Sign Domain Card",
|
|
1312
|
+
description: "Enter your PIN to sign the Domain Card credential",
|
|
1313
|
+
submitText: "Sign"
|
|
1314
|
+
});
|
|
1315
|
+
const { signedCredential } = await handlers.signCredential({
|
|
1316
|
+
issuerDid,
|
|
1317
|
+
issuerType: "user",
|
|
1318
|
+
credential: unsignedCredential,
|
|
1319
|
+
pin
|
|
1320
|
+
});
|
|
1321
|
+
const credentialBlob = new Blob([JSON.stringify(signedCredential, null, 2)], {
|
|
1322
|
+
type: "application/json"
|
|
1323
|
+
});
|
|
1324
|
+
const credentialFile = new File([credentialBlob], "domainCard.json", {
|
|
1325
|
+
type: "application/json"
|
|
1326
|
+
});
|
|
1327
|
+
const uploadResult = await handlers.publicFileUpload(credentialFile);
|
|
1328
|
+
const domainCardLinkedResource = buildDomainCardLinkedResource({
|
|
1329
|
+
entityDid,
|
|
1330
|
+
cid: uploadResult.cid,
|
|
1331
|
+
serviceEndpoint: uploadResult.url,
|
|
1332
|
+
description: `Domain Card for ${surveyData["schema:name"] || "Domain"}`
|
|
1333
|
+
});
|
|
1334
|
+
const finalEntityType = surveyData["type_2"] || surveyData["daoType"] || configEntityType;
|
|
1335
|
+
const { entityDid: newEntityDid, transactionHash } = await handlers.createDomain({
|
|
1336
|
+
entityType: finalEntityType,
|
|
1337
|
+
linkedResource: [domainCardLinkedResource],
|
|
1338
|
+
startDate: surveyData["schema:validFrom"],
|
|
1339
|
+
endDate: surveyData["schema:validUntil"]
|
|
1340
|
+
});
|
|
1341
|
+
return {
|
|
1342
|
+
output: {
|
|
1343
|
+
entityDid: newEntityDid,
|
|
1344
|
+
transactionHash,
|
|
1345
|
+
credentialId: uploadResult.cid,
|
|
1346
|
+
entityType: finalEntityType
|
|
1347
|
+
}
|
|
1348
|
+
};
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
|
|
1352
|
+
// src/core/lib/actionRegistry/actions/oracle.ts
|
|
1353
|
+
registerAction({
|
|
1354
|
+
type: "oracle",
|
|
1355
|
+
sideEffect: false,
|
|
1356
|
+
defaultRequiresConfirmation: false,
|
|
1357
|
+
outputSchema: [{ path: "prompt", displayName: "Prompt", type: "string", description: "The prompt sent to the companion" }],
|
|
1358
|
+
run: async (inputs, ctx) => {
|
|
1359
|
+
const prompt = String(inputs.prompt || "").trim();
|
|
1360
|
+
if (!prompt) throw new Error("prompt is required");
|
|
1361
|
+
if (!ctx.handlers?.askCompanion) {
|
|
1362
|
+
throw new Error("askCompanion handler is not available");
|
|
1363
|
+
}
|
|
1364
|
+
await ctx.handlers.askCompanion(prompt);
|
|
1365
|
+
return {
|
|
1366
|
+
output: { prompt }
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
// src/core/lib/actionRegistry/actions/credentialStore.ts
|
|
1372
|
+
registerAction({
|
|
1373
|
+
type: "credential.store",
|
|
1374
|
+
sideEffect: true,
|
|
1375
|
+
defaultRequiresConfirmation: true,
|
|
1376
|
+
requiredCapability: "flow/execute",
|
|
1377
|
+
outputSchema: [
|
|
1378
|
+
{ path: "credentialKey", displayName: "Credential Key", type: "string", description: "Key under which credential was stored (e.g. kycamllevel1)" },
|
|
1379
|
+
{ path: "cid", displayName: "Content ID", type: "string", description: "IPFS-compatible CID of the credential (used for deduplication)" },
|
|
1380
|
+
{ path: "storedAt", displayName: "Stored At", type: "string", description: "ISO timestamp of when the credential was stored" },
|
|
1381
|
+
{ path: "duplicate", displayName: "Duplicate", type: "boolean", description: "Whether this credential was already stored (matched by CID)" }
|
|
1382
|
+
],
|
|
1383
|
+
run: async (inputs, ctx) => {
|
|
1384
|
+
const { credential, credentialKey, roomId } = inputs;
|
|
1385
|
+
if (!credentialKey) throw new Error("credentialKey is required");
|
|
1386
|
+
if (!credential) throw new Error("credential is required");
|
|
1387
|
+
let parsedCredential = credential;
|
|
1388
|
+
if (typeof parsedCredential === "string") {
|
|
1389
|
+
for (let i = 0; i < 3 && typeof parsedCredential === "string"; i++) {
|
|
1390
|
+
try {
|
|
1391
|
+
parsedCredential = JSON.parse(parsedCredential);
|
|
1392
|
+
} catch {
|
|
1393
|
+
throw new Error("credential must be a valid JSON object or JSON string");
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
if (typeof parsedCredential !== "object" || parsedCredential === null || Array.isArray(parsedCredential)) {
|
|
1398
|
+
throw new Error("credential must be a JSON object");
|
|
1399
|
+
}
|
|
1400
|
+
if (!ctx.services.matrix?.storeCredential) {
|
|
1401
|
+
throw new Error("Matrix credential storage service not configured");
|
|
1402
|
+
}
|
|
1403
|
+
const { computeJsonCID } = await import("./cid-6O646X2I.mjs");
|
|
1404
|
+
const cid = await computeJsonCID(parsedCredential);
|
|
1405
|
+
const result = await ctx.services.matrix.storeCredential({
|
|
1406
|
+
roomId: roomId || "",
|
|
1407
|
+
credentialKey: String(credentialKey),
|
|
1408
|
+
credential: parsedCredential,
|
|
1409
|
+
cid
|
|
1410
|
+
});
|
|
1411
|
+
return {
|
|
1412
|
+
output: {
|
|
1413
|
+
credentialKey: String(credentialKey),
|
|
1414
|
+
cid,
|
|
1415
|
+
storedAt: result.storedAt,
|
|
1416
|
+
duplicate: result.duplicate
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1421
|
+
|
|
1422
|
+
// src/core/lib/actionRegistry/actions/payment.ts
|
|
1423
|
+
registerAction({
|
|
1424
|
+
type: "payment",
|
|
1425
|
+
sideEffect: true,
|
|
1426
|
+
defaultRequiresConfirmation: true,
|
|
1427
|
+
requiredCapability: "flow/block/execute",
|
|
1428
|
+
outputSchema: [
|
|
1429
|
+
{ path: "transactionId", displayName: "Transaction ID", type: "string", description: "Payment transaction identifier from the provider" },
|
|
1430
|
+
{ path: "status", displayName: "Status", type: "string", description: "Payment status (proposed, submitted, pending, completed, failed)" },
|
|
1431
|
+
{ path: "proposal", displayName: "Proposal", type: "object", description: "Payment proposal object for review before execution" },
|
|
1432
|
+
{ path: "summary", displayName: "Summary", type: "object", description: "Human-readable payment summary" }
|
|
1433
|
+
],
|
|
1434
|
+
run: async (inputs, ctx) => {
|
|
1435
|
+
const config = inputs.paymentConfig;
|
|
1436
|
+
if (!config || typeof config === "string" && !config.trim()) {
|
|
1437
|
+
throw new Error("paymentConfig is required");
|
|
1438
|
+
}
|
|
1439
|
+
if (!ctx.handlers?.askCompanion) {
|
|
1440
|
+
throw new Error("askCompanion handler is not available");
|
|
1441
|
+
}
|
|
1442
|
+
const parsed = typeof config === "string" ? JSON.parse(config) : config;
|
|
1443
|
+
const configJson = JSON.stringify(parsed, null, 2);
|
|
1444
|
+
await ctx.handlers.askCompanion(
|
|
1445
|
+
[
|
|
1446
|
+
"Execute payment action with this configuration.",
|
|
1447
|
+
"IMPORTANT: First read the flow context and settings \u2014 the flow may contain parameters required by the skill. Also review all blocks in the flow to understand the basic workflow before executing.",
|
|
1448
|
+
`Payment configuration JSON:
|
|
1449
|
+
${configJson}`
|
|
1450
|
+
].join("\n")
|
|
1451
|
+
);
|
|
1452
|
+
return {
|
|
1453
|
+
output: {
|
|
1454
|
+
status: "requested",
|
|
1455
|
+
paymentConfig: parsed
|
|
1456
|
+
}
|
|
1457
|
+
};
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
|
|
1461
|
+
// src/core/lib/ucanDelegationStore.ts
|
|
1462
|
+
var ROOT_DELEGATION_KEY = "__root__";
|
|
1463
|
+
var MIGRATION_VERSION_KEY = "__version__";
|
|
1464
|
+
var CURRENT_VERSION = 2;
|
|
1465
|
+
var isNewFormat = (value) => {
|
|
1466
|
+
if (!value || typeof value !== "object") return false;
|
|
1467
|
+
const entry = value;
|
|
1468
|
+
return entry.v === CURRENT_VERSION && entry.data !== void 0;
|
|
1469
|
+
};
|
|
1470
|
+
var isLegacyFormat = (value) => {
|
|
1471
|
+
return typeof value === "string";
|
|
1472
|
+
};
|
|
1473
|
+
var parseLegacy = (value) => {
|
|
1474
|
+
try {
|
|
1475
|
+
return JSON.parse(value);
|
|
1476
|
+
} catch {
|
|
1477
|
+
return null;
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
var legacyToStoredDelegation = (legacy) => {
|
|
1481
|
+
return {
|
|
1482
|
+
cid: legacy.id,
|
|
1483
|
+
delegation: "",
|
|
1484
|
+
// Empty - CAR requires re-signing
|
|
1485
|
+
issuerDid: legacy.issuer,
|
|
1486
|
+
audienceDid: legacy.audience,
|
|
1487
|
+
capabilities: legacy.capabilities.map((c) => ({
|
|
1488
|
+
can: c.can,
|
|
1489
|
+
with: c.with,
|
|
1490
|
+
nb: c.nb
|
|
1491
|
+
})),
|
|
1492
|
+
expiration: legacy.expiration,
|
|
1493
|
+
createdAt: legacy.issuedAt ? new Date(legacy.issuedAt).getTime() : Date.now(),
|
|
1494
|
+
format: "legacy",
|
|
1495
|
+
proofCids: legacy.proofs
|
|
1496
|
+
};
|
|
1497
|
+
};
|
|
1498
|
+
var createUcanDelegationStore = (yMap) => {
|
|
1499
|
+
const get = (cid) => {
|
|
1500
|
+
if (cid === ROOT_DELEGATION_KEY || cid === MIGRATION_VERSION_KEY) return null;
|
|
1501
|
+
const raw = yMap.get(cid);
|
|
1502
|
+
if (!raw) return null;
|
|
1503
|
+
if (isNewFormat(raw)) {
|
|
1504
|
+
return raw.data;
|
|
1505
|
+
}
|
|
1506
|
+
if (isLegacyFormat(raw)) {
|
|
1507
|
+
const legacy = parseLegacy(raw);
|
|
1508
|
+
if (legacy) {
|
|
1509
|
+
return legacyToStoredDelegation(legacy);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
return null;
|
|
1513
|
+
};
|
|
1514
|
+
const set = (delegation) => {
|
|
1515
|
+
const entry = {
|
|
1516
|
+
v: CURRENT_VERSION,
|
|
1517
|
+
data: delegation
|
|
1518
|
+
};
|
|
1519
|
+
yMap.set(delegation.cid, entry);
|
|
1520
|
+
};
|
|
1521
|
+
const remove = (cid) => {
|
|
1522
|
+
yMap.delete(cid);
|
|
1523
|
+
};
|
|
1524
|
+
const has = (cid) => {
|
|
1525
|
+
return yMap.has(cid) && cid !== ROOT_DELEGATION_KEY && cid !== MIGRATION_VERSION_KEY;
|
|
1526
|
+
};
|
|
1527
|
+
const getRoot = () => {
|
|
1528
|
+
const rootCid = yMap.get(ROOT_DELEGATION_KEY);
|
|
1529
|
+
if (!rootCid) return null;
|
|
1530
|
+
return get(rootCid);
|
|
1531
|
+
};
|
|
1532
|
+
const setRootCid = (cid) => {
|
|
1533
|
+
yMap.set(ROOT_DELEGATION_KEY, cid);
|
|
1534
|
+
};
|
|
1535
|
+
const getRootCid = () => {
|
|
1536
|
+
return yMap.get(ROOT_DELEGATION_KEY) || null;
|
|
1537
|
+
};
|
|
1538
|
+
const getAll = () => {
|
|
1539
|
+
const delegations = [];
|
|
1540
|
+
yMap.forEach((value, key) => {
|
|
1541
|
+
if (key === ROOT_DELEGATION_KEY || key === MIGRATION_VERSION_KEY) return;
|
|
1542
|
+
if (isNewFormat(value)) {
|
|
1543
|
+
delegations.push(value.data);
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
if (isLegacyFormat(value)) {
|
|
1547
|
+
const legacy = parseLegacy(value);
|
|
1548
|
+
if (legacy) {
|
|
1549
|
+
delegations.push(legacyToStoredDelegation(legacy));
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
return delegations;
|
|
1554
|
+
};
|
|
1555
|
+
const getByAudience = (audienceDid) => {
|
|
1556
|
+
return getAll().filter((d) => d.audienceDid === audienceDid);
|
|
1557
|
+
};
|
|
1558
|
+
const getByIssuer = (issuerDid) => {
|
|
1559
|
+
return getAll().filter((d) => d.issuerDid === issuerDid);
|
|
1560
|
+
};
|
|
1561
|
+
const findByCapability = (can, withUri) => {
|
|
1562
|
+
return getAll().filter(
|
|
1563
|
+
(d) => d.capabilities.some((c) => {
|
|
1564
|
+
if (c.can === can && c.with === withUri) return true;
|
|
1565
|
+
if (c.can === "*" || c.can === "flow/*") return true;
|
|
1566
|
+
if (c.can.endsWith("/*")) {
|
|
1567
|
+
const prefix = c.can.slice(0, -1);
|
|
1568
|
+
if (can.startsWith(prefix)) return true;
|
|
1569
|
+
}
|
|
1570
|
+
if (c.with === "*") return true;
|
|
1571
|
+
if (c.with.endsWith("*")) {
|
|
1572
|
+
const prefix = c.with.slice(0, -1);
|
|
1573
|
+
if (withUri.startsWith(prefix)) return true;
|
|
1574
|
+
}
|
|
1575
|
+
return false;
|
|
1576
|
+
})
|
|
1577
|
+
);
|
|
1578
|
+
};
|
|
1579
|
+
const getVersion = () => {
|
|
1580
|
+
const version = yMap.get(MIGRATION_VERSION_KEY);
|
|
1581
|
+
return version ?? 1;
|
|
1582
|
+
};
|
|
1583
|
+
const setVersion = (version) => {
|
|
1584
|
+
yMap.set(MIGRATION_VERSION_KEY, version);
|
|
1585
|
+
};
|
|
1586
|
+
const getLegacy = (id) => {
|
|
1587
|
+
if (id === ROOT_DELEGATION_KEY || id === MIGRATION_VERSION_KEY) return null;
|
|
1588
|
+
const raw = yMap.get(id);
|
|
1589
|
+
if (!raw) return null;
|
|
1590
|
+
if (isLegacyFormat(raw)) {
|
|
1591
|
+
return parseLegacy(raw);
|
|
1592
|
+
}
|
|
1593
|
+
return null;
|
|
1594
|
+
};
|
|
1595
|
+
const hasLegacy = (id) => {
|
|
1596
|
+
if (id === ROOT_DELEGATION_KEY || id === MIGRATION_VERSION_KEY) return false;
|
|
1597
|
+
const raw = yMap.get(id);
|
|
1598
|
+
return isLegacyFormat(raw);
|
|
1599
|
+
};
|
|
1600
|
+
const getAllLegacy = () => {
|
|
1601
|
+
const legacyDelegations = [];
|
|
1602
|
+
yMap.forEach((value, key) => {
|
|
1603
|
+
if (key === ROOT_DELEGATION_KEY || key === MIGRATION_VERSION_KEY) return;
|
|
1604
|
+
if (isLegacyFormat(value)) {
|
|
1605
|
+
const legacy = parseLegacy(value);
|
|
1606
|
+
if (legacy) {
|
|
1607
|
+
legacyDelegations.push(legacy);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
});
|
|
1611
|
+
return legacyDelegations;
|
|
1612
|
+
};
|
|
1613
|
+
const convertLegacyToStored = (legacy) => {
|
|
1614
|
+
return legacyToStoredDelegation(legacy);
|
|
1615
|
+
};
|
|
1616
|
+
return {
|
|
1617
|
+
get,
|
|
1618
|
+
set,
|
|
1619
|
+
remove,
|
|
1620
|
+
has,
|
|
1621
|
+
getRoot,
|
|
1622
|
+
setRootCid,
|
|
1623
|
+
getRootCid,
|
|
1624
|
+
getAll,
|
|
1625
|
+
getByAudience,
|
|
1626
|
+
getByIssuer,
|
|
1627
|
+
findByCapability,
|
|
1628
|
+
getVersion,
|
|
1629
|
+
setVersion,
|
|
1630
|
+
getLegacy,
|
|
1631
|
+
hasLegacy,
|
|
1632
|
+
getAllLegacy,
|
|
1633
|
+
convertLegacyToStored
|
|
1634
|
+
};
|
|
1635
|
+
};
|
|
1636
|
+
var createMemoryUcanDelegationStore = () => {
|
|
1637
|
+
const store = /* @__PURE__ */ new Map();
|
|
1638
|
+
const get = (cid) => {
|
|
1639
|
+
if (cid === ROOT_DELEGATION_KEY || cid === MIGRATION_VERSION_KEY) return null;
|
|
1640
|
+
const raw = store.get(cid);
|
|
1641
|
+
if (!raw) return null;
|
|
1642
|
+
if (isNewFormat(raw)) {
|
|
1643
|
+
return raw.data;
|
|
1644
|
+
}
|
|
1645
|
+
if (isLegacyFormat(raw)) {
|
|
1646
|
+
const legacy = parseLegacy(raw);
|
|
1647
|
+
if (legacy) {
|
|
1648
|
+
return legacyToStoredDelegation(legacy);
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
return null;
|
|
1652
|
+
};
|
|
1653
|
+
const set = (delegation) => {
|
|
1654
|
+
const entry = {
|
|
1655
|
+
v: CURRENT_VERSION,
|
|
1656
|
+
data: delegation
|
|
1657
|
+
};
|
|
1658
|
+
store.set(delegation.cid, entry);
|
|
1659
|
+
};
|
|
1660
|
+
const remove = (cid) => {
|
|
1661
|
+
store.delete(cid);
|
|
1662
|
+
};
|
|
1663
|
+
const has = (cid) => {
|
|
1664
|
+
return store.has(cid) && cid !== ROOT_DELEGATION_KEY && cid !== MIGRATION_VERSION_KEY;
|
|
1665
|
+
};
|
|
1666
|
+
const getRoot = () => {
|
|
1667
|
+
const rootCid = store.get(ROOT_DELEGATION_KEY);
|
|
1668
|
+
if (!rootCid) return null;
|
|
1669
|
+
return get(rootCid);
|
|
1670
|
+
};
|
|
1671
|
+
const setRootCid = (cid) => {
|
|
1672
|
+
store.set(ROOT_DELEGATION_KEY, cid);
|
|
1673
|
+
};
|
|
1674
|
+
const getRootCid = () => {
|
|
1675
|
+
return store.get(ROOT_DELEGATION_KEY) || null;
|
|
1676
|
+
};
|
|
1677
|
+
const getAll = () => {
|
|
1678
|
+
const delegations = [];
|
|
1679
|
+
store.forEach((value, key) => {
|
|
1680
|
+
if (key === ROOT_DELEGATION_KEY || key === MIGRATION_VERSION_KEY) return;
|
|
1681
|
+
if (isNewFormat(value)) {
|
|
1682
|
+
delegations.push(value.data);
|
|
1683
|
+
return;
|
|
1684
|
+
}
|
|
1685
|
+
if (isLegacyFormat(value)) {
|
|
1686
|
+
const legacy = parseLegacy(value);
|
|
1687
|
+
if (legacy) {
|
|
1688
|
+
delegations.push(legacyToStoredDelegation(legacy));
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
});
|
|
1692
|
+
return delegations;
|
|
1693
|
+
};
|
|
1694
|
+
const getByAudience = (audienceDid) => {
|
|
1695
|
+
return getAll().filter((d) => d.audienceDid === audienceDid);
|
|
1696
|
+
};
|
|
1697
|
+
const getByIssuer = (issuerDid) => {
|
|
1698
|
+
return getAll().filter((d) => d.issuerDid === issuerDid);
|
|
1699
|
+
};
|
|
1700
|
+
const findByCapability = (can, withUri) => {
|
|
1701
|
+
return getAll().filter(
|
|
1702
|
+
(d) => d.capabilities.some((c) => {
|
|
1703
|
+
if (c.can === can && c.with === withUri) return true;
|
|
1704
|
+
if (c.can === "*" || c.can === "flow/*") return true;
|
|
1705
|
+
if (c.can.endsWith("/*")) {
|
|
1706
|
+
const prefix = c.can.slice(0, -1);
|
|
1707
|
+
if (can.startsWith(prefix)) return true;
|
|
1708
|
+
}
|
|
1709
|
+
if (c.with === "*") return true;
|
|
1710
|
+
if (c.with.endsWith("*")) {
|
|
1711
|
+
const prefix = c.with.slice(0, -1);
|
|
1712
|
+
if (withUri.startsWith(prefix)) return true;
|
|
1713
|
+
}
|
|
1714
|
+
return false;
|
|
1715
|
+
})
|
|
1716
|
+
);
|
|
1717
|
+
};
|
|
1718
|
+
const getVersion = () => {
|
|
1719
|
+
const version = store.get(MIGRATION_VERSION_KEY);
|
|
1720
|
+
return version ?? 1;
|
|
1721
|
+
};
|
|
1722
|
+
const setVersion = (version) => {
|
|
1723
|
+
store.set(MIGRATION_VERSION_KEY, version);
|
|
1724
|
+
};
|
|
1725
|
+
const getLegacy = (id) => {
|
|
1726
|
+
if (id === ROOT_DELEGATION_KEY || id === MIGRATION_VERSION_KEY) return null;
|
|
1727
|
+
const raw = store.get(id);
|
|
1728
|
+
if (!raw) return null;
|
|
1729
|
+
if (isLegacyFormat(raw)) {
|
|
1730
|
+
return parseLegacy(raw);
|
|
1731
|
+
}
|
|
1732
|
+
return null;
|
|
1733
|
+
};
|
|
1734
|
+
const hasLegacy = (id) => {
|
|
1735
|
+
if (id === ROOT_DELEGATION_KEY || id === MIGRATION_VERSION_KEY) return false;
|
|
1736
|
+
const raw = store.get(id);
|
|
1737
|
+
return isLegacyFormat(raw);
|
|
1738
|
+
};
|
|
1739
|
+
const getAllLegacy = () => {
|
|
1740
|
+
const legacyDelegations = [];
|
|
1741
|
+
store.forEach((value, key) => {
|
|
1742
|
+
if (key === ROOT_DELEGATION_KEY || key === MIGRATION_VERSION_KEY) return;
|
|
1743
|
+
if (isLegacyFormat(value)) {
|
|
1744
|
+
const legacy = parseLegacy(value);
|
|
1745
|
+
if (legacy) {
|
|
1746
|
+
legacyDelegations.push(legacy);
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1750
|
+
return legacyDelegations;
|
|
1751
|
+
};
|
|
1752
|
+
const convertLegacyToStored = (legacy) => {
|
|
1753
|
+
return legacyToStoredDelegation(legacy);
|
|
1754
|
+
};
|
|
1755
|
+
return {
|
|
1756
|
+
get,
|
|
1757
|
+
set,
|
|
1758
|
+
remove,
|
|
1759
|
+
has,
|
|
1760
|
+
getRoot,
|
|
1761
|
+
setRootCid,
|
|
1762
|
+
getRootCid,
|
|
1763
|
+
getAll,
|
|
1764
|
+
getByAudience,
|
|
1765
|
+
getByIssuer,
|
|
1766
|
+
findByCapability,
|
|
1767
|
+
getVersion,
|
|
1768
|
+
setVersion,
|
|
1769
|
+
getLegacy,
|
|
1770
|
+
hasLegacy,
|
|
1771
|
+
getAllLegacy,
|
|
1772
|
+
convertLegacyToStored
|
|
1773
|
+
};
|
|
1774
|
+
};
|
|
1775
|
+
|
|
1776
|
+
// src/core/lib/invocationStore.ts
|
|
1777
|
+
var createInvocationStore = (yMap) => {
|
|
1778
|
+
const add = (invocation) => {
|
|
1779
|
+
yMap.set(invocation.cid, invocation);
|
|
1780
|
+
};
|
|
1781
|
+
const get = (cid) => {
|
|
1782
|
+
const raw = yMap.get(cid);
|
|
1783
|
+
if (!raw || typeof raw !== "object") return null;
|
|
1784
|
+
return raw;
|
|
1785
|
+
};
|
|
1786
|
+
const remove = (cid) => {
|
|
1787
|
+
yMap.delete(cid);
|
|
1788
|
+
};
|
|
1789
|
+
const getAll = () => {
|
|
1790
|
+
const invocations = [];
|
|
1791
|
+
yMap.forEach((value) => {
|
|
1792
|
+
if (value && typeof value === "object" && "cid" in value) {
|
|
1793
|
+
invocations.push(value);
|
|
1794
|
+
}
|
|
1795
|
+
});
|
|
1796
|
+
return invocations.sort((a, b) => b.executedAt - a.executedAt);
|
|
1797
|
+
};
|
|
1798
|
+
const getByInvoker = (invokerDid) => {
|
|
1799
|
+
return getAll().filter((i) => i.invokerDid === invokerDid);
|
|
1800
|
+
};
|
|
1801
|
+
const getByFlow = (flowId) => {
|
|
1802
|
+
return getAll().filter((i) => i.flowId === flowId);
|
|
1803
|
+
};
|
|
1804
|
+
const getByBlock = (flowId, blockId) => {
|
|
1805
|
+
return getAll().filter((i) => i.flowId === flowId && i.blockId === blockId);
|
|
1806
|
+
};
|
|
1807
|
+
const getByCapability = (can, withUri) => {
|
|
1808
|
+
return getAll().filter((i) => i.capability.can === can && i.capability.with === withUri);
|
|
1809
|
+
};
|
|
1810
|
+
const hasBeenInvoked = (cid) => {
|
|
1811
|
+
return yMap.has(cid);
|
|
1812
|
+
};
|
|
1813
|
+
const getInDateRange = (startMs, endMs) => {
|
|
1814
|
+
return getAll().filter((i) => i.executedAt >= startMs && i.executedAt <= endMs);
|
|
1815
|
+
};
|
|
1816
|
+
const getSuccessful = () => {
|
|
1817
|
+
return getAll().filter((i) => i.result === "success");
|
|
1818
|
+
};
|
|
1819
|
+
const getFailures = () => {
|
|
1820
|
+
return getAll().filter((i) => i.result === "failure");
|
|
1821
|
+
};
|
|
1822
|
+
const getPendingSubmission = () => {
|
|
1823
|
+
return getAll().filter((i) => i.result === "success" && !i.transactionHash);
|
|
1824
|
+
};
|
|
1825
|
+
const markSubmitted = (cid, transactionHash) => {
|
|
1826
|
+
const invocation = get(cid);
|
|
1827
|
+
if (invocation) {
|
|
1828
|
+
const updated = {
|
|
1829
|
+
...invocation,
|
|
1830
|
+
transactionHash
|
|
1831
|
+
};
|
|
1832
|
+
yMap.set(cid, updated);
|
|
1833
|
+
}
|
|
1834
|
+
};
|
|
1835
|
+
const getCount = () => {
|
|
1836
|
+
return getAll().length;
|
|
1837
|
+
};
|
|
1838
|
+
const getCountByResult = () => {
|
|
1839
|
+
const all = getAll();
|
|
1840
|
+
return {
|
|
1841
|
+
success: all.filter((i) => i.result === "success").length,
|
|
1842
|
+
failure: all.filter((i) => i.result === "failure").length
|
|
1843
|
+
};
|
|
1844
|
+
};
|
|
1845
|
+
return {
|
|
1846
|
+
add,
|
|
1847
|
+
get,
|
|
1848
|
+
remove,
|
|
1849
|
+
getAll,
|
|
1850
|
+
getByInvoker,
|
|
1851
|
+
getByFlow,
|
|
1852
|
+
getByBlock,
|
|
1853
|
+
getByCapability,
|
|
1854
|
+
hasBeenInvoked,
|
|
1855
|
+
getInDateRange,
|
|
1856
|
+
getSuccessful,
|
|
1857
|
+
getFailures,
|
|
1858
|
+
getPendingSubmission,
|
|
1859
|
+
markSubmitted,
|
|
1860
|
+
getCount,
|
|
1861
|
+
getCountByResult
|
|
1862
|
+
};
|
|
1863
|
+
};
|
|
1864
|
+
var createMemoryInvocationStore = () => {
|
|
1865
|
+
const store = /* @__PURE__ */ new Map();
|
|
1866
|
+
const add = (invocation) => {
|
|
1867
|
+
store.set(invocation.cid, invocation);
|
|
1868
|
+
};
|
|
1869
|
+
const get = (cid) => {
|
|
1870
|
+
return store.get(cid) || null;
|
|
1871
|
+
};
|
|
1872
|
+
const remove = (cid) => {
|
|
1873
|
+
store.delete(cid);
|
|
1874
|
+
};
|
|
1875
|
+
const getAll = () => {
|
|
1876
|
+
const invocations = Array.from(store.values());
|
|
1877
|
+
return invocations.sort((a, b) => b.executedAt - a.executedAt);
|
|
1878
|
+
};
|
|
1879
|
+
const getByInvoker = (invokerDid) => {
|
|
1880
|
+
return getAll().filter((i) => i.invokerDid === invokerDid);
|
|
1881
|
+
};
|
|
1882
|
+
const getByFlow = (flowId) => {
|
|
1883
|
+
return getAll().filter((i) => i.flowId === flowId);
|
|
1884
|
+
};
|
|
1885
|
+
const getByBlock = (flowId, blockId) => {
|
|
1886
|
+
return getAll().filter((i) => i.flowId === flowId && i.blockId === blockId);
|
|
1887
|
+
};
|
|
1888
|
+
const getByCapability = (can, withUri) => {
|
|
1889
|
+
return getAll().filter((i) => i.capability.can === can && i.capability.with === withUri);
|
|
1890
|
+
};
|
|
1891
|
+
const hasBeenInvoked = (cid) => {
|
|
1892
|
+
return store.has(cid);
|
|
1893
|
+
};
|
|
1894
|
+
const getInDateRange = (startMs, endMs) => {
|
|
1895
|
+
return getAll().filter((i) => i.executedAt >= startMs && i.executedAt <= endMs);
|
|
1896
|
+
};
|
|
1897
|
+
const getSuccessful = () => {
|
|
1898
|
+
return getAll().filter((i) => i.result === "success");
|
|
1899
|
+
};
|
|
1900
|
+
const getFailures = () => {
|
|
1901
|
+
return getAll().filter((i) => i.result === "failure");
|
|
1902
|
+
};
|
|
1903
|
+
const getPendingSubmission = () => {
|
|
1904
|
+
return getAll().filter((i) => i.result === "success" && !i.transactionHash);
|
|
1905
|
+
};
|
|
1906
|
+
const markSubmitted = (cid, transactionHash) => {
|
|
1907
|
+
const invocation = get(cid);
|
|
1908
|
+
if (invocation) {
|
|
1909
|
+
store.set(cid, { ...invocation, transactionHash });
|
|
1910
|
+
}
|
|
1911
|
+
};
|
|
1912
|
+
const getCount = () => {
|
|
1913
|
+
return store.size;
|
|
1914
|
+
};
|
|
1915
|
+
const getCountByResult = () => {
|
|
1916
|
+
const all = getAll();
|
|
1917
|
+
return {
|
|
1918
|
+
success: all.filter((i) => i.result === "success").length,
|
|
1919
|
+
failure: all.filter((i) => i.result === "failure").length
|
|
1920
|
+
};
|
|
1921
|
+
};
|
|
1922
|
+
return {
|
|
1923
|
+
add,
|
|
1924
|
+
get,
|
|
1925
|
+
remove,
|
|
1926
|
+
getAll,
|
|
1927
|
+
getByInvoker,
|
|
1928
|
+
getByFlow,
|
|
1929
|
+
getByBlock,
|
|
1930
|
+
getByCapability,
|
|
1931
|
+
hasBeenInvoked,
|
|
1932
|
+
getInDateRange,
|
|
1933
|
+
getSuccessful,
|
|
1934
|
+
getFailures,
|
|
1935
|
+
getPendingSubmission,
|
|
1936
|
+
markSubmitted,
|
|
1937
|
+
getCount,
|
|
1938
|
+
getCountByResult
|
|
1939
|
+
};
|
|
1940
|
+
};
|
|
1941
|
+
|
|
1942
|
+
// src/core/lib/flowEngine/utils.ts
|
|
1943
|
+
var parseActors = (value) => {
|
|
1944
|
+
if (!value) return [];
|
|
1945
|
+
if (Array.isArray(value)) {
|
|
1946
|
+
return value.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
1947
|
+
}
|
|
1948
|
+
if (typeof value === "string") {
|
|
1949
|
+
const trimmed = value.trim();
|
|
1950
|
+
if (!trimmed) return [];
|
|
1951
|
+
try {
|
|
1952
|
+
const parsed = JSON.parse(trimmed);
|
|
1953
|
+
if (Array.isArray(parsed)) {
|
|
1954
|
+
return parsed.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
|
|
1955
|
+
}
|
|
1956
|
+
} catch {
|
|
1957
|
+
}
|
|
1958
|
+
return trimmed.split(",").map((item) => item.trim()).filter(Boolean);
|
|
1959
|
+
}
|
|
1960
|
+
return [];
|
|
1961
|
+
};
|
|
1962
|
+
var parseActivationStatus = (value) => {
|
|
1963
|
+
if (value === "pending" || value === "approved" || value === "rejected") {
|
|
1964
|
+
return value;
|
|
1965
|
+
}
|
|
1966
|
+
return void 0;
|
|
1967
|
+
};
|
|
1968
|
+
var buildAuthzFromProps = (props) => {
|
|
1969
|
+
const authorisedActors = parseActors(props.authorisedActors);
|
|
1970
|
+
const activationRequiredStatus = parseActivationStatus(props.activationRequiredStatus);
|
|
1971
|
+
const activationUpstreamNodeId = typeof props.activationUpstreamNodeId === "string" ? props.activationUpstreamNodeId.trim() : "";
|
|
1972
|
+
const linkedClaimCollectionId = typeof props.linkedClaimCollectionId === "string" ? props.linkedClaimCollectionId.trim() : "";
|
|
1973
|
+
const authz = {};
|
|
1974
|
+
if (typeof props.parentCapability === "string" && props.parentCapability.trim()) {
|
|
1975
|
+
authz.parentCapability = props.parentCapability.trim();
|
|
1976
|
+
}
|
|
1977
|
+
if (authorisedActors.length > 0) {
|
|
1978
|
+
authz.authorisedActors = authorisedActors;
|
|
1979
|
+
}
|
|
1980
|
+
if (linkedClaimCollectionId) {
|
|
1981
|
+
authz.linkedClaim = { collectionId: linkedClaimCollectionId };
|
|
1982
|
+
}
|
|
1983
|
+
if (activationUpstreamNodeId && activationRequiredStatus) {
|
|
1984
|
+
authz.activationCondition = {
|
|
1985
|
+
upstreamNodeId: activationUpstreamNodeId,
|
|
1986
|
+
requiredStatus: activationRequiredStatus,
|
|
1987
|
+
requireAuthorisedActor: Boolean(props.activationRequireAuthorisedActor)
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
return authz;
|
|
1991
|
+
};
|
|
1992
|
+
var buildFlowNodeFromBlock = (block) => {
|
|
1993
|
+
const base = {
|
|
1994
|
+
id: block.id,
|
|
1995
|
+
type: block.type,
|
|
1996
|
+
props: block.props || {}
|
|
1997
|
+
};
|
|
1998
|
+
const authz = buildAuthzFromProps(block.props || {});
|
|
1999
|
+
return {
|
|
2000
|
+
...base,
|
|
2001
|
+
...authz
|
|
2002
|
+
};
|
|
2003
|
+
};
|
|
2004
|
+
|
|
2005
|
+
// src/core/lib/flowEngine/runtime.ts
|
|
2006
|
+
var ensureStateObject = (value) => {
|
|
2007
|
+
if (!value || typeof value !== "object") {
|
|
2008
|
+
return {};
|
|
2009
|
+
}
|
|
2010
|
+
return { ...value };
|
|
2011
|
+
};
|
|
2012
|
+
var createYMapManager = (map) => {
|
|
2013
|
+
return {
|
|
2014
|
+
get: (nodeId) => {
|
|
2015
|
+
const stored = map.get(nodeId);
|
|
2016
|
+
return ensureStateObject(stored);
|
|
2017
|
+
},
|
|
2018
|
+
update: (nodeId, updates) => {
|
|
2019
|
+
const current = ensureStateObject(map.get(nodeId));
|
|
2020
|
+
map.set(nodeId, { ...current, ...updates });
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
};
|
|
2024
|
+
var createMemoryManager = () => {
|
|
2025
|
+
const memory = /* @__PURE__ */ new Map();
|
|
2026
|
+
return {
|
|
2027
|
+
get: (nodeId) => ensureStateObject(memory.get(nodeId)),
|
|
2028
|
+
update: (nodeId, updates) => {
|
|
2029
|
+
const current = ensureStateObject(memory.get(nodeId));
|
|
2030
|
+
memory.set(nodeId, { ...current, ...updates });
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
2033
|
+
};
|
|
2034
|
+
var createRuntimeStateManager = (editor) => {
|
|
2035
|
+
if (editor?._yRuntime) {
|
|
2036
|
+
return createYMapManager(editor._yRuntime);
|
|
2037
|
+
}
|
|
2038
|
+
return createMemoryManager();
|
|
2039
|
+
};
|
|
2040
|
+
function clearRuntimeForTemplateClone(yDoc) {
|
|
2041
|
+
const runtime = yDoc.getMap("runtime");
|
|
2042
|
+
const invocations = yDoc.getMap("invocations");
|
|
2043
|
+
yDoc.transact(() => {
|
|
2044
|
+
runtime.forEach((_, key) => runtime.delete(key));
|
|
2045
|
+
invocations.forEach((_, key) => invocations.delete(key));
|
|
2046
|
+
});
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
// src/core/lib/flowEngine/activation.ts
|
|
2050
|
+
var isNodeActive = (node, runtime) => {
|
|
2051
|
+
if (!node.activationCondition) {
|
|
2052
|
+
return { active: true };
|
|
2053
|
+
}
|
|
2054
|
+
const { upstreamNodeId, requiredStatus, requireAuthorisedActor } = node.activationCondition;
|
|
2055
|
+
if (!upstreamNodeId) {
|
|
2056
|
+
return { active: true };
|
|
2057
|
+
}
|
|
2058
|
+
const upstreamState = runtime.get(upstreamNodeId);
|
|
2059
|
+
if (!upstreamState.claimId) {
|
|
2060
|
+
return { active: false, reason: `Upstream node ${upstreamNodeId} has no claim submission yet.` };
|
|
2061
|
+
}
|
|
2062
|
+
if (upstreamState.evaluationStatus !== requiredStatus) {
|
|
2063
|
+
return {
|
|
2064
|
+
active: false,
|
|
2065
|
+
reason: `Upstream node ${upstreamNodeId} status is ${upstreamState.evaluationStatus || "unknown"}, requires ${requiredStatus}.`
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
if (requireAuthorisedActor) {
|
|
2069
|
+
const upstreamActor = upstreamState.submittedByDid;
|
|
2070
|
+
if (!upstreamActor) {
|
|
2071
|
+
return { active: false, reason: "Upstream submission actor is unknown." };
|
|
2072
|
+
}
|
|
2073
|
+
const upstreamAuthorised = Array.isArray(upstreamState.authorisedActorsSnapshot) ? upstreamState.authorisedActorsSnapshot : [];
|
|
2074
|
+
if (upstreamAuthorised.length > 0 && !upstreamAuthorised.includes(upstreamActor)) {
|
|
2075
|
+
return { active: false, reason: "Upstream claim not submitted by an authorised actor." };
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
return { active: true };
|
|
2079
|
+
};
|
|
2080
|
+
|
|
2081
|
+
// src/core/lib/flowEngine/capabilityValidation.ts
|
|
2082
|
+
var capabilityCovers = (granted, required) => {
|
|
2083
|
+
if (granted.can !== required.can && granted.can !== "*") {
|
|
2084
|
+
if (granted.can.endsWith("/*")) {
|
|
2085
|
+
const prefix = granted.can.slice(0, -2);
|
|
2086
|
+
if (!required.can.startsWith(prefix)) return false;
|
|
2087
|
+
} else {
|
|
2088
|
+
return false;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
if (granted.with !== required.with && granted.with !== "*") {
|
|
2092
|
+
if (granted.with.endsWith("/*")) {
|
|
2093
|
+
const prefix = granted.with.slice(0, -2);
|
|
2094
|
+
if (!required.with.startsWith(prefix)) return false;
|
|
2095
|
+
} else if (granted.with.endsWith("*")) {
|
|
2096
|
+
const prefix = granted.with.slice(0, -1);
|
|
2097
|
+
if (!required.with.startsWith(prefix)) return false;
|
|
2098
|
+
} else {
|
|
2099
|
+
return false;
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
return true;
|
|
2103
|
+
};
|
|
2104
|
+
var validateCapabilityChain = async (params) => {
|
|
2105
|
+
const { capability, actorDid, requiredCapability, delegationStore, verifySignature, rootIssuer } = params;
|
|
2106
|
+
const chain = [];
|
|
2107
|
+
const visited = /* @__PURE__ */ new Set();
|
|
2108
|
+
let current = capability;
|
|
2109
|
+
while (current) {
|
|
2110
|
+
if (visited.has(current.id)) {
|
|
2111
|
+
return { valid: false, error: "Circular delegation detected" };
|
|
2112
|
+
}
|
|
2113
|
+
visited.add(current.id);
|
|
2114
|
+
chain.unshift(current);
|
|
2115
|
+
if (current.expiration && current.expiration < Date.now()) {
|
|
2116
|
+
return { valid: false, error: `Capability ${current.id} has expired` };
|
|
2117
|
+
}
|
|
2118
|
+
const signatureResult = await verifySignature(JSON.stringify(current), current.issuer);
|
|
2119
|
+
if (!signatureResult.valid) {
|
|
2120
|
+
return { valid: false, error: `Invalid signature on capability ${current.id}: ${signatureResult.error}` };
|
|
2121
|
+
}
|
|
2122
|
+
if (current.proofs.length === 0) {
|
|
2123
|
+
if (current.issuer !== rootIssuer) {
|
|
2124
|
+
return { valid: false, error: `Root capability issuer mismatch. Expected ${rootIssuer}, got ${current.issuer}` };
|
|
2125
|
+
}
|
|
2126
|
+
break;
|
|
2127
|
+
}
|
|
2128
|
+
const parentId = current.proofs[0];
|
|
2129
|
+
const parent = delegationStore.get(parentId);
|
|
2130
|
+
if (!parent) {
|
|
2131
|
+
return { valid: false, error: `Parent capability ${parentId} not found` };
|
|
2132
|
+
}
|
|
2133
|
+
if (parent.audience !== current.issuer) {
|
|
2134
|
+
return { valid: false, error: `Delegation chain broken: ${parent.audience} !== ${current.issuer}` };
|
|
2135
|
+
}
|
|
2136
|
+
current = parent;
|
|
2137
|
+
}
|
|
2138
|
+
const finalCap = chain[chain.length - 1];
|
|
2139
|
+
if (finalCap.audience !== actorDid) {
|
|
2140
|
+
return { valid: false, error: `Capability not granted to actor. Expected ${actorDid}, got ${finalCap.audience}` };
|
|
2141
|
+
}
|
|
2142
|
+
for (const cap of chain) {
|
|
2143
|
+
const hasRequiredCap = cap.capabilities.some((c) => capabilityCovers(c, requiredCapability));
|
|
2144
|
+
if (!hasRequiredCap) {
|
|
2145
|
+
return { valid: false, error: `Capability ${cap.id} does not grant required permission` };
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
return { valid: true, chain };
|
|
2149
|
+
};
|
|
2150
|
+
var findValidCapability = async (params) => {
|
|
2151
|
+
const { actorDid, requiredCapability, delegationStore, verifySignature, rootIssuer } = params;
|
|
2152
|
+
const allDelegations = delegationStore.getAll();
|
|
2153
|
+
const actorDelegations = allDelegations.filter((d) => d.audience === actorDid);
|
|
2154
|
+
for (const delegation of actorDelegations) {
|
|
2155
|
+
const result = await validateCapabilityChain({
|
|
2156
|
+
capability: delegation,
|
|
2157
|
+
actorDid,
|
|
2158
|
+
requiredCapability,
|
|
2159
|
+
delegationStore,
|
|
2160
|
+
verifySignature,
|
|
2161
|
+
rootIssuer
|
|
2162
|
+
});
|
|
2163
|
+
if (result.valid) {
|
|
2164
|
+
return { found: true, capabilityId: delegation.id };
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
const root = delegationStore.getRoot();
|
|
2168
|
+
if (root && root.audience === actorDid) {
|
|
2169
|
+
const result = await validateCapabilityChain({
|
|
2170
|
+
capability: root,
|
|
2171
|
+
actorDid,
|
|
2172
|
+
requiredCapability,
|
|
2173
|
+
delegationStore,
|
|
2174
|
+
verifySignature,
|
|
2175
|
+
rootIssuer
|
|
2176
|
+
});
|
|
2177
|
+
if (result.valid) {
|
|
2178
|
+
return { found: true, capabilityId: root.id };
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return { found: false, error: "No valid capability found for actor" };
|
|
2182
|
+
};
|
|
2183
|
+
|
|
2184
|
+
// src/core/lib/flowEngine/authorization.ts
|
|
2185
|
+
var isActorAuthorized = async (node, actorDid, context) => {
|
|
2186
|
+
if (node.authorisedActors && node.authorisedActors.length > 0) {
|
|
2187
|
+
if (!node.authorisedActors.includes(actorDid)) {
|
|
2188
|
+
return {
|
|
2189
|
+
authorized: false,
|
|
2190
|
+
reason: `Actor ${actorDid} is not in the authorized actors list for this block.`
|
|
2191
|
+
};
|
|
2192
|
+
}
|
|
2193
|
+
if (!node.parentCapability) {
|
|
2194
|
+
return { authorized: true };
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
if (node.parentCapability && context?.delegationStore && context?.verifySignature && context?.rootIssuer) {
|
|
2198
|
+
const requiredCapability = {
|
|
2199
|
+
can: "flow/block/execute",
|
|
2200
|
+
with: context.flowUri ? `${context.flowUri}:${node.id}` : `ixo:flow:*:${node.id}`
|
|
2201
|
+
};
|
|
2202
|
+
const result = await findValidCapability({
|
|
2203
|
+
actorDid,
|
|
2204
|
+
requiredCapability,
|
|
2205
|
+
delegationStore: context.delegationStore,
|
|
2206
|
+
verifySignature: context.verifySignature,
|
|
2207
|
+
rootIssuer: context.rootIssuer
|
|
2208
|
+
});
|
|
2209
|
+
if (!result.found) {
|
|
2210
|
+
return {
|
|
2211
|
+
authorized: false,
|
|
2212
|
+
reason: result.error || "No valid capability found"
|
|
2213
|
+
};
|
|
2214
|
+
}
|
|
2215
|
+
return { authorized: true, capabilityId: result.capabilityId };
|
|
2216
|
+
}
|
|
2217
|
+
if (node.parentCapability && context?.ucanManager) {
|
|
2218
|
+
try {
|
|
2219
|
+
const parent = await context.ucanManager.loadParentCapability(node.parentCapability);
|
|
2220
|
+
const derived = await context.ucanManager.deriveNodeCapability(parent, node.id, actorDid);
|
|
2221
|
+
await context.ucanManager.validateDerivedCapability(derived, node.id, actorDid);
|
|
2222
|
+
return { authorized: true, derived };
|
|
2223
|
+
} catch (error) {
|
|
2224
|
+
const message = error instanceof Error ? error.message : "Capability derivation failed";
|
|
2225
|
+
return { authorized: false, reason: message };
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
if (node.parentCapability && !context?.delegationStore && !context?.ucanManager) {
|
|
2229
|
+
return {
|
|
2230
|
+
authorized: false,
|
|
2231
|
+
reason: "Capability validation required but neither delegation store nor UCAN manager configured."
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
return { authorized: true };
|
|
2235
|
+
};
|
|
2236
|
+
var isActorAuthorizedV2 = async (node, actorDid, context) => {
|
|
2237
|
+
if (node.authorisedActors && node.authorisedActors.length > 0) {
|
|
2238
|
+
if (!node.authorisedActors.includes(actorDid)) {
|
|
2239
|
+
return {
|
|
2240
|
+
authorized: false,
|
|
2241
|
+
reason: `Actor ${actorDid} is not in the authorized actors list for this block.`
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
if (!node.parentCapability) {
|
|
2245
|
+
return { authorized: true };
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
if (node.parentCapability && context?.ucanService && context?.flowUri) {
|
|
2249
|
+
const requiredCapability = {
|
|
2250
|
+
can: "flow/block/execute",
|
|
2251
|
+
with: `${context.flowUri}:${node.id}`
|
|
2252
|
+
};
|
|
2253
|
+
const validationResult = await context.ucanService.validateDelegationChain(actorDid, requiredCapability);
|
|
2254
|
+
if (!validationResult.valid) {
|
|
2255
|
+
return {
|
|
2256
|
+
authorized: false,
|
|
2257
|
+
reason: validationResult.error || "No valid capability chain found"
|
|
2258
|
+
};
|
|
2259
|
+
}
|
|
2260
|
+
const proofCids = validationResult.proofChain?.map((d) => d.cid) || [];
|
|
2261
|
+
return {
|
|
2262
|
+
authorized: true,
|
|
2263
|
+
capabilityId: proofCids[0],
|
|
2264
|
+
// First in chain is the actor's delegation
|
|
2265
|
+
proofCids
|
|
2266
|
+
};
|
|
2267
|
+
}
|
|
2268
|
+
if (node.parentCapability && context?.delegationStore && context?.verifySignature && context?.rootIssuer) {
|
|
2269
|
+
const requiredCapability = {
|
|
2270
|
+
can: "flow/block/execute",
|
|
2271
|
+
with: context.flowUri ? `${context.flowUri}:${node.id}` : `ixo:flow:*:${node.id}`
|
|
2272
|
+
};
|
|
2273
|
+
const result = await findValidCapability({
|
|
2274
|
+
actorDid,
|
|
2275
|
+
requiredCapability,
|
|
2276
|
+
delegationStore: context.delegationStore,
|
|
2277
|
+
verifySignature: context.verifySignature,
|
|
2278
|
+
rootIssuer: context.rootIssuer
|
|
2279
|
+
});
|
|
2280
|
+
if (!result.found) {
|
|
2281
|
+
return {
|
|
2282
|
+
authorized: false,
|
|
2283
|
+
reason: result.error || "No valid capability found"
|
|
2284
|
+
};
|
|
2285
|
+
}
|
|
2286
|
+
return { authorized: true, capabilityId: result.capabilityId };
|
|
2287
|
+
}
|
|
2288
|
+
if (node.parentCapability && context?.ucanManager) {
|
|
2289
|
+
try {
|
|
2290
|
+
const parent = await context.ucanManager.loadParentCapability(node.parentCapability);
|
|
2291
|
+
const derived = await context.ucanManager.deriveNodeCapability(parent, node.id, actorDid);
|
|
2292
|
+
await context.ucanManager.validateDerivedCapability(derived, node.id, actorDid);
|
|
2293
|
+
return { authorized: true, derived };
|
|
2294
|
+
} catch (error) {
|
|
2295
|
+
const message = error instanceof Error ? error.message : "Capability derivation failed";
|
|
2296
|
+
return { authorized: false, reason: message };
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
if (node.parentCapability && !context?.ucanService && !context?.delegationStore && !context?.ucanManager) {
|
|
2300
|
+
return {
|
|
2301
|
+
authorized: false,
|
|
2302
|
+
reason: "Capability validation required but no UCAN service or delegation store configured."
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
return { authorized: true };
|
|
2306
|
+
};
|
|
2307
|
+
|
|
2308
|
+
// src/core/lib/flowEngine/executor.ts
|
|
2309
|
+
var updateRuntimeAfterSuccess = (node, actorDid, runtime, actionResult, capabilityId, now) => {
|
|
2310
|
+
const updates = {
|
|
2311
|
+
submittedByDid: actionResult.submittedByDid || actorDid,
|
|
2312
|
+
evaluationStatus: actionResult.evaluationStatus || "pending",
|
|
2313
|
+
executionTimestamp: now ? now() : Date.now(),
|
|
2314
|
+
derivedUcan: capabilityId,
|
|
2315
|
+
authorisedActorsSnapshot: node.authorisedActors
|
|
2316
|
+
};
|
|
2317
|
+
if (actionResult.claimId) {
|
|
2318
|
+
updates.claimId = actionResult.claimId;
|
|
2319
|
+
}
|
|
2320
|
+
runtime.update(node.id, updates);
|
|
2321
|
+
};
|
|
2322
|
+
var executeNode = async ({ node, actorDid, context, action }) => {
|
|
2323
|
+
const { runtime, delegationStore, verifySignature, rootIssuer, flowUri, ucanManager, now } = context;
|
|
2324
|
+
const activation = isNodeActive(node, runtime);
|
|
2325
|
+
if (!activation.active) {
|
|
2326
|
+
return { success: false, stage: "activation", error: activation.reason };
|
|
2327
|
+
}
|
|
2328
|
+
const authContext = {
|
|
2329
|
+
delegationStore,
|
|
2330
|
+
verifySignature,
|
|
2331
|
+
rootIssuer,
|
|
2332
|
+
flowUri,
|
|
2333
|
+
ucanManager
|
|
2334
|
+
};
|
|
2335
|
+
const auth = await isActorAuthorized(node, actorDid, authContext);
|
|
2336
|
+
if (!auth.authorized) {
|
|
2337
|
+
return { success: false, stage: "authorization", error: auth.reason };
|
|
2338
|
+
}
|
|
2339
|
+
if (node.linkedClaim && !node.linkedClaim.collectionId) {
|
|
2340
|
+
return { success: false, stage: "claim", error: "Linked claim collection is required but missing." };
|
|
2341
|
+
}
|
|
2342
|
+
try {
|
|
2343
|
+
const result = await action();
|
|
2344
|
+
if (node.linkedClaim && !result.claimId) {
|
|
2345
|
+
return { success: false, stage: "claim", error: "Execution did not return a claimId for linked claim requirement." };
|
|
2346
|
+
}
|
|
2347
|
+
updateRuntimeAfterSuccess(node, actorDid, runtime, result, auth.capabilityId, now);
|
|
2348
|
+
return { success: true, stage: "complete", result, capabilityId: auth.capabilityId };
|
|
2349
|
+
} catch (error) {
|
|
2350
|
+
const message = error instanceof Error ? error.message : "Execution failed";
|
|
2351
|
+
return { success: false, stage: "action", error: message };
|
|
2352
|
+
}
|
|
2353
|
+
};
|
|
2354
|
+
var executeNodeWithInvocation = async ({ node, actorDid, actorType, entityRoomId, context, action, pin }) => {
|
|
2355
|
+
const { runtime, ucanService, invocationStore, flowUri, flowId, flowOwnerDid, now } = context;
|
|
2356
|
+
const activation = isNodeActive(node, runtime);
|
|
2357
|
+
if (!activation.active) {
|
|
2358
|
+
return { success: false, stage: "activation", error: activation.reason };
|
|
2359
|
+
}
|
|
2360
|
+
const authContext = {
|
|
2361
|
+
ucanService,
|
|
2362
|
+
flowUri,
|
|
2363
|
+
flowOwnerDid,
|
|
2364
|
+
// Legacy fallbacks
|
|
2365
|
+
delegationStore: context.delegationStore,
|
|
2366
|
+
verifySignature: context.verifySignature,
|
|
2367
|
+
rootIssuer: context.rootIssuer,
|
|
2368
|
+
ucanManager: context.ucanManager
|
|
2369
|
+
};
|
|
2370
|
+
const auth = await isActorAuthorizedV2(node, actorDid, authContext);
|
|
2371
|
+
if (!auth.authorized) {
|
|
2372
|
+
return { success: false, stage: "authorization", error: auth.reason };
|
|
2373
|
+
}
|
|
2374
|
+
if (node.linkedClaim && !node.linkedClaim.collectionId) {
|
|
2375
|
+
return { success: false, stage: "claim", error: "Linked claim collection is required but missing." };
|
|
2376
|
+
}
|
|
2377
|
+
let invocationCid;
|
|
2378
|
+
let invocationData;
|
|
2379
|
+
if (ucanService && auth.proofCids && auth.proofCids.length > 0) {
|
|
2380
|
+
const capability = {
|
|
2381
|
+
can: "flow/block/execute",
|
|
2382
|
+
with: `${flowUri}:${node.id}`
|
|
2383
|
+
};
|
|
2384
|
+
try {
|
|
2385
|
+
const invocationResult = await ucanService.createAndValidateInvocation(
|
|
2386
|
+
{
|
|
2387
|
+
invokerDid: actorDid,
|
|
2388
|
+
invokerType: actorType,
|
|
2389
|
+
entityRoomId,
|
|
2390
|
+
capability,
|
|
2391
|
+
proofs: auth.proofCids,
|
|
2392
|
+
pin
|
|
2393
|
+
},
|
|
2394
|
+
flowId,
|
|
2395
|
+
node.id
|
|
2396
|
+
);
|
|
2397
|
+
if (!invocationResult.valid) {
|
|
2398
|
+
return {
|
|
2399
|
+
success: false,
|
|
2400
|
+
stage: "authorization",
|
|
2401
|
+
error: `Invocation validation failed: ${invocationResult.error}`
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
invocationCid = invocationResult.cid;
|
|
2405
|
+
invocationData = invocationResult.invocation;
|
|
2406
|
+
} catch (error) {
|
|
2407
|
+
const message = error instanceof Error ? error.message : "Failed to create invocation";
|
|
2408
|
+
return { success: false, stage: "authorization", error: message };
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
try {
|
|
2412
|
+
const result = await action();
|
|
2413
|
+
if (node.linkedClaim && !result.claimId) {
|
|
2414
|
+
if (invocationStore && invocationCid && invocationData) {
|
|
2415
|
+
const storedInvocation = {
|
|
2416
|
+
cid: invocationCid,
|
|
2417
|
+
invocation: invocationData,
|
|
2418
|
+
invokerDid: actorDid,
|
|
2419
|
+
capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
|
|
2420
|
+
executedAt: now ? now() : Date.now(),
|
|
2421
|
+
flowId,
|
|
2422
|
+
blockId: node.id,
|
|
2423
|
+
result: "failure",
|
|
2424
|
+
error: "Execution did not return a claimId for linked claim requirement.",
|
|
2425
|
+
proofCids: auth.proofCids || []
|
|
2426
|
+
};
|
|
2427
|
+
invocationStore.add(storedInvocation);
|
|
2428
|
+
}
|
|
2429
|
+
return {
|
|
2430
|
+
success: false,
|
|
2431
|
+
stage: "claim",
|
|
2432
|
+
error: "Execution did not return a claimId for linked claim requirement.",
|
|
2433
|
+
invocationCid
|
|
2434
|
+
};
|
|
2435
|
+
}
|
|
2436
|
+
if (invocationStore && invocationCid && invocationData) {
|
|
2437
|
+
const storedInvocation = {
|
|
2438
|
+
cid: invocationCid,
|
|
2439
|
+
invocation: invocationData,
|
|
2440
|
+
invokerDid: actorDid,
|
|
2441
|
+
capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
|
|
2442
|
+
executedAt: now ? now() : Date.now(),
|
|
2443
|
+
flowId,
|
|
2444
|
+
blockId: node.id,
|
|
2445
|
+
result: "success",
|
|
2446
|
+
proofCids: auth.proofCids || [],
|
|
2447
|
+
claimId: result.claimId
|
|
2448
|
+
};
|
|
2449
|
+
invocationStore.add(storedInvocation);
|
|
2450
|
+
}
|
|
2451
|
+
updateRuntimeAfterSuccess(node, actorDid, runtime, result, invocationCid || auth.capabilityId, now);
|
|
2452
|
+
return {
|
|
2453
|
+
success: true,
|
|
2454
|
+
stage: "complete",
|
|
2455
|
+
result,
|
|
2456
|
+
capabilityId: auth.capabilityId,
|
|
2457
|
+
invocationCid
|
|
2458
|
+
};
|
|
2459
|
+
} catch (error) {
|
|
2460
|
+
const message = error instanceof Error ? error.message : "Execution failed";
|
|
2461
|
+
if (invocationStore && invocationCid && invocationData) {
|
|
2462
|
+
const storedInvocation = {
|
|
2463
|
+
cid: invocationCid,
|
|
2464
|
+
invocation: invocationData,
|
|
2465
|
+
invokerDid: actorDid,
|
|
2466
|
+
capability: { can: "flow/block/execute", with: `${flowUri}:${node.id}` },
|
|
2467
|
+
executedAt: now ? now() : Date.now(),
|
|
2468
|
+
flowId,
|
|
2469
|
+
blockId: node.id,
|
|
2470
|
+
result: "failure",
|
|
2471
|
+
error: message,
|
|
2472
|
+
proofCids: auth.proofCids || []
|
|
2473
|
+
};
|
|
2474
|
+
invocationStore.add(storedInvocation);
|
|
2475
|
+
}
|
|
2476
|
+
return { success: false, stage: "action", error: message, invocationCid };
|
|
2477
|
+
}
|
|
2478
|
+
};
|
|
2479
|
+
|
|
2480
|
+
// src/core/lib/delegationStore.ts
|
|
2481
|
+
var ROOT_CAPABILITY_KEY = "__root__";
|
|
2482
|
+
var createDelegationStore = (yMap) => {
|
|
2483
|
+
return {
|
|
2484
|
+
get: (capabilityId) => {
|
|
2485
|
+
const raw = yMap.get(capabilityId);
|
|
2486
|
+
if (!raw || capabilityId === ROOT_CAPABILITY_KEY) return null;
|
|
2487
|
+
try {
|
|
2488
|
+
return JSON.parse(raw);
|
|
2489
|
+
} catch {
|
|
2490
|
+
return null;
|
|
2491
|
+
}
|
|
2492
|
+
},
|
|
2493
|
+
set: (capability) => {
|
|
2494
|
+
yMap.set(capability.id, JSON.stringify(capability));
|
|
2495
|
+
},
|
|
2496
|
+
remove: (capabilityId) => {
|
|
2497
|
+
yMap.delete(capabilityId);
|
|
2498
|
+
},
|
|
2499
|
+
getRoot: () => {
|
|
2500
|
+
const rootId = yMap.get(ROOT_CAPABILITY_KEY);
|
|
2501
|
+
if (!rootId) return null;
|
|
2502
|
+
const raw = yMap.get(rootId);
|
|
2503
|
+
if (!raw) return null;
|
|
2504
|
+
try {
|
|
2505
|
+
return JSON.parse(raw);
|
|
2506
|
+
} catch {
|
|
2507
|
+
return null;
|
|
2508
|
+
}
|
|
2509
|
+
},
|
|
2510
|
+
setRootId: (capabilityId) => {
|
|
2511
|
+
yMap.set(ROOT_CAPABILITY_KEY, capabilityId);
|
|
2512
|
+
},
|
|
2513
|
+
getAll: () => {
|
|
2514
|
+
const capabilities = [];
|
|
2515
|
+
yMap.forEach((value, key) => {
|
|
2516
|
+
if (key !== ROOT_CAPABILITY_KEY) {
|
|
2517
|
+
try {
|
|
2518
|
+
capabilities.push(JSON.parse(value));
|
|
2519
|
+
} catch {
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
});
|
|
2523
|
+
return capabilities;
|
|
2524
|
+
},
|
|
2525
|
+
has: (capabilityId) => {
|
|
2526
|
+
return yMap.has(capabilityId);
|
|
2527
|
+
}
|
|
2528
|
+
};
|
|
2529
|
+
};
|
|
2530
|
+
var createMemoryDelegationStore = () => {
|
|
2531
|
+
const store = /* @__PURE__ */ new Map();
|
|
2532
|
+
return {
|
|
2533
|
+
get: (capabilityId) => {
|
|
2534
|
+
const raw = store.get(capabilityId);
|
|
2535
|
+
if (!raw || capabilityId === ROOT_CAPABILITY_KEY) return null;
|
|
2536
|
+
try {
|
|
2537
|
+
return JSON.parse(raw);
|
|
2538
|
+
} catch {
|
|
2539
|
+
return null;
|
|
2540
|
+
}
|
|
2541
|
+
},
|
|
2542
|
+
set: (capability) => {
|
|
2543
|
+
store.set(capability.id, JSON.stringify(capability));
|
|
2544
|
+
},
|
|
2545
|
+
remove: (capabilityId) => {
|
|
2546
|
+
store.delete(capabilityId);
|
|
2547
|
+
},
|
|
2548
|
+
getRoot: () => {
|
|
2549
|
+
const rootId = store.get(ROOT_CAPABILITY_KEY);
|
|
2550
|
+
if (!rootId) return null;
|
|
2551
|
+
const raw = store.get(rootId);
|
|
2552
|
+
if (!raw) return null;
|
|
2553
|
+
try {
|
|
2554
|
+
return JSON.parse(raw);
|
|
2555
|
+
} catch {
|
|
2556
|
+
return null;
|
|
2557
|
+
}
|
|
2558
|
+
},
|
|
2559
|
+
setRootId: (capabilityId) => {
|
|
2560
|
+
store.set(ROOT_CAPABILITY_KEY, capabilityId);
|
|
2561
|
+
},
|
|
2562
|
+
getAll: () => {
|
|
2563
|
+
const capabilities = [];
|
|
2564
|
+
store.forEach((value, key) => {
|
|
2565
|
+
if (key !== ROOT_CAPABILITY_KEY) {
|
|
2566
|
+
try {
|
|
2567
|
+
capabilities.push(JSON.parse(value));
|
|
2568
|
+
} catch {
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
});
|
|
2572
|
+
return capabilities;
|
|
2573
|
+
},
|
|
2574
|
+
has: (capabilityId) => {
|
|
2575
|
+
return store.has(capabilityId);
|
|
2576
|
+
}
|
|
2577
|
+
};
|
|
2578
|
+
};
|
|
2579
|
+
|
|
2580
|
+
// src/core/services/ucanService.ts
|
|
2581
|
+
import {
|
|
2582
|
+
createDelegation as ucanCreateDelegation,
|
|
2583
|
+
createInvocation as ucanCreateInvocation,
|
|
2584
|
+
serializeDelegation,
|
|
2585
|
+
serializeInvocation,
|
|
2586
|
+
parseDelegation,
|
|
2587
|
+
parseSigner,
|
|
2588
|
+
signerFromMnemonic
|
|
2589
|
+
} from "@ixo/ucan";
|
|
2590
|
+
function toSupportedDID(did) {
|
|
2591
|
+
if (did.startsWith("did:ixo:") || did.startsWith("did:key:")) {
|
|
2592
|
+
return did;
|
|
2593
|
+
}
|
|
2594
|
+
return void 0;
|
|
2595
|
+
}
|
|
2596
|
+
function toUcantoCapabilities(capabilities) {
|
|
2597
|
+
return capabilities.map((cap) => ({
|
|
2598
|
+
can: cap.can,
|
|
2599
|
+
with: cap.with,
|
|
2600
|
+
...cap.nb && { nb: cap.nb }
|
|
2601
|
+
}));
|
|
2602
|
+
}
|
|
2603
|
+
async function getSigner(handlers, did, didType, entityRoomId, pin) {
|
|
2604
|
+
const supportedDid = toSupportedDID(did);
|
|
2605
|
+
if (handlers.getPrivateKey) {
|
|
2606
|
+
const privateKey = await handlers.getPrivateKey({ did, didType, entityRoomId, pin });
|
|
2607
|
+
return parseSigner(privateKey, supportedDid);
|
|
2608
|
+
}
|
|
2609
|
+
if (handlers.getMnemonic) {
|
|
2610
|
+
const mnemonic = await handlers.getMnemonic({ did, didType, entityRoomId, pin });
|
|
2611
|
+
const result = await signerFromMnemonic(mnemonic, supportedDid);
|
|
2612
|
+
return result.signer;
|
|
2613
|
+
}
|
|
2614
|
+
throw new Error("No signer handler configured (need getPrivateKey or getMnemonic)");
|
|
2615
|
+
}
|
|
2616
|
+
function getCidFromDelegation(delegation) {
|
|
2617
|
+
return delegation.cid.toString();
|
|
2618
|
+
}
|
|
2619
|
+
var createUcanService = (config) => {
|
|
2620
|
+
const { delegationStore, invocationStore, handlers, flowOwnerDid } = config;
|
|
2621
|
+
const delegationCache = /* @__PURE__ */ new Map();
|
|
2622
|
+
const isConfigured = () => {
|
|
2623
|
+
const hasSessionHandlers = !!(handlers.createSignerSession && handlers.signWithSession);
|
|
2624
|
+
const hasLegacyHandlers = !!(handlers.getPrivateKey || handlers.getMnemonic);
|
|
2625
|
+
return hasSessionHandlers || hasLegacyHandlers;
|
|
2626
|
+
};
|
|
2627
|
+
const parseDelegationFromStore = async (cid) => {
|
|
2628
|
+
if (delegationCache.has(cid)) {
|
|
2629
|
+
return delegationCache.get(cid);
|
|
2630
|
+
}
|
|
2631
|
+
const stored = delegationStore.get(cid);
|
|
2632
|
+
if (!stored) return null;
|
|
2633
|
+
if (stored.format === "legacy" || !stored.delegation) {
|
|
2634
|
+
return null;
|
|
2635
|
+
}
|
|
2636
|
+
try {
|
|
2637
|
+
const delegation = await parseDelegation(stored.delegation);
|
|
2638
|
+
delegationCache.set(cid, delegation);
|
|
2639
|
+
return delegation;
|
|
2640
|
+
} catch {
|
|
2641
|
+
return null;
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
const getProofDelegations = async (proofCids) => {
|
|
2645
|
+
const proofs = [];
|
|
2646
|
+
for (const cid of proofCids) {
|
|
2647
|
+
const delegation = await parseDelegationFromStore(cid);
|
|
2648
|
+
if (delegation) {
|
|
2649
|
+
proofs.push(delegation);
|
|
2650
|
+
}
|
|
2651
|
+
}
|
|
2652
|
+
return proofs;
|
|
2653
|
+
};
|
|
2654
|
+
const createRootDelegation = async (params) => {
|
|
2655
|
+
const { flowOwnerDid: ownerDid, issuerType, entityRoomId, flowUri: uri, pin } = params;
|
|
2656
|
+
const signer = await getSigner(handlers, ownerDid, issuerType, entityRoomId, pin);
|
|
2657
|
+
const capabilities = [{ can: "flow/*", with: uri }];
|
|
2658
|
+
const delegation = await ucanCreateDelegation({
|
|
2659
|
+
issuer: signer,
|
|
2660
|
+
audience: ownerDid,
|
|
2661
|
+
capabilities,
|
|
2662
|
+
proofs: []
|
|
2663
|
+
});
|
|
2664
|
+
const serialized = await serializeDelegation(delegation);
|
|
2665
|
+
const cid = getCidFromDelegation(delegation);
|
|
2666
|
+
const storedDelegation = {
|
|
2667
|
+
cid,
|
|
2668
|
+
delegation: serialized,
|
|
2669
|
+
issuerDid: ownerDid,
|
|
2670
|
+
audienceDid: ownerDid,
|
|
2671
|
+
capabilities,
|
|
2672
|
+
createdAt: Date.now(),
|
|
2673
|
+
format: "car",
|
|
2674
|
+
proofCids: []
|
|
2675
|
+
};
|
|
2676
|
+
delegationStore.set(storedDelegation);
|
|
2677
|
+
delegationStore.setRootCid(cid);
|
|
2678
|
+
delegationCache.set(cid, delegation);
|
|
2679
|
+
return storedDelegation;
|
|
2680
|
+
};
|
|
2681
|
+
const createDelegation = async (params) => {
|
|
2682
|
+
const { issuerDid, issuerType, entityRoomId, audience, capabilities, proofs = [], expiration, pin } = params;
|
|
2683
|
+
const signer = await getSigner(handlers, issuerDid, issuerType, entityRoomId, pin);
|
|
2684
|
+
const proofCids = proofs.length > 0 ? proofs : [delegationStore.getRootCid()].filter(Boolean);
|
|
2685
|
+
const proofDelegations = await getProofDelegations(proofCids);
|
|
2686
|
+
const delegation = await ucanCreateDelegation({
|
|
2687
|
+
issuer: signer,
|
|
2688
|
+
audience,
|
|
2689
|
+
capabilities: toUcantoCapabilities(capabilities),
|
|
2690
|
+
proofs: proofDelegations,
|
|
2691
|
+
expiration: expiration ? Math.floor(expiration / 1e3) : void 0
|
|
2692
|
+
// Convert ms to seconds
|
|
2693
|
+
});
|
|
2694
|
+
const serialized = await serializeDelegation(delegation);
|
|
2695
|
+
const cid = getCidFromDelegation(delegation);
|
|
2696
|
+
const storedDelegation = {
|
|
2697
|
+
cid,
|
|
2698
|
+
delegation: serialized,
|
|
2699
|
+
issuerDid,
|
|
2700
|
+
audienceDid: audience,
|
|
2701
|
+
capabilities,
|
|
2702
|
+
expiration,
|
|
2703
|
+
createdAt: Date.now(),
|
|
2704
|
+
format: "car",
|
|
2705
|
+
proofCids
|
|
2706
|
+
};
|
|
2707
|
+
delegationStore.set(storedDelegation);
|
|
2708
|
+
delegationCache.set(cid, delegation);
|
|
2709
|
+
return storedDelegation;
|
|
2710
|
+
};
|
|
2711
|
+
const revokeDelegation = (cid) => {
|
|
2712
|
+
delegationStore.remove(cid);
|
|
2713
|
+
delegationCache.delete(cid);
|
|
2714
|
+
};
|
|
2715
|
+
const getDelegation = (cid) => {
|
|
2716
|
+
return delegationStore.get(cid);
|
|
2717
|
+
};
|
|
2718
|
+
const getAllDelegations = () => {
|
|
2719
|
+
return delegationStore.getAll();
|
|
2720
|
+
};
|
|
2721
|
+
const getRootDelegation = () => {
|
|
2722
|
+
return delegationStore.getRoot();
|
|
2723
|
+
};
|
|
2724
|
+
const findValidProofs = async (audienceDid, capability) => {
|
|
2725
|
+
const delegations = delegationStore.getByAudience(audienceDid);
|
|
2726
|
+
if (delegations.length === 0) {
|
|
2727
|
+
const root = delegationStore.getRoot();
|
|
2728
|
+
if (root && root.audienceDid === audienceDid) {
|
|
2729
|
+
return { found: true, proofCids: [root.cid] };
|
|
2730
|
+
}
|
|
2731
|
+
return { found: false, error: "No delegations found for actor" };
|
|
2732
|
+
}
|
|
2733
|
+
for (const delegation of delegations) {
|
|
2734
|
+
const covers = delegation.capabilities.some((c) => {
|
|
2735
|
+
if (c.can === capability.can && c.with === capability.with) return true;
|
|
2736
|
+
if (c.can === "*" || c.can === "flow/*") return true;
|
|
2737
|
+
if (c.can.endsWith("/*")) {
|
|
2738
|
+
const prefix = c.can.slice(0, -1);
|
|
2739
|
+
if (capability.can.startsWith(prefix)) return true;
|
|
2740
|
+
}
|
|
2741
|
+
if (c.with === "*") return true;
|
|
2742
|
+
if (c.with.endsWith("*")) {
|
|
2743
|
+
const prefix = c.with.slice(0, -1);
|
|
2744
|
+
if (capability.with.startsWith(prefix)) return true;
|
|
2745
|
+
}
|
|
2746
|
+
return false;
|
|
2747
|
+
});
|
|
2748
|
+
if (covers) {
|
|
2749
|
+
if (delegation.expiration && delegation.expiration < Date.now()) {
|
|
2750
|
+
continue;
|
|
2751
|
+
}
|
|
2752
|
+
const proofCids = [delegation.cid, ...delegation.proofCids];
|
|
2753
|
+
return { found: true, proofCids };
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
return { found: false, error: "No valid delegation found for capability" };
|
|
2757
|
+
};
|
|
2758
|
+
const validateDelegationChain = async (audienceDid, capability) => {
|
|
2759
|
+
const proofsResult = await findValidProofs(audienceDid, capability);
|
|
2760
|
+
if (!proofsResult.found || !proofsResult.proofCids) {
|
|
2761
|
+
return { valid: false, error: proofsResult.error };
|
|
2762
|
+
}
|
|
2763
|
+
const proofChain = [];
|
|
2764
|
+
for (const cid of proofsResult.proofCids) {
|
|
2765
|
+
const delegation = delegationStore.get(cid);
|
|
2766
|
+
if (!delegation) {
|
|
2767
|
+
return { valid: false, error: `Proof delegation ${cid} not found` };
|
|
2768
|
+
}
|
|
2769
|
+
proofChain.push(delegation);
|
|
2770
|
+
}
|
|
2771
|
+
for (let i = 0; i < proofChain.length - 1; i++) {
|
|
2772
|
+
const current = proofChain[i];
|
|
2773
|
+
const parent = proofChain[i + 1];
|
|
2774
|
+
if (parent.audienceDid !== current.issuerDid) {
|
|
2775
|
+
return {
|
|
2776
|
+
valid: false,
|
|
2777
|
+
error: `Chain broken: ${parent.cid} audience (${parent.audienceDid}) != ${current.cid} issuer (${current.issuerDid})`
|
|
2778
|
+
};
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
const root = proofChain[proofChain.length - 1];
|
|
2782
|
+
if (root.issuerDid !== flowOwnerDid) {
|
|
2783
|
+
return { valid: false, error: `Root issuer ${root.issuerDid} is not flow owner ${flowOwnerDid}` };
|
|
2784
|
+
}
|
|
2785
|
+
return { valid: true, proofChain };
|
|
2786
|
+
};
|
|
2787
|
+
const createAndValidateInvocation = async (params, _flowId, _blockId) => {
|
|
2788
|
+
const { invokerDid, invokerType, entityRoomId, capability, proofs, pin } = params;
|
|
2789
|
+
const validation = await validateDelegationChain(invokerDid, capability);
|
|
2790
|
+
if (!validation.valid) {
|
|
2791
|
+
return {
|
|
2792
|
+
cid: "",
|
|
2793
|
+
invocation: "",
|
|
2794
|
+
valid: false,
|
|
2795
|
+
error: validation.error
|
|
2796
|
+
};
|
|
2797
|
+
}
|
|
2798
|
+
const signer = await getSigner(handlers, invokerDid, invokerType, entityRoomId, pin);
|
|
2799
|
+
const proofDelegations = await getProofDelegations(proofs);
|
|
2800
|
+
const ucantoCapability = {
|
|
2801
|
+
can: capability.can,
|
|
2802
|
+
with: capability.with,
|
|
2803
|
+
...capability.nb && { nb: capability.nb }
|
|
2804
|
+
};
|
|
2805
|
+
const invocation = await ucanCreateInvocation({
|
|
2806
|
+
issuer: signer,
|
|
2807
|
+
audience: flowOwnerDid,
|
|
2808
|
+
capability: ucantoCapability,
|
|
2809
|
+
proofs: proofDelegations
|
|
2810
|
+
});
|
|
2811
|
+
const serialized = await serializeInvocation(invocation);
|
|
2812
|
+
const built = await invocation.buildIPLDView();
|
|
2813
|
+
const cid = built.cid.toString();
|
|
2814
|
+
return {
|
|
2815
|
+
cid,
|
|
2816
|
+
invocation: serialized,
|
|
2817
|
+
valid: true
|
|
2818
|
+
};
|
|
2819
|
+
};
|
|
2820
|
+
const executeWithInvocation = async (params, action, flowId, blockId) => {
|
|
2821
|
+
const invocationResult = await createAndValidateInvocation(params, flowId, blockId);
|
|
2822
|
+
if (!invocationResult.valid) {
|
|
2823
|
+
return {
|
|
2824
|
+
success: false,
|
|
2825
|
+
invocationCid: invocationResult.cid,
|
|
2826
|
+
error: invocationResult.error
|
|
2827
|
+
};
|
|
2828
|
+
}
|
|
2829
|
+
if (invocationStore.hasBeenInvoked(invocationResult.cid)) {
|
|
2830
|
+
return {
|
|
2831
|
+
success: false,
|
|
2832
|
+
invocationCid: invocationResult.cid,
|
|
2833
|
+
error: "Invocation has already been used (replay attack prevented)"
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
try {
|
|
2837
|
+
const actionResult = await action();
|
|
2838
|
+
const storedInvocation = {
|
|
2839
|
+
cid: invocationResult.cid,
|
|
2840
|
+
invocation: invocationResult.invocation,
|
|
2841
|
+
invokerDid: params.invokerDid,
|
|
2842
|
+
capability: params.capability,
|
|
2843
|
+
executedAt: Date.now(),
|
|
2844
|
+
flowId,
|
|
2845
|
+
blockId,
|
|
2846
|
+
result: "success",
|
|
2847
|
+
proofCids: params.proofs
|
|
2848
|
+
};
|
|
2849
|
+
invocationStore.add(storedInvocation);
|
|
2850
|
+
return {
|
|
2851
|
+
success: true,
|
|
2852
|
+
invocationCid: invocationResult.cid,
|
|
2853
|
+
result: actionResult,
|
|
2854
|
+
actionResult
|
|
2855
|
+
};
|
|
2856
|
+
} catch (error) {
|
|
2857
|
+
const storedInvocation = {
|
|
2858
|
+
cid: invocationResult.cid,
|
|
2859
|
+
invocation: invocationResult.invocation,
|
|
2860
|
+
invokerDid: params.invokerDid,
|
|
2861
|
+
capability: params.capability,
|
|
2862
|
+
executedAt: Date.now(),
|
|
2863
|
+
flowId,
|
|
2864
|
+
blockId,
|
|
2865
|
+
result: "failure",
|
|
2866
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
2867
|
+
proofCids: params.proofs
|
|
2868
|
+
};
|
|
2869
|
+
invocationStore.add(storedInvocation);
|
|
2870
|
+
return {
|
|
2871
|
+
success: false,
|
|
2872
|
+
invocationCid: invocationResult.cid,
|
|
2873
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2874
|
+
};
|
|
2875
|
+
}
|
|
2876
|
+
};
|
|
2877
|
+
const migrateLegacyDelegation = async (legacyId, pin) => {
|
|
2878
|
+
const legacy = delegationStore.getLegacy(legacyId);
|
|
2879
|
+
if (!legacy) {
|
|
2880
|
+
return null;
|
|
2881
|
+
}
|
|
2882
|
+
const newDelegation = await createDelegation({
|
|
2883
|
+
issuerDid: legacy.issuer,
|
|
2884
|
+
issuerType: "user",
|
|
2885
|
+
// Assume user, host app should verify
|
|
2886
|
+
audience: legacy.audience,
|
|
2887
|
+
capabilities: legacy.capabilities,
|
|
2888
|
+
proofs: legacy.proofs,
|
|
2889
|
+
expiration: legacy.expiration,
|
|
2890
|
+
pin
|
|
2891
|
+
});
|
|
2892
|
+
return newDelegation;
|
|
2893
|
+
};
|
|
2894
|
+
const migrateAllLegacy = async (pin) => {
|
|
2895
|
+
const report = {
|
|
2896
|
+
total: 0,
|
|
2897
|
+
migrated: 0,
|
|
2898
|
+
failed: 0,
|
|
2899
|
+
errors: []
|
|
2900
|
+
};
|
|
2901
|
+
const legacyDelegations = delegationStore.getAllLegacy();
|
|
2902
|
+
report.total = legacyDelegations.length;
|
|
2903
|
+
for (const legacy of legacyDelegations) {
|
|
2904
|
+
try {
|
|
2905
|
+
const migrated = await migrateLegacyDelegation(legacy.id, pin);
|
|
2906
|
+
if (migrated) {
|
|
2907
|
+
report.migrated++;
|
|
2908
|
+
} else {
|
|
2909
|
+
report.failed++;
|
|
2910
|
+
report.errors.push({ id: legacy.id, error: "Migration returned null" });
|
|
2911
|
+
}
|
|
2912
|
+
} catch (error) {
|
|
2913
|
+
report.failed++;
|
|
2914
|
+
report.errors.push({
|
|
2915
|
+
id: legacy.id,
|
|
2916
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
2917
|
+
});
|
|
2918
|
+
}
|
|
2919
|
+
}
|
|
2920
|
+
return report;
|
|
2921
|
+
};
|
|
2922
|
+
const getLegacyCount = () => {
|
|
2923
|
+
return delegationStore.getAllLegacy().length;
|
|
2924
|
+
};
|
|
2925
|
+
return {
|
|
2926
|
+
createRootDelegation,
|
|
2927
|
+
createDelegation,
|
|
2928
|
+
revokeDelegation,
|
|
2929
|
+
getDelegation,
|
|
2930
|
+
getAllDelegations,
|
|
2931
|
+
getRootDelegation,
|
|
2932
|
+
createAndValidateInvocation,
|
|
2933
|
+
executeWithInvocation,
|
|
2934
|
+
validateDelegationChain,
|
|
2935
|
+
findValidProofs,
|
|
2936
|
+
parseDelegationFromStore,
|
|
2937
|
+
migrateLegacyDelegation,
|
|
2938
|
+
migrateAllLegacy,
|
|
2939
|
+
getLegacyCount,
|
|
2940
|
+
isConfigured
|
|
2941
|
+
};
|
|
2942
|
+
};
|
|
2943
|
+
|
|
2944
|
+
// src/core/services/ucanManager.ts
|
|
2945
|
+
var parseGrant = (value) => {
|
|
2946
|
+
const trimmed = value.trim();
|
|
2947
|
+
if (!trimmed) {
|
|
2948
|
+
throw new Error("Empty capability value");
|
|
2949
|
+
}
|
|
2950
|
+
try {
|
|
2951
|
+
const parsed = JSON.parse(trimmed);
|
|
2952
|
+
if (parsed && typeof parsed === "object") {
|
|
2953
|
+
return {
|
|
2954
|
+
raw: trimmed,
|
|
2955
|
+
with: typeof parsed.with === "string" ? parsed.with : void 0,
|
|
2956
|
+
audience: typeof parsed.aud === "string" ? parsed.aud : void 0,
|
|
2957
|
+
expiresAt: typeof parsed.exp === "number" ? parsed.exp * 1e3 : void 0,
|
|
2958
|
+
action: typeof parsed.can === "string" ? parsed.can : void 0
|
|
2959
|
+
};
|
|
2960
|
+
}
|
|
2961
|
+
} catch {
|
|
2962
|
+
}
|
|
2963
|
+
return { raw: trimmed };
|
|
2964
|
+
};
|
|
2965
|
+
var SimpleUCANManager = class {
|
|
2966
|
+
async loadParentCapability(capability) {
|
|
2967
|
+
return parseGrant(capability);
|
|
2968
|
+
}
|
|
2969
|
+
async deriveNodeCapability(parent, nodeId, actorDid) {
|
|
2970
|
+
if (parent.expiresAt && parent.expiresAt < Date.now()) {
|
|
2971
|
+
throw new Error("Parent capability expired");
|
|
2972
|
+
}
|
|
2973
|
+
if (parent.audience && parent.audience !== actorDid) {
|
|
2974
|
+
throw new Error(`Actor ${actorDid} is not the audience for the capability`);
|
|
2975
|
+
}
|
|
2976
|
+
if (parent.with && !(parent.with.endsWith("*") || parent.with.includes(nodeId))) {
|
|
2977
|
+
throw new Error(`Capability resource ${parent.with} does not cover node ${nodeId}`);
|
|
2978
|
+
}
|
|
2979
|
+
return { ...parent };
|
|
2980
|
+
}
|
|
2981
|
+
async validateDerivedCapability(derived) {
|
|
2982
|
+
if (derived.expiresAt && derived.expiresAt < Date.now()) {
|
|
2983
|
+
throw new Error("Derived capability expired");
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
};
|
|
2987
|
+
|
|
2988
|
+
export {
|
|
2989
|
+
registerAction,
|
|
2990
|
+
getAction,
|
|
2991
|
+
getAllActions,
|
|
2992
|
+
hasAction,
|
|
2993
|
+
buildServicesFromHandlers,
|
|
2994
|
+
buildVerifiableCredential,
|
|
2995
|
+
buildDomainCardLinkedResource,
|
|
2996
|
+
parseLinkedEntities,
|
|
2997
|
+
buildGovernanceGroupLinkedEntities,
|
|
2998
|
+
transformSurveyToCredentialSubject,
|
|
2999
|
+
extractSurveyAnswersTemplate,
|
|
3000
|
+
createUcanDelegationStore,
|
|
3001
|
+
createMemoryUcanDelegationStore,
|
|
3002
|
+
createInvocationStore,
|
|
3003
|
+
createMemoryInvocationStore,
|
|
3004
|
+
buildAuthzFromProps,
|
|
3005
|
+
buildFlowNodeFromBlock,
|
|
3006
|
+
createRuntimeStateManager,
|
|
3007
|
+
clearRuntimeForTemplateClone,
|
|
3008
|
+
isNodeActive,
|
|
3009
|
+
validateCapabilityChain,
|
|
3010
|
+
findValidCapability,
|
|
3011
|
+
isActorAuthorized,
|
|
3012
|
+
isActorAuthorizedV2,
|
|
3013
|
+
executeNode,
|
|
3014
|
+
executeNodeWithInvocation,
|
|
3015
|
+
createDelegationStore,
|
|
3016
|
+
createMemoryDelegationStore,
|
|
3017
|
+
createUcanService,
|
|
3018
|
+
SimpleUCANManager
|
|
3019
|
+
};
|
|
3020
|
+
//# sourceMappingURL=chunk-3RYZSIC2.mjs.map
|