@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.
- package/dist/{chunk-QIJA3CMG.mjs → chunk-4ETFMWQR.mjs} +1232 -287
- package/dist/chunk-4ETFMWQR.mjs.map +1 -0
- package/dist/{chunk-FXFKKA6L.mjs → chunk-VE3WI2J2.mjs} +2 -2
- package/dist/{chunk-WIPR64OD.mjs → chunk-YWL7V44B.mjs} +4803 -5863
- package/dist/chunk-YWL7V44B.mjs.map +1 -0
- package/dist/core/index.d.ts +263 -5
- package/dist/core/index.mjs +30 -2
- package/dist/{decompile-BroSNv1q.d.ts → decompile-BNprXLsA.d.ts} +2 -2
- package/dist/{graphql-client-DGl50_zh.d.ts → graphql-client-l6N8ekd1.d.ts} +65 -2
- package/dist/{index-BEoftwDZ.d.ts → index-CNCZs4wP.d.ts} +1 -247
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +3 -3
- package/dist/mantine/index.d.ts +4 -4
- package/dist/mantine/index.mjs +2 -2
- package/package.json +1 -1
- package/dist/chunk-QIJA3CMG.mjs.map +0 -1
- package/dist/chunk-WIPR64OD.mjs.map +0 -1
- /package/dist/{chunk-FXFKKA6L.mjs.map → chunk-VE3WI2J2.mjs.map} +0 -0
|
@@ -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.
|
|
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/
|
|
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/
|
|
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/
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
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
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
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/
|
|
2194
|
+
// src/core/lib/actionRegistry/actions/domainSign.ts
|
|
1467
2195
|
registerAction({
|
|
1468
|
-
type: "qi/domain.
|
|
1469
|
-
can: "domain/
|
|
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
|
|
1475
|
-
{ path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "
|
|
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)
|
|
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
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
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
|
|
1502
|
-
const
|
|
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
|
|
1508
|
-
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 ${
|
|
2273
|
+
description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
|
|
1533
2274
|
});
|
|
1534
|
-
|
|
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
|
|
2289
|
+
entityType,
|
|
1537
2290
|
linkedResource: [domainCardLinkedResource],
|
|
1538
|
-
|
|
1539
|
-
|
|
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
|
-
|
|
1546
|
-
|
|
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/
|
|
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
|
-
|
|
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-
|
|
5125
|
+
//# sourceMappingURL=chunk-4ETFMWQR.mjs.map
|