@ixo/editor 3.0.0-beta.3 → 3.0.0-beta.30

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