@ixo/editor 3.8.1 → 4.0.0

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.
@@ -15,8 +15,16 @@ var ACTION_TYPE_ALIASES = {
15
15
  "proposal.vote": "qi/proposal.vote",
16
16
  "protocol.select": "qi/protocol.select",
17
17
  "domain.sign": "qi/domain.sign",
18
- "domain.create": "qi/domain.create",
18
+ "domain.card-build": "qi/domain.card-build",
19
+ "domain.card-preview": "qi/domain.card-preview",
19
20
  "credential.store": "qi/credential.store",
21
+ // POD setup flow — camelCase orchestrator labels → canonical action types
22
+ DomainIndexerLookup: "qi/pod.domain-indexer-lookup",
23
+ DomainSingleSelection: "qi/pod.domain-single-selection",
24
+ EntitySingleSelection: "qi/pod.entity-single-selection",
25
+ MemberMultiSelect: "qi/pod.member-multi-select",
26
+ governanceConfig: "qi/pod.governance-config",
27
+ listDomainFlows: "qi/pod.list-domain-flows",
20
28
  payment: "qi/payment.execute",
21
29
  "matrix.dm": "qi/matrix.dm"
22
30
  };
@@ -54,7 +62,8 @@ var CAN_TO_TYPE = {
54
62
  "matrix/dm": "qi/matrix.dm",
55
63
  "proposal/create": "qi/proposal.create",
56
64
  "proposal/vote": "qi/proposal.vote",
57
- "domain/create": "qi/domain.create",
65
+ "domain/card-build": "qi/domain.card-build",
66
+ "domain/card-preview": "qi/domain.card-preview",
58
67
  "domain/sign": "qi/domain.sign",
59
68
  "credential/store": "qi/credential.store",
60
69
  "payment/execute": "qi/payment.execute",
@@ -62,7 +71,13 @@ var CAN_TO_TYPE = {
62
71
  "protocol/select": "qi/protocol.select",
63
72
  "human/checkbox": "qi/human.checkbox.set",
64
73
  "human/form": "qi/human.form.submit",
65
- "oracle/query": "oracle"
74
+ "oracle/query": "oracle",
75
+ "pod/domain-indexer-lookup": "qi/pod.domain-indexer-lookup",
76
+ "pod/domain-single-selection": "qi/pod.domain-single-selection",
77
+ "pod/entity-single-selection": "qi/pod.entity-single-selection",
78
+ "pod/governance-config": "qi/pod.governance-config",
79
+ "pod/member-multi-select": "qi/pod.member-multi-select",
80
+ "pod/list-domain-flows": "qi/pod.list-domain-flows"
66
81
  };
67
82
  var TYPE_TO_CAN = Object.fromEntries(Object.entries(CAN_TO_TYPE).map(([can, type]) => [type, can]));
68
83
  function canToType(can) {
@@ -206,6 +221,190 @@ function hasDiffResolver(actionType) {
206
221
  return diffResolvers.has(actionType);
207
222
  }
208
223
 
224
+ // src/core/lib/actionRegistry/actions/pod/domainIndexerLookup.ts
225
+ registerAction({
226
+ type: "qi/pod.domain-indexer-lookup",
227
+ can: "pod/domain-indexer-lookup",
228
+ sideEffect: false,
229
+ defaultRequiresConfirmation: false,
230
+ outputSchema: [
231
+ { path: "purposeDescription", displayName: "Purpose Description", type: "string", description: "The user-provided purpose text" },
232
+ { path: "blueprintCandidates", displayName: "Blueprint Candidates", type: "array", description: "Ranked array of matching blueprint DIDs and metadata" }
233
+ ],
234
+ run: async (inputs) => {
235
+ const purposeDescription = String(inputs.userMessage || inputs.purposeDescription || "").trim();
236
+ if (!purposeDescription) throw new Error("userMessage is required");
237
+ return {
238
+ output: {
239
+ purposeDescription,
240
+ blueprintCandidates: []
241
+ }
242
+ };
243
+ }
244
+ });
245
+
246
+ // src/core/lib/actionRegistry/actions/pod/domainSingleSelection.ts
247
+ registerAction({
248
+ type: "qi/pod.domain-single-selection",
249
+ can: "pod/domain-single-selection",
250
+ sideEffect: false,
251
+ defaultRequiresConfirmation: false,
252
+ outputSchema: [
253
+ { path: "selectedBlueprintDid", displayName: "Selected Blueprint DID", type: "string", description: "DID of the selected blueprint" },
254
+ { path: "selectedBlueprintName", displayName: "Selected Blueprint Name", type: "string", description: "Display name of the selected blueprint" },
255
+ { path: "selectedBlueprintDescription", displayName: "Selected Blueprint Description", type: "string", description: "Description of the selected blueprint" }
256
+ ],
257
+ run: async (inputs) => {
258
+ const selectedBlueprintDid = String(inputs.selectedBlueprintDid || "").trim();
259
+ if (!selectedBlueprintDid) throw new Error("selectedBlueprintDid is required");
260
+ return {
261
+ output: {
262
+ selectedBlueprintDid,
263
+ selectedBlueprintName: String(inputs.selectedBlueprintName || "").trim(),
264
+ selectedBlueprintDescription: String(inputs.selectedBlueprintDescription || "").trim()
265
+ }
266
+ };
267
+ }
268
+ });
269
+
270
+ // src/core/lib/actionRegistry/actions/pod/entitySingleSelection.ts
271
+ registerAction({
272
+ type: "qi/pod.entity-single-selection",
273
+ can: "pod/entity-single-selection",
274
+ sideEffect: false,
275
+ defaultRequiresConfirmation: false,
276
+ outputSchema: [
277
+ { path: "selectedEntityDid", displayName: "Selected Entity DID", type: "string", description: "DID of the selected parent entity, or null if skipped" },
278
+ { path: "selectedEntityName", displayName: "Selected Entity Name", type: "string", description: "Display name of the selected parent entity" },
279
+ { path: "skipped", displayName: "Skipped", type: "boolean", description: "True if the user skipped this step" }
280
+ ],
281
+ run: async (inputs) => {
282
+ const skipped = !!inputs.skipped;
283
+ if (skipped) {
284
+ return { output: { selectedEntityDid: null, selectedEntityName: "", skipped: true } };
285
+ }
286
+ const selectedEntityDid = String(inputs.selectedEntityDid || "").trim();
287
+ if (!selectedEntityDid) throw new Error("selectedEntityDid is required when not skipping");
288
+ return {
289
+ output: {
290
+ selectedEntityDid,
291
+ selectedEntityName: String(inputs.selectedEntityName || "").trim(),
292
+ skipped: false
293
+ }
294
+ };
295
+ }
296
+ });
297
+
298
+ // src/core/lib/actionRegistry/actions/pod/memberMultiSelect.ts
299
+ registerAction({
300
+ type: "qi/pod.member-multi-select",
301
+ can: "pod/member-multi-select",
302
+ sideEffect: false,
303
+ defaultRequiresConfirmation: false,
304
+ outputSchema: [
305
+ { path: "members", displayName: "Members", type: "array", description: "Array of { did, role, votingPower } \u2014 categorical/multisig only" },
306
+ { path: "multisigThreshold", displayName: "Multisig Threshold", type: "number", description: "Minimum signers required \u2014 multisig only" },
307
+ { path: "nftContractAddress", displayName: "NFT Contract Address", type: "string", description: "NFT staking contract address \u2014 nftStaking only" },
308
+ { path: "tokenConfig", displayName: "Token Config", type: "object", description: "Token configuration \u2014 tokenStaking only" }
309
+ ],
310
+ run: async (inputs) => {
311
+ const groupType = inputs.groupType || "categorical";
312
+ if (groupType === "nftStaking") {
313
+ const addr = String(inputs.nftContractAddress || "").trim();
314
+ if (!addr) throw new Error("NFT contract address is required for nftStaking groups");
315
+ return { output: { nftContractAddress: addr } };
316
+ }
317
+ if (groupType === "tokenStaking") {
318
+ const tokenConfig = inputs.tokenConfig;
319
+ if (!tokenConfig) throw new Error("tokenConfig is required for tokenStaking groups");
320
+ if (tokenConfig.isExistingToken) {
321
+ if (!String(tokenConfig.tokenAddress || "").trim()) throw new Error("Token contract address is required");
322
+ } else {
323
+ if (!String(tokenConfig.tokenName || "").trim()) throw new Error("Token name is required");
324
+ if (!String(tokenConfig.tokenSymbol || "").trim()) throw new Error("Token symbol is required");
325
+ const supply = Number(tokenConfig.tokenSupply);
326
+ if (isNaN(supply) || supply <= 0) throw new Error("Token supply must be a positive number");
327
+ }
328
+ return { output: { tokenConfig } };
329
+ }
330
+ const members = Array.isArray(inputs.members) ? inputs.members : [];
331
+ if (members.length === 0) throw new Error("At least one member is required");
332
+ const dids = members.map((m) => String(m.did || ""));
333
+ const uniqueDids = new Set(dids);
334
+ if (uniqueDids.size !== dids.length) throw new Error("Duplicate member DIDs are not allowed");
335
+ if (groupType === "multisig") {
336
+ const threshold = Number(inputs.multisigThreshold);
337
+ if (!Number.isInteger(threshold) || threshold < 1) throw new Error("Multisig threshold must be a positive integer");
338
+ if (threshold > members.length) throw new Error(`Threshold (${threshold}) cannot exceed member count (${members.length})`);
339
+ return { output: { members, multisigThreshold: threshold } };
340
+ }
341
+ const hasAdmin = members.some((m) => String(m.role || "").toLowerCase() === "admin");
342
+ if (!hasAdmin) throw new Error("At least one member must have the Admin role");
343
+ for (const m of members) {
344
+ const vp = Number(m.votingPower);
345
+ if (!Number.isInteger(vp) || vp <= 0) throw new Error(`Voting power must be a positive integer (got ${m.votingPower} for ${m.did})`);
346
+ }
347
+ return { output: { members } };
348
+ }
349
+ });
350
+
351
+ // src/core/lib/actionRegistry/actions/pod/governanceConfig.ts
352
+ var VALID_GROUP_TYPES = ["categorical", "multisig", "nftStaking", "tokenStaking"];
353
+ registerAction({
354
+ type: "qi/pod.governance-config",
355
+ can: "pod/governance-config",
356
+ sideEffect: false,
357
+ defaultRequiresConfirmation: false,
358
+ outputSchema: [
359
+ { path: "groupName", displayName: "Group Name", type: "string", description: "Human-readable name for the governance group" },
360
+ { path: "groupType", displayName: "Group Type", type: "string", description: "Governance group type (categorical | multisig | nftStaking | tokenStaking)" },
361
+ { path: "governance", displayName: "Governance Settings", type: "object", description: "Cosmos group decision policy parameters" }
362
+ ],
363
+ run: async (inputs) => {
364
+ const groupName = String(inputs.groupName || "").trim();
365
+ if (!groupName) throw new Error("groupName is required");
366
+ const groupType = inputs.groupType;
367
+ if (!groupType || !VALID_GROUP_TYPES.includes(groupType)) {
368
+ throw new Error(`groupType must be one of: ${VALID_GROUP_TYPES.join(", ")}`);
369
+ }
370
+ const governance = inputs.governance;
371
+ if (!governance) throw new Error("governance settings are required");
372
+ if (!governance.votingPeriod) throw new Error("votingPeriod is required");
373
+ if (groupType === "multisig") {
374
+ const raw = String(governance.threshold ?? "").trim();
375
+ const threshold = Number(raw);
376
+ if (!raw || !Number.isFinite(threshold) || !Number.isInteger(threshold) || threshold < 1) {
377
+ throw new Error("multisig threshold must be a positive integer");
378
+ }
379
+ } else {
380
+ const quorum = parseFloat(governance.quorum);
381
+ if (isNaN(quorum) || quorum <= 0 || quorum > 1) throw new Error("quorum must be between 0 and 1 (e.g. 0.33)");
382
+ const threshold = parseFloat(governance.threshold);
383
+ if (isNaN(threshold) || threshold <= 0 || threshold > 1) throw new Error("threshold must be between 0 and 1 (e.g. 0.51)");
384
+ const vetoThreshold = parseFloat(governance.vetoThreshold);
385
+ if (!isNaN(vetoThreshold) && vetoThreshold + threshold > 1) {
386
+ throw new Error("threshold + vetoThreshold cannot exceed 1.0");
387
+ }
388
+ }
389
+ return { output: { groupName, groupType, governance } };
390
+ }
391
+ });
392
+
393
+ // src/core/lib/actionRegistry/actions/pod/listDomainFlows.ts
394
+ registerAction({
395
+ type: "qi/pod.list-domain-flows",
396
+ can: "pod/list-domain-flows",
397
+ sideEffect: false,
398
+ defaultRequiresConfirmation: false,
399
+ outputSchema: [
400
+ { path: "selectedFlowDids", displayName: "Selected Flow DIDs", type: "array", description: "Array of selected flow template DIDs" }
401
+ ],
402
+ run: async (inputs) => {
403
+ const selectedFlowDids = Array.isArray(inputs.selectedFlowDids) ? inputs.selectedFlowDids : [];
404
+ return { output: { selectedFlowDids } };
405
+ }
406
+ });
407
+
209
408
  // src/core/lib/actionRegistry/actions/httpRequest.ts
210
409
  registerAction({
211
410
  type: "qi/http.request",
@@ -985,211 +1184,7 @@ registerAction({
985
1184
  }
986
1185
  });
987
1186
 
988
- // src/mantine/blocks/domainCreator/utils/buildVerifiableCredential.ts
989
- var DOMAIN_CARD_CONTEXT = [
990
- "https://w3id.org/ixo/context/v1",
991
- {
992
- schema: "https://schema.org/",
993
- ixo: "https://w3id.org/ixo/vocab/v1",
994
- prov: "http://www.w3.org/ns/prov#",
995
- proj: "http://www.w3.org/ns/project#",
996
- id: "@id",
997
- type: "@type",
998
- "@protected": true
999
- }
1000
- ];
1001
- var DOMAIN_CARD_SCHEMA = {
1002
- id: "https://w3id.org/ixo/protocol/schema/v1#domainCard",
1003
- type: "JsonSchema"
1004
- };
1005
- function toISOString(dateInput, fallback = /* @__PURE__ */ new Date()) {
1006
- if (!dateInput) {
1007
- return fallback.toISOString();
1008
- }
1009
- if (dateInput instanceof Date) {
1010
- return dateInput.toISOString();
1011
- }
1012
- if (/^\d{4}-\d{2}-\d{2}$/.test(dateInput)) {
1013
- return (/* @__PURE__ */ new Date(dateInput + "T00:00:00.000Z")).toISOString();
1014
- }
1015
- if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(dateInput)) {
1016
- return (/* @__PURE__ */ new Date(dateInput + ":00.000Z")).toISOString();
1017
- }
1018
- const parsed = new Date(dateInput);
1019
- if (!isNaN(parsed.getTime())) {
1020
- return parsed.toISOString();
1021
- }
1022
- return fallback.toISOString();
1023
- }
1024
- function getDefaultValidUntil(validFrom) {
1025
- const fromDate = new Date(validFrom);
1026
- const untilDate = new Date(fromDate);
1027
- untilDate.setFullYear(untilDate.getFullYear() + 5);
1028
- return untilDate.toISOString();
1029
- }
1030
- function buildVerifiableCredential(params) {
1031
- const { entityDid, issuerDid, credentialSubject, validFrom, validUntil } = params;
1032
- const validFromISO = toISOString(validFrom);
1033
- const validUntilISO = validUntil ? toISOString(validUntil) : getDefaultValidUntil(validFromISO);
1034
- return {
1035
- "@context": DOMAIN_CARD_CONTEXT,
1036
- id: `${entityDid}#dmn`,
1037
- type: ["VerifiableCredential", "ixo:DomainCard"],
1038
- issuer: {
1039
- id: issuerDid
1040
- },
1041
- validFrom: validFromISO,
1042
- validUntil: validUntilISO,
1043
- credentialSchema: DOMAIN_CARD_SCHEMA,
1044
- credentialSubject: {
1045
- ...credentialSubject,
1046
- // Ensure the subject ID matches the entity DID
1047
- id: entityDid
1048
- }
1049
- };
1050
- }
1051
- function buildDomainCardLinkedResource(params) {
1052
- return {
1053
- id: `${params.entityDid}#dmn`,
1054
- type: "domainCard",
1055
- proof: params.cid,
1056
- right: "",
1057
- encrypted: "false",
1058
- mediaType: "application/json",
1059
- description: params.description || "Domain Card",
1060
- serviceEndpoint: params.serviceEndpoint
1061
- };
1062
- }
1063
-
1064
- // src/mantine/blocks/domainCreatorSign/utils/buildLinkedEntityResource.ts
1065
- function parseLinkedEntities(entitiesString) {
1066
- if (!entitiesString || entitiesString === "[]") return [];
1067
- try {
1068
- return JSON.parse(entitiesString);
1069
- } catch {
1070
- return [];
1071
- }
1072
- }
1073
- function buildGovernanceGroupLinkedEntities(linkedEntities) {
1074
- return linkedEntities.filter((entity) => entity.type === "governanceGroup" && entity.coreAddress).map((entity) => ({
1075
- id: entity.coreAddress,
1076
- type: "group",
1077
- relationship: "governs",
1078
- service: ""
1079
- }));
1080
- }
1081
-
1082
- // src/core/lib/actionRegistry/actions/domainSign.ts
1083
- registerAction({
1084
- type: "qi/domain.sign",
1085
- can: "domain/sign",
1086
- sideEffect: true,
1087
- defaultRequiresConfirmation: true,
1088
- requiredCapability: "flow/block/execute",
1089
- outputSchema: [
1090
- { path: "entityDid", displayName: "Entity DID", type: "string", description: "The DID of the newly created domain entity" },
1091
- { path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "The on-chain transaction hash for domain creation" }
1092
- ],
1093
- run: async (inputs, ctx) => {
1094
- const handlers = ctx.handlers;
1095
- if (!handlers) {
1096
- throw new Error("Handlers not available");
1097
- }
1098
- if (!handlers.requestPin) throw new Error("requestPin handler not available");
1099
- if (!handlers.signCredential) throw new Error("signCredential handler not implemented");
1100
- if (!handlers.publicFileUpload) throw new Error("publicFileUpload handler not available");
1101
- if (!handlers.createDomain) throw new Error("createDomain handler not implemented");
1102
- let domainCardData;
1103
- if (typeof inputs.domainCardData === "string") {
1104
- try {
1105
- domainCardData = JSON.parse(inputs.domainCardData);
1106
- } catch {
1107
- throw new Error("domainCardData must be valid JSON");
1108
- }
1109
- } else if (inputs.domainCardData && typeof inputs.domainCardData === "object") {
1110
- domainCardData = inputs.domainCardData;
1111
- } else {
1112
- throw new Error("domainCardData is required");
1113
- }
1114
- if (!domainCardData?.credentialSubject?.name) {
1115
- throw new Error("domainCardData is missing or invalid (credentialSubject.name required)");
1116
- }
1117
- const extractEntityType = (type) => type.replace(/^schema:/i, "").toLowerCase();
1118
- const entityType = String(inputs.entityType || "").trim() || (domainCardData.credentialSubject?.type?.[0] ? extractEntityType(domainCardData.credentialSubject.type[0]) : "dao");
1119
- const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
1120
- if (!issuerDid) throw new Error("Unable to determine issuer DID");
1121
- const entityDidPlaceholder = "did:ixo:entity:pending";
1122
- const validFrom = domainCardData.validFrom || (/* @__PURE__ */ new Date()).toISOString();
1123
- const validUntil = domainCardData.validUntil || (() => {
1124
- const d = /* @__PURE__ */ new Date();
1125
- d.setFullYear(d.getFullYear() + 100);
1126
- return d.toISOString();
1127
- })();
1128
- const credentialSubject = {
1129
- ...domainCardData.credentialSubject,
1130
- id: entityDidPlaceholder
1131
- };
1132
- const unsignedCredential = buildVerifiableCredential({
1133
- entityDid: entityDidPlaceholder,
1134
- issuerDid,
1135
- credentialSubject,
1136
- validFrom,
1137
- validUntil
1138
- });
1139
- const pin = await handlers.requestPin({
1140
- title: "Sign Domain Card",
1141
- description: "Enter your PIN to sign the Domain Card credential",
1142
- submitText: "Sign"
1143
- });
1144
- const { signedCredential } = await handlers.signCredential({
1145
- issuerDid,
1146
- issuerType: "user",
1147
- credential: unsignedCredential,
1148
- pin
1149
- });
1150
- const credentialBlob = new Blob([JSON.stringify(signedCredential, null, 2)], {
1151
- type: "application/json"
1152
- });
1153
- const credentialFile = new File([credentialBlob], "domainCard.json", {
1154
- type: "application/json"
1155
- });
1156
- const uploadResult = await handlers.publicFileUpload(credentialFile);
1157
- const domainCardLinkedResource = buildDomainCardLinkedResource({
1158
- entityDid: entityDidPlaceholder,
1159
- cid: uploadResult.cid,
1160
- serviceEndpoint: uploadResult.url,
1161
- description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
1162
- });
1163
- let linkedEntitiesData = [];
1164
- if (inputs.linkedEntities) {
1165
- if (typeof inputs.linkedEntities === "string") {
1166
- try {
1167
- linkedEntitiesData = JSON.parse(inputs.linkedEntities);
1168
- } catch {
1169
- }
1170
- } else if (Array.isArray(inputs.linkedEntities)) {
1171
- linkedEntitiesData = inputs.linkedEntities;
1172
- }
1173
- }
1174
- const governanceGroupLinkedEntities = buildGovernanceGroupLinkedEntities(parseLinkedEntities(JSON.stringify(linkedEntitiesData)));
1175
- const endDate = domainCardData.endDate || validUntil;
1176
- const { entityDid: newEntityDid, transactionHash } = await handlers.createDomain({
1177
- entityType,
1178
- linkedResource: [domainCardLinkedResource],
1179
- linkedEntity: governanceGroupLinkedEntities.length > 0 ? governanceGroupLinkedEntities : void 0,
1180
- startDate: validFrom,
1181
- endDate
1182
- });
1183
- return {
1184
- output: {
1185
- entityDid: newEntityDid,
1186
- transactionHash
1187
- }
1188
- };
1189
- }
1190
- });
1191
-
1192
- // src/mantine/blocks/domainCreator/utils/transformSurveyToCredentialSubject.ts
1187
+ // src/core/lib/domainCard/transformSurveyToCredentialSubject.ts
1193
1188
  function extractPanelDynamicItems(surveyData, panelName, itemMapper) {
1194
1189
  const items = surveyData[panelName];
1195
1190
  if (!Array.isArray(items)) return [];
@@ -1421,91 +1416,837 @@ function transformSurveyToCredentialSubject(surveyData, entityDid) {
1421
1416
  return credentialSubject;
1422
1417
  }
1423
1418
 
1424
- // src/mantine/blocks/domainCreator/utils/extractSurveyAnswersTemplate.ts
1425
- function extractFieldsFromElements(elements, fields) {
1426
- for (const element of elements) {
1427
- if (element.type === "panel" && element.elements) {
1428
- extractFieldsFromElements(element.elements, fields);
1429
- continue;
1430
- }
1431
- if (element.type === "paneldynamic" && element.name) {
1432
- fields[element.name] = [];
1433
- if (element.templateElements) {
1434
- extractFieldsFromElements(element.templateElements, fields);
1435
- }
1436
- continue;
1437
- }
1438
- if (element.name && element.type !== "panel") {
1439
- switch (element.type) {
1440
- case "boolean":
1441
- fields[element.name] = false;
1442
- break;
1443
- case "checkbox":
1444
- fields[element.name] = [];
1445
- break;
1446
- case "file":
1447
- fields[element.name] = [];
1448
- break;
1449
- default:
1450
- fields[element.name] = "";
1451
- }
1452
- }
1453
- if (element.elements) {
1454
- extractFieldsFromElements(element.elements, fields);
1455
- }
1419
+ // src/core/lib/domainCard/buildVerifiableCredential.ts
1420
+ var DOMAIN_CARD_CONTEXT = [
1421
+ "https://w3id.org/ixo/context/v1",
1422
+ {
1423
+ schema: "https://schema.org/",
1424
+ ixo: "https://w3id.org/ixo/vocab/v1",
1425
+ prov: "http://www.w3.org/ns/prov#",
1426
+ proj: "http://www.w3.org/ns/project#",
1427
+ id: "@id",
1428
+ type: "@type",
1429
+ "@protected": true
1430
+ }
1431
+ ];
1432
+ var DOMAIN_CARD_SCHEMA = {
1433
+ id: "https://w3id.org/ixo/protocol/schema/v1#domainCard",
1434
+ type: "JsonSchema"
1435
+ };
1436
+ function toISOString(dateInput, fallback = /* @__PURE__ */ new Date()) {
1437
+ if (!dateInput) {
1438
+ return fallback.toISOString();
1439
+ }
1440
+ if (dateInput instanceof Date) {
1441
+ return dateInput.toISOString();
1442
+ }
1443
+ if (/^\d{4}-\d{2}-\d{2}$/.test(dateInput)) {
1444
+ return (/* @__PURE__ */ new Date(dateInput + "T00:00:00.000Z")).toISOString();
1445
+ }
1446
+ if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(dateInput)) {
1447
+ return (/* @__PURE__ */ new Date(dateInput + ":00.000Z")).toISOString();
1456
1448
  }
1449
+ const parsed = new Date(dateInput);
1450
+ if (!isNaN(parsed.getTime())) {
1451
+ return parsed.toISOString();
1452
+ }
1453
+ return fallback.toISOString();
1454
+ }
1455
+ function getDefaultValidUntil(validFrom) {
1456
+ const fromDate = new Date(validFrom);
1457
+ const untilDate = new Date(fromDate);
1458
+ untilDate.setFullYear(untilDate.getFullYear() + 5);
1459
+ return untilDate.toISOString();
1460
+ }
1461
+ function buildVerifiableCredential(params) {
1462
+ const { entityDid, issuerDid, credentialSubject, validFrom, validUntil } = params;
1463
+ const validFromISO = toISOString(validFrom);
1464
+ const validUntilISO = validUntil ? toISOString(validUntil) : getDefaultValidUntil(validFromISO);
1465
+ return {
1466
+ "@context": DOMAIN_CARD_CONTEXT,
1467
+ id: `${entityDid}#dmn`,
1468
+ type: ["VerifiableCredential", "ixo:DomainCard"],
1469
+ issuer: {
1470
+ id: issuerDid
1471
+ },
1472
+ validFrom: validFromISO,
1473
+ validUntil: validUntilISO,
1474
+ credentialSchema: DOMAIN_CARD_SCHEMA,
1475
+ credentialSubject: {
1476
+ ...credentialSubject,
1477
+ // Ensure the subject ID matches the entity DID
1478
+ id: entityDid
1479
+ }
1480
+ };
1481
+ }
1482
+ function buildDomainCardLinkedResource(params) {
1483
+ return {
1484
+ id: `${params.entityDid}#dmn`,
1485
+ type: "domainCard",
1486
+ proof: params.cid,
1487
+ right: "",
1488
+ encrypted: "false",
1489
+ mediaType: "application/json",
1490
+ description: params.description || "Domain Card",
1491
+ serviceEndpoint: params.serviceEndpoint
1492
+ };
1457
1493
  }
1458
- function extractSurveyAnswersTemplate(surveyDef) {
1459
- const fields = {};
1460
- for (const page of surveyDef.pages) {
1461
- extractFieldsFromElements(page.elements, fields);
1494
+
1495
+ // src/core/lib/domainCard/buildLinkedEntityResource.ts
1496
+ function parseLinkedEntities(entitiesString) {
1497
+ if (!entitiesString || entitiesString === "[]") return [];
1498
+ try {
1499
+ return JSON.parse(entitiesString);
1500
+ } catch {
1501
+ return [];
1462
1502
  }
1463
- return fields;
1464
1503
  }
1504
+ function buildGovernanceGroupLinkedEntities(linkedEntities) {
1505
+ return linkedEntities.filter((entity) => entity.type === "governanceGroup" && entity.coreAddress).map((entity) => ({
1506
+ id: entity.coreAddress,
1507
+ type: "group",
1508
+ relationship: "governs",
1509
+ service: ""
1510
+ }));
1511
+ }
1512
+
1513
+ // src/core/lib/domainCard/defaultSurvey.ts
1514
+ var tempDomainCreatorSurvey = {
1515
+ title: "Domain Card Creation",
1516
+ description: "This survey collects structured information required to create a Domain Card Verifiable Credential in compliance with W3C standards.",
1517
+ pages: [
1518
+ {
1519
+ name: "domainDetails",
1520
+ title: "Domain Information",
1521
+ description: "Provide identifying and descriptive information about the domain entity represented by this credential.",
1522
+ elements: [
1523
+ {
1524
+ type: "boolean",
1525
+ name: "ixo:advancedDomainSettings",
1526
+ title: "Show Advanced Options",
1527
+ defaultValue: "false"
1528
+ },
1529
+ {
1530
+ type: "dropdown",
1531
+ name: "type_1",
1532
+ visible: false,
1533
+ title: "Domain Type (Primary)",
1534
+ defaultValue: "dao",
1535
+ choices: [
1536
+ {
1537
+ value: "dao",
1538
+ text: "DAO"
1539
+ },
1540
+ {
1541
+ value: "protocol",
1542
+ text: "Protocol"
1543
+ }
1544
+ ]
1545
+ },
1546
+ {
1547
+ type: "dropdown",
1548
+ name: "type_2",
1549
+ title: "Domain Type ",
1550
+ isRequired: true,
1551
+ choicesByUrl: {
1552
+ url: "https://test.studio.ixo.earth/api/survey-choices?url=https://raw.githubusercontent.com/ixofoundation/ns/refs/heads/GraemeLeightonIXO-patch-4/protocol/entities/v1/index.json&path=entities.dao.types",
1553
+ valueName: "Value",
1554
+ titleName: "Text"
1555
+ }
1556
+ },
1557
+ {
1558
+ type: "dropdown",
1559
+ name: "daoType",
1560
+ title: "DAO Type",
1561
+ isRequired: true,
1562
+ choicesByUrl: {
1563
+ url: "https://test.studio.ixo.earth/api/survey-choices?url=https://raw.githubusercontent.com/ixofoundation/ns/refs/heads/GraemeLeightonIXO-patch-4/protocol/tags/v1/index.json&path=daoType",
1564
+ valueName: "Value",
1565
+ titleName: "Text"
1566
+ }
1567
+ },
1568
+ {
1569
+ type: "text",
1570
+ name: "schema:validFrom",
1571
+ title: "Valid From",
1572
+ defaultValueExpression: "today()",
1573
+ isRequired: true,
1574
+ inputType: "date"
1575
+ },
1576
+ {
1577
+ type: "text",
1578
+ name: "schema:validUntil",
1579
+ title: "Vaid Untill",
1580
+ defaultValueExpression: "today()",
1581
+ isRequired: true,
1582
+ inputType: "date"
1583
+ },
1584
+ {
1585
+ type: "text",
1586
+ name: "schema:name",
1587
+ title: "Domain Name",
1588
+ description: "The official name of the domain.",
1589
+ isRequired: true
1590
+ },
1591
+ {
1592
+ type: "paneldynamic",
1593
+ name: "pannel_schema:alternateName",
1594
+ title: "Alternate Names",
1595
+ templateElements: [
1596
+ {
1597
+ type: "text",
1598
+ name: "schema:alternateName",
1599
+ title: "Alternate Name"
1600
+ }
1601
+ ]
1602
+ },
1603
+ {
1604
+ type: "text",
1605
+ name: "schema:url",
1606
+ title: "URL",
1607
+ description: "Primary URL for the domain",
1608
+ inputType: "url"
1609
+ },
1610
+ {
1611
+ type: "paneldynamic",
1612
+ name: "schema:sameAs",
1613
+ title: "Additional URLs",
1614
+ description: "Additional URLs associated with the domain (Twitter, Github, Medium)",
1615
+ templateElements: [
1616
+ {
1617
+ type: "text",
1618
+ name: "schema:sameAs.url",
1619
+ title: "URL",
1620
+ inputType: "url"
1621
+ }
1622
+ ]
1623
+ },
1624
+ {
1625
+ type: "comment",
1626
+ name: "schema.description",
1627
+ title: "Canonical Description",
1628
+ description: "A concise, one-paragraph description of the domain.",
1629
+ isRequired: true
1630
+ },
1631
+ {
1632
+ type: "panel",
1633
+ name: "pannel_schema:media",
1634
+ title: "Domain Images",
1635
+ elements: [
1636
+ {
1637
+ type: "text",
1638
+ name: "ixo:imageProfile_url",
1639
+ title: "Profile Image URL",
1640
+ inputType: "url"
1641
+ },
1642
+ {
1643
+ type: "file",
1644
+ name: "ixo:imageProfile",
1645
+ title: "Profile Image"
1646
+ },
1647
+ {
1648
+ type: "text",
1649
+ name: "ixo:imageLogo_url",
1650
+ title: "Logo URL",
1651
+ inputType: "url"
1652
+ },
1653
+ {
1654
+ type: "file",
1655
+ name: "ixo:imageLogo",
1656
+ title: "Logo"
1657
+ }
1658
+ ]
1659
+ },
1660
+ {
1661
+ type: "comment",
1662
+ name: "schema:keywords",
1663
+ title: "Keywords",
1664
+ description: "List of comma separated keywords describing the domain\u2019s focus areas."
1665
+ },
1666
+ {
1667
+ type: "paneldynamic",
1668
+ name: "pannel_ixo:knowsAbout",
1669
+ title: "Topics /Primary Knowledge Areas",
1670
+ description: "Subjects or fields the domain is knowledgeable in.",
1671
+ templateElements: [
1672
+ {
1673
+ type: "text",
1674
+ name: "ixo:knowsAbout",
1675
+ title: "Knows About"
1676
+ }
1677
+ ]
1678
+ }
1679
+ ]
1680
+ },
1681
+ {
1682
+ name: "contactAndLocation",
1683
+ visibleIf: "{ixo:advancedDomainSettings} = true",
1684
+ title: "Contact & Location",
1685
+ description: "Provide address and contact information for the domain.",
1686
+ elements: [
1687
+ {
1688
+ type: "panel",
1689
+ name: "schema:address",
1690
+ title: "Postal Address",
1691
+ elements: [
1692
+ {
1693
+ type: "text",
1694
+ name: "schema:streetAddress",
1695
+ title: "Street Address"
1696
+ },
1697
+ {
1698
+ type: "text",
1699
+ name: "schema:addressLocality",
1700
+ title: "City"
1701
+ },
1702
+ {
1703
+ type: "text",
1704
+ name: "schema:addressRegion",
1705
+ title: "Region/State"
1706
+ },
1707
+ {
1708
+ type: "text",
1709
+ name: "schema:postalCode",
1710
+ title: "Postal Code"
1711
+ },
1712
+ {
1713
+ type: "text",
1714
+ name: "schema:addressCountry",
1715
+ title: "Country"
1716
+ }
1717
+ ]
1718
+ },
1719
+ {
1720
+ type: "text",
1721
+ name: "schema:AdministrativeArea",
1722
+ title: "Area Served"
1723
+ },
1724
+ {
1725
+ type: "paneldynamic",
1726
+ name: "pannel:schema_contactPoint",
1727
+ title: "Contact Points",
1728
+ description: "List available contact methods for support, business, or technical inquiries.",
1729
+ templateElements: [
1730
+ {
1731
+ type: "text",
1732
+ name: "schema:contactType",
1733
+ title: "Contact Type",
1734
+ description: "Example: General, Support, Sales"
1735
+ },
1736
+ {
1737
+ type: "text",
1738
+ name: "schema:email",
1739
+ title: "Email Address",
1740
+ inputType: "email"
1741
+ },
1742
+ {
1743
+ type: "text",
1744
+ name: "schema:telephone",
1745
+ title: "Telephone ",
1746
+ inputType: "tel"
1747
+ },
1748
+ {
1749
+ type: "text",
1750
+ name: "schema:availableLanguage",
1751
+ title: "Languages Supported",
1752
+ description: "Comma separated two letter language code (English = en)"
1753
+ }
1754
+ ]
1755
+ }
1756
+ ]
1757
+ },
1758
+ {
1759
+ name: "composition",
1760
+ visibleIf: "{ixo:advancedDomainSettings} = true",
1761
+ title: "Composition",
1762
+ elements: [
1763
+ {
1764
+ type: "paneldynamic",
1765
+ name: "schema:hasPart",
1766
+ title: "Domain Components",
1767
+ description: "Describes the specific items, documents, linked domains, or components that belong to this domain.",
1768
+ templateElements: [
1769
+ {
1770
+ type: "text",
1771
+ name: "schema:hasPart.id",
1772
+ title: "Identifier",
1773
+ description: "URI or URL "
1774
+ },
1775
+ {
1776
+ type: "text",
1777
+ name: "schema:hasPart.name",
1778
+ title: "Name"
1779
+ },
1780
+ {
1781
+ type: "text",
1782
+ name: "schema:hasPart.description",
1783
+ title: "Description"
1784
+ },
1785
+ {
1786
+ type: "text",
1787
+ name: "schema:hasPart.url",
1788
+ title: "URL",
1789
+ description: "If different to the identifier",
1790
+ inputType: "url"
1791
+ },
1792
+ {
1793
+ type: "text",
1794
+ name: "schema:hasPart.creator.name",
1795
+ title: "Creator",
1796
+ description: "Component creator (Organisation Name)"
1797
+ }
1798
+ ]
1799
+ },
1800
+ {
1801
+ type: "paneldynamic",
1802
+ name: "schema:subjectOf",
1803
+ title: "Publications",
1804
+ description: "Publications produced by the domain or where the domain is the subject.",
1805
+ templateElements: [
1806
+ {
1807
+ type: "text",
1808
+ name: "schema:subjectOf.name",
1809
+ title: "Publication Title"
1810
+ },
1811
+ {
1812
+ type: "text",
1813
+ name: "schema:subjectOf.url",
1814
+ title: "URL"
1815
+ },
1816
+ {
1817
+ type: "text",
1818
+ name: "schema:subjectOf.author.name",
1819
+ title: "Author"
1820
+ }
1821
+ ]
1822
+ },
1823
+ {
1824
+ type: "paneldynamic",
1825
+ name: "schema:makesOffer",
1826
+ title: "Offers (Product and/or Services)",
1827
+ templateElements: [
1828
+ {
1829
+ type: "dropdown",
1830
+ name: "schema:itemOffered.type",
1831
+ title: "Catagory",
1832
+ choices: [
1833
+ {
1834
+ value: "product",
1835
+ text: "Product"
1836
+ },
1837
+ {
1838
+ value: "service",
1839
+ text: "Service"
1840
+ }
1841
+ ]
1842
+ },
1843
+ {
1844
+ type: "text",
1845
+ name: "schema:itemOffered.name",
1846
+ title: "Name"
1847
+ },
1848
+ {
1849
+ type: "text",
1850
+ name: "schema:itemOffered.description",
1851
+ title: "Description"
1852
+ },
1853
+ {
1854
+ type: "text",
1855
+ name: "schema:itemOffered.url",
1856
+ title: "URL",
1857
+ inputType: "url"
1858
+ }
1859
+ ]
1860
+ }
1861
+ ]
1862
+ },
1863
+ {
1864
+ name: "relationshipsAndOffers",
1865
+ visibleIf: "{ixo:advancedDomainSettings} = true",
1866
+ title: "Relationships & Funding",
1867
+ description: "Describe the domain\u2019s relationships with other organizations and its software or service offerings.",
1868
+ elements: [
1869
+ {
1870
+ type: "paneldynamic",
1871
+ name: "schema:memberOf",
1872
+ title: "Memberships",
1873
+ templateElements: [
1874
+ {
1875
+ type: "text",
1876
+ name: "schema:memberOf.name",
1877
+ title: "Organization Name"
1878
+ }
1879
+ ]
1880
+ },
1881
+ {
1882
+ type: "paneldynamic",
1883
+ name: "schema:wasAssociatedWith",
1884
+ title: "Partner/Associated Organizations",
1885
+ templateElements: [
1886
+ {
1887
+ type: "text",
1888
+ name: "schema:wasAssociatedWith.name",
1889
+ title: "Organization Name"
1890
+ },
1891
+ {
1892
+ type: "text",
1893
+ name: "schema:wasAssociatedWith.url",
1894
+ title: "URL"
1895
+ }
1896
+ ]
1897
+ },
1898
+ {
1899
+ type: "paneldynamic",
1900
+ name: "schema:funding",
1901
+ title: "Funding Sources",
1902
+ templateElements: [
1903
+ {
1904
+ type: "text",
1905
+ name: "schema:funder.name",
1906
+ title: "Funder Organization"
1907
+ },
1908
+ {
1909
+ type: "text",
1910
+ name: "schema:amount.currency",
1911
+ title: "Currency Code"
1912
+ },
1913
+ {
1914
+ type: "text",
1915
+ name: "schema:amount.value",
1916
+ title: "Funding Amount"
1917
+ }
1918
+ ]
1919
+ }
1920
+ ]
1921
+ },
1922
+ {
1923
+ name: "events",
1924
+ visibleIf: "{ixo:advancedDomainSettings} = true",
1925
+ title: "Events",
1926
+ elements: [
1927
+ {
1928
+ type: "paneldynamic",
1929
+ name: "schema:event",
1930
+ title: "Event",
1931
+ templateElements: [
1932
+ {
1933
+ type: "text",
1934
+ name: "schema:event.name",
1935
+ title: "Name"
1936
+ },
1937
+ {
1938
+ type: "text",
1939
+ name: "schema:startDate",
1940
+ title: "Start Date"
1941
+ },
1942
+ {
1943
+ type: "text",
1944
+ name: "schema:endDate",
1945
+ title: "End Date"
1946
+ },
1947
+ {
1948
+ type: "text",
1949
+ name: "schema:event.location",
1950
+ title: "Location Name"
1951
+ },
1952
+ {
1953
+ type: "panel",
1954
+ name: "schema:event.address",
1955
+ title: "Postal Address",
1956
+ elements: [
1957
+ {
1958
+ type: "text",
1959
+ name: "schema:event.streetAddress",
1960
+ title: "Street Address"
1961
+ },
1962
+ {
1963
+ type: "text",
1964
+ name: "schema:event.addressLocality",
1965
+ title: "City"
1966
+ },
1967
+ {
1968
+ type: "text",
1969
+ name: "schema:event.addressRegion",
1970
+ title: "Region/State"
1971
+ },
1972
+ {
1973
+ type: "text",
1974
+ name: "schema:event.postalCode",
1975
+ title: "Postal Code"
1976
+ },
1977
+ {
1978
+ type: "text",
1979
+ name: "schema:event.addressCountry",
1980
+ title: "Country"
1981
+ }
1982
+ ]
1983
+ }
1984
+ ]
1985
+ }
1986
+ ]
1987
+ },
1988
+ {
1989
+ name: "agentsCredentialsAndAttributes",
1990
+ visibleIf: "{ixo:advancedDomainSettings} = true",
1991
+ title: "Agents, Credentials, and Attributes",
1992
+ elements: [
1993
+ {
1994
+ type: "paneldynamic",
1995
+ name: "ixo:agentCard",
1996
+ title: "Agents",
1997
+ templateElements: [
1998
+ {
1999
+ type: "text",
2000
+ name: "ixo:agentCard.id",
2001
+ title: "Agent ID"
2002
+ },
2003
+ {
2004
+ type: "text",
2005
+ name: "ixo:agentCard.name",
2006
+ title: "Name"
2007
+ },
2008
+ {
2009
+ type: "text",
2010
+ name: "ixo:agentCard.description",
2011
+ title: "Description"
2012
+ }
2013
+ ]
2014
+ },
2015
+ {
2016
+ type: "paneldynamic",
2017
+ name: "ixo:verifiableCredential",
2018
+ title: "Credentials",
2019
+ templateElements: [
2020
+ {
2021
+ type: "text",
2022
+ name: "schema:ID",
2023
+ title: "Credential ID"
2024
+ },
2025
+ {
2026
+ type: "text",
2027
+ name: "schema:Name",
2028
+ title: "Name"
2029
+ },
2030
+ {
2031
+ type: "text",
2032
+ name: "schema:description",
2033
+ title: "Description"
2034
+ }
2035
+ ]
2036
+ },
2037
+ {
2038
+ type: "paneldynamic",
2039
+ name: "ixo:attribute",
2040
+ title: "Attributes",
2041
+ templateElements: [
2042
+ {
2043
+ type: "text",
2044
+ name: "schema:ID_2",
2045
+ title: "Attribute ID"
2046
+ },
2047
+ {
2048
+ type: "text",
2049
+ name: "schema:name_2",
2050
+ title: "Name"
2051
+ },
2052
+ {
2053
+ type: "text",
2054
+ name: "schema:description_2",
2055
+ title: "Description"
2056
+ }
2057
+ ]
2058
+ }
2059
+ ]
2060
+ },
2061
+ {
2062
+ name: "project",
2063
+ visibleIf: "{ixo:advancedDomainSettings} = true",
2064
+ title: "Project Information",
2065
+ description: "Provide details about the related project(s), including objectives, sponsors, and deliverables.",
2066
+ elements: [
2067
+ {
2068
+ type: "paneldynamic",
2069
+ name: "pannel_proj:project",
2070
+ title: "Projects",
2071
+ templateElements: [
2072
+ {
2073
+ type: "text",
2074
+ name: "proj:project.name",
2075
+ title: "Project Title"
2076
+ },
2077
+ {
2078
+ type: "comment",
2079
+ name: "proj:project.description",
2080
+ title: "Project Mission",
2081
+ description: "High-level purpose or mission statement of the project."
2082
+ },
2083
+ {
2084
+ type: "paneldynamic",
2085
+ name: "proj:project.hadObjective",
2086
+ title: "Project Objectives",
2087
+ templateElements: [
2088
+ {
2089
+ type: "comment",
2090
+ name: "proj:hadObjective",
2091
+ title: "Project Objective"
2092
+ }
2093
+ ]
2094
+ },
2095
+ {
2096
+ type: "text",
2097
+ name: "proj:plannedStart",
2098
+ title: "Planned Start Date",
2099
+ inputType: "datetime-local"
2100
+ },
2101
+ {
2102
+ type: "text",
2103
+ name: "proj:plannedEnd",
2104
+ title: "Planned End Date",
2105
+ inputType: "datetime-local"
2106
+ },
2107
+ {
2108
+ type: "paneldynamic",
2109
+ name: "proj:wasFundedThrough",
2110
+ title: "Project Funding",
2111
+ templateElements: [
2112
+ {
2113
+ type: "text",
2114
+ name: "proj:moneyAmount",
2115
+ title: "Funding Amount"
2116
+ },
2117
+ {
2118
+ type: "text",
2119
+ name: "proj:moneyCurrency",
2120
+ title: "Funding Currency"
2121
+ },
2122
+ {
2123
+ type: "text",
2124
+ name: "prov.agent.name",
2125
+ title: "Funder Name"
2126
+ },
2127
+ {
2128
+ type: "text",
2129
+ name: "prov:agent.id",
2130
+ title: "Funder URL",
2131
+ inputType: "url"
2132
+ }
2133
+ ]
2134
+ }
2135
+ ]
2136
+ }
2137
+ ]
2138
+ },
2139
+ {
2140
+ name: "researchProfile",
2141
+ title: "Research Profile",
2142
+ description: "Provide information about the research profile associated with the domain.",
2143
+ elements: [
2144
+ {
2145
+ type: "paneldynamic",
2146
+ name: "ixo:ResearchProfile",
2147
+ title: "Seed Queries",
2148
+ templateElements: [
2149
+ {
2150
+ type: "comment",
2151
+ name: "ixo:seedQueries",
2152
+ title: "Seed Query",
2153
+ description: "Seed keywords or queries that define the research scope."
2154
+ }
2155
+ ]
2156
+ },
2157
+ {
2158
+ type: "paneldynamic",
2159
+ name: "schema:creativeWork",
2160
+ title: "Citations",
2161
+ templateElements: [
2162
+ {
2163
+ type: "text",
2164
+ name: "schema:creativeWork.name",
2165
+ title: "Citation Title"
2166
+ },
2167
+ {
2168
+ type: "text",
2169
+ name: "schema:creativeWork.url",
2170
+ title: "Citation URL"
2171
+ },
2172
+ {
2173
+ type: "text",
2174
+ name: "schema:creativeWork.publisher",
2175
+ title: "Publisher"
2176
+ },
2177
+ {
2178
+ type: "text",
2179
+ name: "schema:creativeWork.datePublished",
2180
+ title: "Date Published",
2181
+ inputType: "datetime-local"
2182
+ }
2183
+ ]
2184
+ }
2185
+ ]
2186
+ }
2187
+ ],
2188
+ showPageTitles: false,
2189
+ showQuestionNumbers: "on",
2190
+ showProgressBar: true,
2191
+ progressBarLocation: "top"
2192
+ };
1465
2193
 
1466
- // src/core/lib/actionRegistry/actions/domainCreate.ts
2194
+ // src/core/lib/actionRegistry/actions/domainSign.ts
1467
2195
  registerAction({
1468
- type: "qi/domain.create",
1469
- can: "domain/create",
2196
+ type: "qi/domain.sign",
2197
+ can: "domain/sign",
1470
2198
  sideEffect: true,
1471
2199
  defaultRequiresConfirmation: true,
1472
2200
  requiredCapability: "flow/block/execute",
1473
2201
  outputSchema: [
1474
- { path: "entityDid", displayName: "Entity DID", type: "string", description: "The created domain entity DID" },
1475
- { path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "Blockchain transaction hash" },
1476
- { path: "credentialId", displayName: "Credential ID", type: "string", description: "The uploaded domain card credential identifier (CID)" },
1477
- { path: "entityType", displayName: "Entity Type", type: "string", description: "The type of domain entity created" }
2202
+ { path: "entityDid", displayName: "Entity DID", type: "string", description: "The DID of the newly created domain entity" },
2203
+ { path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "The on-chain transaction hash for domain creation" }
1478
2204
  ],
1479
2205
  run: async (inputs, ctx) => {
1480
2206
  const handlers = ctx.handlers;
1481
- if (!handlers) throw new Error("Handlers not available");
2207
+ if (!handlers) {
2208
+ throw new Error("Handlers not available");
2209
+ }
2210
+ if (!handlers.requestPin) throw new Error("requestPin handler not available");
1482
2211
  if (!handlers.signCredential) throw new Error("signCredential handler not implemented");
1483
2212
  if (!handlers.publicFileUpload) throw new Error("publicFileUpload handler not available");
1484
2213
  if (!handlers.createDomain) throw new Error("createDomain handler not implemented");
1485
- if (!handlers.requestPin) throw new Error("requestPin handler not available");
1486
- const configEntityType = String(inputs.entityType || "dao").trim();
1487
- let surveyData = {};
1488
- if (inputs.surveyData) {
1489
- if (typeof inputs.surveyData === "string") {
1490
- try {
1491
- surveyData = JSON.parse(inputs.surveyData);
1492
- } catch {
1493
- throw new Error("surveyData must be valid JSON");
1494
- }
1495
- } else if (typeof inputs.surveyData === "object" && !Array.isArray(inputs.surveyData)) {
1496
- surveyData = inputs.surveyData;
2214
+ let domainCardData;
2215
+ if (typeof inputs.domainCardData === "string") {
2216
+ try {
2217
+ domainCardData = JSON.parse(inputs.domainCardData);
2218
+ } catch {
2219
+ throw new Error("domainCardData must be valid JSON");
1497
2220
  }
2221
+ } else if (inputs.domainCardData && typeof inputs.domainCardData === "object") {
2222
+ domainCardData = inputs.domainCardData;
2223
+ } else {
2224
+ throw new Error("domainCardData is required");
2225
+ }
2226
+ if (!domainCardData?.credentialSubject?.name) {
2227
+ throw new Error("domainCardData is missing or invalid (credentialSubject.name required)");
1498
2228
  }
2229
+ const extractEntityType = (type) => type.replace(/^schema:/i, "").toLowerCase();
2230
+ const entityType = String(inputs.entityType || "").trim() || (domainCardData.credentialSubject?.type?.[0] ? extractEntityType(domainCardData.credentialSubject.type[0]) : "dao");
1499
2231
  const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
1500
2232
  if (!issuerDid) throw new Error("Unable to determine issuer DID");
1501
- const entityDid = "did:ixo:entity:pending";
1502
- const credentialSubject = transformSurveyToCredentialSubject(surveyData, entityDid);
2233
+ const entityDidPlaceholder = "did:ixo:entity:pending";
2234
+ const validFrom = domainCardData.validFrom || (/* @__PURE__ */ new Date()).toISOString();
2235
+ const validUntil = domainCardData.validUntil || (() => {
2236
+ const d = /* @__PURE__ */ new Date();
2237
+ d.setFullYear(d.getFullYear() + 100);
2238
+ return d.toISOString();
2239
+ })();
2240
+ const credentialSubject = {
2241
+ ...domainCardData.credentialSubject,
2242
+ id: entityDidPlaceholder
2243
+ };
1503
2244
  const unsignedCredential = buildVerifiableCredential({
1504
- entityDid,
2245
+ entityDid: entityDidPlaceholder,
1505
2246
  issuerDid,
1506
2247
  credentialSubject,
1507
- validFrom: surveyData["schema:validFrom"] || (/* @__PURE__ */ new Date()).toISOString(),
1508
- validUntil: surveyData["schema:validUntil"]
2248
+ validFrom,
2249
+ validUntil
1509
2250
  });
1510
2251
  const pin = await handlers.requestPin({
1511
2252
  title: "Sign Domain Card",
@@ -1526,24 +2267,160 @@ registerAction({
1526
2267
  });
1527
2268
  const uploadResult = await handlers.publicFileUpload(credentialFile);
1528
2269
  const domainCardLinkedResource = buildDomainCardLinkedResource({
1529
- entityDid,
2270
+ entityDid: entityDidPlaceholder,
1530
2271
  cid: uploadResult.cid,
1531
2272
  serviceEndpoint: uploadResult.url,
1532
- description: `Domain Card for ${surveyData["schema:name"] || "Domain"}`
2273
+ description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
1533
2274
  });
1534
- const finalEntityType = surveyData["type_2"] || surveyData["daoType"] || configEntityType;
2275
+ let linkedEntitiesData = [];
2276
+ if (inputs.linkedEntities) {
2277
+ if (typeof inputs.linkedEntities === "string") {
2278
+ try {
2279
+ linkedEntitiesData = JSON.parse(inputs.linkedEntities);
2280
+ } catch {
2281
+ }
2282
+ } else if (Array.isArray(inputs.linkedEntities)) {
2283
+ linkedEntitiesData = inputs.linkedEntities;
2284
+ }
2285
+ }
2286
+ const governanceGroupLinkedEntities = buildGovernanceGroupLinkedEntities(parseLinkedEntities(JSON.stringify(linkedEntitiesData)));
2287
+ const endDate = domainCardData.endDate || validUntil;
1535
2288
  const { entityDid: newEntityDid, transactionHash } = await handlers.createDomain({
1536
- entityType: finalEntityType,
2289
+ entityType,
1537
2290
  linkedResource: [domainCardLinkedResource],
1538
- startDate: surveyData["schema:validFrom"],
1539
- endDate: surveyData["schema:validUntil"]
2291
+ linkedEntity: governanceGroupLinkedEntities.length > 0 ? governanceGroupLinkedEntities : void 0,
2292
+ startDate: validFrom,
2293
+ endDate
1540
2294
  });
1541
2295
  return {
1542
2296
  output: {
1543
2297
  entityDid: newEntityDid,
1544
- transactionHash,
1545
- credentialId: uploadResult.cid,
1546
- entityType: finalEntityType
2298
+ transactionHash
2299
+ }
2300
+ };
2301
+ }
2302
+ });
2303
+
2304
+ // src/core/lib/actionRegistry/actions/domainCardBuild.ts
2305
+ registerAction({
2306
+ type: "qi/domain.card-build",
2307
+ can: "domain/card-build",
2308
+ sideEffect: false,
2309
+ defaultRequiresConfirmation: false,
2310
+ outputSchema: [
2311
+ {
2312
+ path: "domainCardData",
2313
+ displayName: "Domain Card Data",
2314
+ type: "object",
2315
+ description: "Unsigned domain card envelope { credentialSubject, validFrom, validUntil } ready for preview and signing"
2316
+ },
2317
+ { path: "unsignedCredential", displayName: "Unsigned Credential", type: "object", description: "The full unsigned W3C Verifiable Credential" },
2318
+ { path: "credentialSubject", displayName: "Credential Subject", type: "object", description: "The ixo:DomainCard credentialSubject extracted from the survey" },
2319
+ { path: "surveyData", displayName: "Survey Answers", type: "object", description: "Raw survey answers used to build the card" },
2320
+ { path: "entityType", displayName: "Entity Type", type: "string", description: "Resolved entity type (from survey or configured default)" },
2321
+ { path: "issuerDid", displayName: "Issuer DID", type: "string", description: "DID of the user or entity that built the card" }
2322
+ ],
2323
+ run: async (inputs, ctx) => {
2324
+ const handlers = ctx.handlers;
2325
+ if (!handlers) throw new Error("Handlers not available");
2326
+ const configEntityType = String(inputs.entityType || "dao").trim();
2327
+ let surveyData = {};
2328
+ if (inputs.surveyData) {
2329
+ if (typeof inputs.surveyData === "string") {
2330
+ try {
2331
+ surveyData = JSON.parse(inputs.surveyData);
2332
+ } catch {
2333
+ throw new Error("surveyData must be valid JSON");
2334
+ }
2335
+ } else if (typeof inputs.surveyData === "object" && !Array.isArray(inputs.surveyData)) {
2336
+ surveyData = inputs.surveyData;
2337
+ }
2338
+ }
2339
+ if (!surveyData || Object.keys(surveyData).length === 0) {
2340
+ throw new Error("surveyData is required to build a domain card");
2341
+ }
2342
+ const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
2343
+ if (!issuerDid) throw new Error("Unable to determine issuer DID");
2344
+ const entityDidPlaceholder = "did:ixo:entity:pending";
2345
+ const credentialSubject = transformSurveyToCredentialSubject(surveyData, entityDidPlaceholder);
2346
+ const validFrom = surveyData["schema:validFrom"] || (/* @__PURE__ */ new Date()).toISOString();
2347
+ const validUntil = surveyData["schema:validUntil"] || (() => {
2348
+ const d = new Date(validFrom);
2349
+ d.setFullYear(d.getFullYear() + 5);
2350
+ return d.toISOString();
2351
+ })();
2352
+ const unsignedCredential = buildVerifiableCredential({
2353
+ entityDid: entityDidPlaceholder,
2354
+ issuerDid,
2355
+ credentialSubject,
2356
+ validFrom,
2357
+ validUntil
2358
+ });
2359
+ const resolvedEntityType = surveyData["type_2"] || surveyData["daoType"] || configEntityType;
2360
+ const domainCardData = {
2361
+ credentialSubject,
2362
+ validFrom,
2363
+ validUntil
2364
+ };
2365
+ return {
2366
+ output: {
2367
+ domainCardData,
2368
+ unsignedCredential,
2369
+ credentialSubject,
2370
+ surveyData,
2371
+ entityType: resolvedEntityType,
2372
+ issuerDid
2373
+ }
2374
+ };
2375
+ }
2376
+ });
2377
+
2378
+ // src/core/lib/actionRegistry/actions/domainCardPreview.ts
2379
+ registerAction({
2380
+ type: "qi/domain.card-preview",
2381
+ can: "domain/card-preview",
2382
+ sideEffect: false,
2383
+ defaultRequiresConfirmation: false,
2384
+ outputSchema: [
2385
+ {
2386
+ path: "domainCardData",
2387
+ displayName: "Domain Card Data",
2388
+ type: "object",
2389
+ description: "Approved domain card envelope { credentialSubject, validFrom, validUntil } ready to sign"
2390
+ },
2391
+ { path: "domainPreviewData", displayName: "Preview Data", type: "object", description: "Oracle-enriched human-facing preview of the domain card" },
2392
+ { path: "status", displayName: "Status", type: "string", description: "pending | loading | ready | approved | error" },
2393
+ { path: "approvedAt", displayName: "Approved At", type: "number", description: "Timestamp when the user approved the preview" }
2394
+ ],
2395
+ run: async (inputs) => {
2396
+ let domainCardData = inputs.domainCardData;
2397
+ if (typeof domainCardData === "string") {
2398
+ try {
2399
+ domainCardData = JSON.parse(domainCardData);
2400
+ } catch {
2401
+ throw new Error("domainCardData must be valid JSON");
2402
+ }
2403
+ }
2404
+ if (!domainCardData || typeof domainCardData !== "object") {
2405
+ throw new Error("domainCardData is required to preview a domain card");
2406
+ }
2407
+ if (!domainCardData.credentialSubject?.name) {
2408
+ throw new Error("domainCardData.credentialSubject.name is required");
2409
+ }
2410
+ let domainPreviewData = inputs.domainPreviewData;
2411
+ if (typeof domainPreviewData === "string") {
2412
+ try {
2413
+ domainPreviewData = JSON.parse(domainPreviewData);
2414
+ } catch {
2415
+ domainPreviewData = void 0;
2416
+ }
2417
+ }
2418
+ return {
2419
+ output: {
2420
+ domainCardData,
2421
+ domainPreviewData,
2422
+ status: "approved",
2423
+ approvedAt: Date.now()
1547
2424
  }
1548
2425
  };
1549
2426
  }
@@ -2990,6 +3867,29 @@ function removePendingInvocation(yDoc, listenerBlockId, pendingInvocationId) {
2990
3867
  inner.delete(pendingInvocationId);
2991
3868
  return true;
2992
3869
  }
3870
+ function appendRunRecord(yDoc, blockId, details, userId) {
3871
+ const auditMap = yDoc.getMap("auditTrail");
3872
+ yDoc.transact(() => {
3873
+ let arr = auditMap.get(blockId);
3874
+ if (!arr) {
3875
+ arr = new Y.Array();
3876
+ auditMap.set(blockId, arr);
3877
+ }
3878
+ const event = {
3879
+ id: `${details.runId}`,
3880
+ blockId,
3881
+ type: RUN_RECORD_AUDIT_TYPE,
3882
+ details,
3883
+ message: void 0,
3884
+ meta: {
3885
+ timestamp: details.completedAt,
3886
+ userId,
3887
+ editable: false
3888
+ }
3889
+ };
3890
+ arr.push([event]);
3891
+ });
3892
+ }
2993
3893
  function readRunRecords(yDoc, blockId) {
2994
3894
  const auditMap = yDoc.getMap("auditTrail");
2995
3895
  const arr = auditMap.get(blockId);
@@ -3004,6 +3904,39 @@ function readRunRecords(yDoc, blockId) {
3004
3904
  });
3005
3905
  return records;
3006
3906
  }
3907
+ function findFailedListenersForSourceRun(yDoc, sourceBlockId, sourceRunId, listenerBlockIds) {
3908
+ const failures = [];
3909
+ for (const listenerBlockId of listenerBlockIds) {
3910
+ const records = readRunRecords(yDoc, listenerBlockId);
3911
+ for (const record of records) {
3912
+ if (!record.error) continue;
3913
+ if (record.triggeredBy?.sourceBlockId !== sourceBlockId) continue;
3914
+ if (record.fromPendingInvocationId == null) continue;
3915
+ const sourceRunIdField = record.sourceRunId;
3916
+ if (sourceRunIdField && sourceRunIdField !== sourceRunId) continue;
3917
+ failures.push({ listenerBlockId, record });
3918
+ }
3919
+ }
3920
+ return failures;
3921
+ }
3922
+ function replayFailedListenerRun(yDoc, failedRecord, listenerBlockId, originalPayload, originalRefSnapshots, assigneeDid) {
3923
+ if (!failedRecord.triggeredBy) return false;
3924
+ const replayId = `${failedRecord.runId}:replay-${Date.now().toString(36)}`;
3925
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3926
+ const replay = {
3927
+ id: replayId,
3928
+ triggeringBlockId: failedRecord.triggeredBy.sourceBlockId,
3929
+ sourceRunId: failedRecord.sourceRunId || failedRecord.runId,
3930
+ eventName: failedRecord.triggeredBy.eventName,
3931
+ eventIndex: 0,
3932
+ payload: originalPayload,
3933
+ refSnapshots: originalRefSnapshots,
3934
+ assigneeDid,
3935
+ emittedAt: now,
3936
+ expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1e3).toISOString()
3937
+ };
3938
+ return queuePendingInvocation(yDoc, listenerBlockId, replay);
3939
+ }
3007
3940
 
3008
3941
  // src/core/lib/flowEngine/reconcile.ts
3009
3942
  function reconcilePendingInvocations(editor) {
@@ -3142,6 +4075,11 @@ function parseIsoDurationToMs(duration) {
3142
4075
  if (s) ms += parseInt(s, 10) * 1e3;
3143
4076
  return ms;
3144
4077
  }
4078
+ function getActionForBlock(block) {
4079
+ const actionType = block?.props?.actionType;
4080
+ if (typeof actionType !== "string") return void 0;
4081
+ return getAction(actionType);
4082
+ }
3145
4083
 
3146
4084
  // src/core/lib/flowEngine/migration.ts
3147
4085
  var MIGRATION_REGISTRY = {};
@@ -3301,7 +4239,8 @@ var ICON_DEFAULTS = {
3301
4239
  "matrix/dm": "message-circle",
3302
4240
  "proposal/create": "scroll",
3303
4241
  "proposal/vote": "vote",
3304
- "domain/create": "globe",
4242
+ "domain/card-build": "file-text",
4243
+ "domain/card-preview": "id",
3305
4244
  "domain/sign": "feather",
3306
4245
  "credential/store": "shield",
3307
4246
  "payment/execute": "credit-card",
@@ -4140,12 +5079,7 @@ export {
4140
5079
  buildServicesFromHandlers,
4141
5080
  getDiffResolver,
4142
5081
  hasDiffResolver,
4143
- buildVerifiableCredential,
4144
- buildDomainCardLinkedResource,
4145
- parseLinkedEntities,
4146
- buildGovernanceGroupLinkedEntities,
4147
- transformSurveyToCredentialSubject,
4148
- extractSurveyAnswersTemplate,
5082
+ tempDomainCreatorSurvey,
4149
5083
  getHomeserver,
4150
5084
  didToMatrixUserId,
4151
5085
  findOrCreateDMRoom,
@@ -4163,9 +5097,20 @@ export {
4163
5097
  isAuthorized,
4164
5098
  executeNode,
4165
5099
  isRuntimeRef,
5100
+ RUN_RECORD_AUDIT_TYPE,
5101
+ computePendingInvocationId,
5102
+ snapshotInputRefs,
5103
+ getPendingInvocationsMap,
5104
+ getOrCreateBlockPendingMap,
4166
5105
  readPendingInvocations,
5106
+ queuePendingInvocation,
4167
5107
  removePendingInvocation,
5108
+ appendRunRecord,
5109
+ readRunRecords,
5110
+ findFailedListenersForSourceRun,
5111
+ replayFailedListenerRun,
4168
5112
  reconcilePendingInvocations,
5113
+ getActionForBlock,
4169
5114
  compileBaseUcanFlow,
4170
5115
  readCompiledFlowFromYDoc,
4171
5116
  mergeCompiledFlows,
@@ -4177,4 +5122,4 @@ export {
4177
5122
  readFlow,
4178
5123
  setupFlowFromBaseUcan
4179
5124
  };
4180
- //# sourceMappingURL=chunk-QIJA3CMG.mjs.map
5125
+ //# sourceMappingURL=chunk-4ETFMWQR.mjs.map