@ixo/editor 3.9.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-JHQO6FAQ.mjs → chunk-4ETFMWQR.mjs} +990 -301
- package/dist/chunk-4ETFMWQR.mjs.map +1 -0
- package/dist/{chunk-UGCY7XXQ.mjs → chunk-MKNM3L24.mjs} +3193 -5312
- package/dist/chunk-MKNM3L24.mjs.map +1 -0
- package/dist/{chunk-OALEW7JG.mjs → chunk-VE3WI2J2.mjs} +2 -2
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.mjs +2 -2
- package/dist/{decompile-wCWLWfsQ.d.ts → decompile-BNprXLsA.d.ts} +1 -1
- package/dist/{graphql-client-C2VMAiQl.d.ts → graphql-client-l6N8ekd1.d.ts} +2 -2
- package/dist/{index-ClqpuDwu.d.ts → index-CNCZs4wP.d.ts} +0 -252
- 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-JHQO6FAQ.mjs.map +0 -1
- package/dist/chunk-UGCY7XXQ.mjs.map +0 -1
- /package/dist/{chunk-OALEW7JG.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",
|
|
@@ -347,10 +356,13 @@ registerAction({
|
|
|
347
356
|
sideEffect: false,
|
|
348
357
|
defaultRequiresConfirmation: false,
|
|
349
358
|
outputSchema: [
|
|
359
|
+
{ path: "groupName", displayName: "Group Name", type: "string", description: "Human-readable name for the governance group" },
|
|
350
360
|
{ path: "groupType", displayName: "Group Type", type: "string", description: "Governance group type (categorical | multisig | nftStaking | tokenStaking)" },
|
|
351
361
|
{ path: "governance", displayName: "Governance Settings", type: "object", description: "Cosmos group decision policy parameters" }
|
|
352
362
|
],
|
|
353
363
|
run: async (inputs) => {
|
|
364
|
+
const groupName = String(inputs.groupName || "").trim();
|
|
365
|
+
if (!groupName) throw new Error("groupName is required");
|
|
354
366
|
const groupType = inputs.groupType;
|
|
355
367
|
if (!groupType || !VALID_GROUP_TYPES.includes(groupType)) {
|
|
356
368
|
throw new Error(`groupType must be one of: ${VALID_GROUP_TYPES.join(", ")}`);
|
|
@@ -359,8 +371,11 @@ registerAction({
|
|
|
359
371
|
if (!governance) throw new Error("governance settings are required");
|
|
360
372
|
if (!governance.votingPeriod) throw new Error("votingPeriod is required");
|
|
361
373
|
if (groupType === "multisig") {
|
|
362
|
-
const
|
|
363
|
-
|
|
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
|
+
}
|
|
364
379
|
} else {
|
|
365
380
|
const quorum = parseFloat(governance.quorum);
|
|
366
381
|
if (isNaN(quorum) || quorum <= 0 || quorum > 1) throw new Error("quorum must be between 0 and 1 (e.g. 0.33)");
|
|
@@ -371,7 +386,7 @@ registerAction({
|
|
|
371
386
|
throw new Error("threshold + vetoThreshold cannot exceed 1.0");
|
|
372
387
|
}
|
|
373
388
|
}
|
|
374
|
-
return { output: { groupType, governance } };
|
|
389
|
+
return { output: { groupName, groupType, governance } };
|
|
375
390
|
}
|
|
376
391
|
});
|
|
377
392
|
|
|
@@ -1169,211 +1184,7 @@ registerAction({
|
|
|
1169
1184
|
}
|
|
1170
1185
|
});
|
|
1171
1186
|
|
|
1172
|
-
// src/
|
|
1173
|
-
var DOMAIN_CARD_CONTEXT = [
|
|
1174
|
-
"https://w3id.org/ixo/context/v1",
|
|
1175
|
-
{
|
|
1176
|
-
schema: "https://schema.org/",
|
|
1177
|
-
ixo: "https://w3id.org/ixo/vocab/v1",
|
|
1178
|
-
prov: "http://www.w3.org/ns/prov#",
|
|
1179
|
-
proj: "http://www.w3.org/ns/project#",
|
|
1180
|
-
id: "@id",
|
|
1181
|
-
type: "@type",
|
|
1182
|
-
"@protected": true
|
|
1183
|
-
}
|
|
1184
|
-
];
|
|
1185
|
-
var DOMAIN_CARD_SCHEMA = {
|
|
1186
|
-
id: "https://w3id.org/ixo/protocol/schema/v1#domainCard",
|
|
1187
|
-
type: "JsonSchema"
|
|
1188
|
-
};
|
|
1189
|
-
function toISOString(dateInput, fallback = /* @__PURE__ */ new Date()) {
|
|
1190
|
-
if (!dateInput) {
|
|
1191
|
-
return fallback.toISOString();
|
|
1192
|
-
}
|
|
1193
|
-
if (dateInput instanceof Date) {
|
|
1194
|
-
return dateInput.toISOString();
|
|
1195
|
-
}
|
|
1196
|
-
if (/^\d{4}-\d{2}-\d{2}$/.test(dateInput)) {
|
|
1197
|
-
return (/* @__PURE__ */ new Date(dateInput + "T00:00:00.000Z")).toISOString();
|
|
1198
|
-
}
|
|
1199
|
-
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$/.test(dateInput)) {
|
|
1200
|
-
return (/* @__PURE__ */ new Date(dateInput + ":00.000Z")).toISOString();
|
|
1201
|
-
}
|
|
1202
|
-
const parsed = new Date(dateInput);
|
|
1203
|
-
if (!isNaN(parsed.getTime())) {
|
|
1204
|
-
return parsed.toISOString();
|
|
1205
|
-
}
|
|
1206
|
-
return fallback.toISOString();
|
|
1207
|
-
}
|
|
1208
|
-
function getDefaultValidUntil(validFrom) {
|
|
1209
|
-
const fromDate = new Date(validFrom);
|
|
1210
|
-
const untilDate = new Date(fromDate);
|
|
1211
|
-
untilDate.setFullYear(untilDate.getFullYear() + 5);
|
|
1212
|
-
return untilDate.toISOString();
|
|
1213
|
-
}
|
|
1214
|
-
function buildVerifiableCredential(params) {
|
|
1215
|
-
const { entityDid, issuerDid, credentialSubject, validFrom, validUntil } = params;
|
|
1216
|
-
const validFromISO = toISOString(validFrom);
|
|
1217
|
-
const validUntilISO = validUntil ? toISOString(validUntil) : getDefaultValidUntil(validFromISO);
|
|
1218
|
-
return {
|
|
1219
|
-
"@context": DOMAIN_CARD_CONTEXT,
|
|
1220
|
-
id: `${entityDid}#dmn`,
|
|
1221
|
-
type: ["VerifiableCredential", "ixo:DomainCard"],
|
|
1222
|
-
issuer: {
|
|
1223
|
-
id: issuerDid
|
|
1224
|
-
},
|
|
1225
|
-
validFrom: validFromISO,
|
|
1226
|
-
validUntil: validUntilISO,
|
|
1227
|
-
credentialSchema: DOMAIN_CARD_SCHEMA,
|
|
1228
|
-
credentialSubject: {
|
|
1229
|
-
...credentialSubject,
|
|
1230
|
-
// Ensure the subject ID matches the entity DID
|
|
1231
|
-
id: entityDid
|
|
1232
|
-
}
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
function buildDomainCardLinkedResource(params) {
|
|
1236
|
-
return {
|
|
1237
|
-
id: `${params.entityDid}#dmn`,
|
|
1238
|
-
type: "domainCard",
|
|
1239
|
-
proof: params.cid,
|
|
1240
|
-
right: "",
|
|
1241
|
-
encrypted: "false",
|
|
1242
|
-
mediaType: "application/json",
|
|
1243
|
-
description: params.description || "Domain Card",
|
|
1244
|
-
serviceEndpoint: params.serviceEndpoint
|
|
1245
|
-
};
|
|
1246
|
-
}
|
|
1247
|
-
|
|
1248
|
-
// src/mantine/blocks/domainCreatorSign/utils/buildLinkedEntityResource.ts
|
|
1249
|
-
function parseLinkedEntities(entitiesString) {
|
|
1250
|
-
if (!entitiesString || entitiesString === "[]") return [];
|
|
1251
|
-
try {
|
|
1252
|
-
return JSON.parse(entitiesString);
|
|
1253
|
-
} catch {
|
|
1254
|
-
return [];
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
function buildGovernanceGroupLinkedEntities(linkedEntities) {
|
|
1258
|
-
return linkedEntities.filter((entity) => entity.type === "governanceGroup" && entity.coreAddress).map((entity) => ({
|
|
1259
|
-
id: entity.coreAddress,
|
|
1260
|
-
type: "group",
|
|
1261
|
-
relationship: "governs",
|
|
1262
|
-
service: ""
|
|
1263
|
-
}));
|
|
1264
|
-
}
|
|
1265
|
-
|
|
1266
|
-
// src/core/lib/actionRegistry/actions/domainSign.ts
|
|
1267
|
-
registerAction({
|
|
1268
|
-
type: "qi/domain.sign",
|
|
1269
|
-
can: "domain/sign",
|
|
1270
|
-
sideEffect: true,
|
|
1271
|
-
defaultRequiresConfirmation: true,
|
|
1272
|
-
requiredCapability: "flow/block/execute",
|
|
1273
|
-
outputSchema: [
|
|
1274
|
-
{ path: "entityDid", displayName: "Entity DID", type: "string", description: "The DID of the newly created domain entity" },
|
|
1275
|
-
{ path: "transactionHash", displayName: "Transaction Hash", type: "string", description: "The on-chain transaction hash for domain creation" }
|
|
1276
|
-
],
|
|
1277
|
-
run: async (inputs, ctx) => {
|
|
1278
|
-
const handlers = ctx.handlers;
|
|
1279
|
-
if (!handlers) {
|
|
1280
|
-
throw new Error("Handlers not available");
|
|
1281
|
-
}
|
|
1282
|
-
if (!handlers.requestPin) throw new Error("requestPin handler not available");
|
|
1283
|
-
if (!handlers.signCredential) throw new Error("signCredential handler not implemented");
|
|
1284
|
-
if (!handlers.publicFileUpload) throw new Error("publicFileUpload handler not available");
|
|
1285
|
-
if (!handlers.createDomain) throw new Error("createDomain handler not implemented");
|
|
1286
|
-
let domainCardData;
|
|
1287
|
-
if (typeof inputs.domainCardData === "string") {
|
|
1288
|
-
try {
|
|
1289
|
-
domainCardData = JSON.parse(inputs.domainCardData);
|
|
1290
|
-
} catch {
|
|
1291
|
-
throw new Error("domainCardData must be valid JSON");
|
|
1292
|
-
}
|
|
1293
|
-
} else if (inputs.domainCardData && typeof inputs.domainCardData === "object") {
|
|
1294
|
-
domainCardData = inputs.domainCardData;
|
|
1295
|
-
} else {
|
|
1296
|
-
throw new Error("domainCardData is required");
|
|
1297
|
-
}
|
|
1298
|
-
if (!domainCardData?.credentialSubject?.name) {
|
|
1299
|
-
throw new Error("domainCardData is missing or invalid (credentialSubject.name required)");
|
|
1300
|
-
}
|
|
1301
|
-
const extractEntityType = (type) => type.replace(/^schema:/i, "").toLowerCase();
|
|
1302
|
-
const entityType = String(inputs.entityType || "").trim() || (domainCardData.credentialSubject?.type?.[0] ? extractEntityType(domainCardData.credentialSubject.type[0]) : "dao");
|
|
1303
|
-
const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
|
|
1304
|
-
if (!issuerDid) throw new Error("Unable to determine issuer DID");
|
|
1305
|
-
const entityDidPlaceholder = "did:ixo:entity:pending";
|
|
1306
|
-
const validFrom = domainCardData.validFrom || (/* @__PURE__ */ new Date()).toISOString();
|
|
1307
|
-
const validUntil = domainCardData.validUntil || (() => {
|
|
1308
|
-
const d = /* @__PURE__ */ new Date();
|
|
1309
|
-
d.setFullYear(d.getFullYear() + 100);
|
|
1310
|
-
return d.toISOString();
|
|
1311
|
-
})();
|
|
1312
|
-
const credentialSubject = {
|
|
1313
|
-
...domainCardData.credentialSubject,
|
|
1314
|
-
id: entityDidPlaceholder
|
|
1315
|
-
};
|
|
1316
|
-
const unsignedCredential = buildVerifiableCredential({
|
|
1317
|
-
entityDid: entityDidPlaceholder,
|
|
1318
|
-
issuerDid,
|
|
1319
|
-
credentialSubject,
|
|
1320
|
-
validFrom,
|
|
1321
|
-
validUntil
|
|
1322
|
-
});
|
|
1323
|
-
const pin = await handlers.requestPin({
|
|
1324
|
-
title: "Sign Domain Card",
|
|
1325
|
-
description: "Enter your PIN to sign the Domain Card credential",
|
|
1326
|
-
submitText: "Sign"
|
|
1327
|
-
});
|
|
1328
|
-
const { signedCredential } = await handlers.signCredential({
|
|
1329
|
-
issuerDid,
|
|
1330
|
-
issuerType: "user",
|
|
1331
|
-
credential: unsignedCredential,
|
|
1332
|
-
pin
|
|
1333
|
-
});
|
|
1334
|
-
const credentialBlob = new Blob([JSON.stringify(signedCredential, null, 2)], {
|
|
1335
|
-
type: "application/json"
|
|
1336
|
-
});
|
|
1337
|
-
const credentialFile = new File([credentialBlob], "domainCard.json", {
|
|
1338
|
-
type: "application/json"
|
|
1339
|
-
});
|
|
1340
|
-
const uploadResult = await handlers.publicFileUpload(credentialFile);
|
|
1341
|
-
const domainCardLinkedResource = buildDomainCardLinkedResource({
|
|
1342
|
-
entityDid: entityDidPlaceholder,
|
|
1343
|
-
cid: uploadResult.cid,
|
|
1344
|
-
serviceEndpoint: uploadResult.url,
|
|
1345
|
-
description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
|
|
1346
|
-
});
|
|
1347
|
-
let linkedEntitiesData = [];
|
|
1348
|
-
if (inputs.linkedEntities) {
|
|
1349
|
-
if (typeof inputs.linkedEntities === "string") {
|
|
1350
|
-
try {
|
|
1351
|
-
linkedEntitiesData = JSON.parse(inputs.linkedEntities);
|
|
1352
|
-
} catch {
|
|
1353
|
-
}
|
|
1354
|
-
} else if (Array.isArray(inputs.linkedEntities)) {
|
|
1355
|
-
linkedEntitiesData = inputs.linkedEntities;
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
const governanceGroupLinkedEntities = buildGovernanceGroupLinkedEntities(parseLinkedEntities(JSON.stringify(linkedEntitiesData)));
|
|
1359
|
-
const endDate = domainCardData.endDate || validUntil;
|
|
1360
|
-
const { entityDid: newEntityDid, transactionHash } = await handlers.createDomain({
|
|
1361
|
-
entityType,
|
|
1362
|
-
linkedResource: [domainCardLinkedResource],
|
|
1363
|
-
linkedEntity: governanceGroupLinkedEntities.length > 0 ? governanceGroupLinkedEntities : void 0,
|
|
1364
|
-
startDate: validFrom,
|
|
1365
|
-
endDate
|
|
1366
|
-
});
|
|
1367
|
-
return {
|
|
1368
|
-
output: {
|
|
1369
|
-
entityDid: newEntityDid,
|
|
1370
|
-
transactionHash
|
|
1371
|
-
}
|
|
1372
|
-
};
|
|
1373
|
-
}
|
|
1374
|
-
});
|
|
1375
|
-
|
|
1376
|
-
// src/mantine/blocks/domainCreator/utils/transformSurveyToCredentialSubject.ts
|
|
1187
|
+
// src/core/lib/domainCard/transformSurveyToCredentialSubject.ts
|
|
1377
1188
|
function extractPanelDynamicItems(surveyData, panelName, itemMapper) {
|
|
1378
1189
|
const items = surveyData[panelName];
|
|
1379
1190
|
if (!Array.isArray(items)) return [];
|
|
@@ -1605,91 +1416,837 @@ function transformSurveyToCredentialSubject(surveyData, entityDid) {
|
|
|
1605
1416
|
return credentialSubject;
|
|
1606
1417
|
}
|
|
1607
1418
|
|
|
1608
|
-
// src/
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
}
|
|
1620
|
-
continue;
|
|
1621
|
-
}
|
|
1622
|
-
if (element.name && element.type !== "panel") {
|
|
1623
|
-
switch (element.type) {
|
|
1624
|
-
case "boolean":
|
|
1625
|
-
fields[element.name] = false;
|
|
1626
|
-
break;
|
|
1627
|
-
case "checkbox":
|
|
1628
|
-
fields[element.name] = [];
|
|
1629
|
-
break;
|
|
1630
|
-
case "file":
|
|
1631
|
-
fields[element.name] = [];
|
|
1632
|
-
break;
|
|
1633
|
-
default:
|
|
1634
|
-
fields[element.name] = "";
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
if (element.elements) {
|
|
1638
|
-
extractFieldsFromElements(element.elements, fields);
|
|
1639
|
-
}
|
|
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
|
|
1640
1430
|
}
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
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();
|
|
1448
|
+
}
|
|
1449
|
+
const parsed = new Date(dateInput);
|
|
1450
|
+
if (!isNaN(parsed.getTime())) {
|
|
1451
|
+
return parsed.toISOString();
|
|
1646
1452
|
}
|
|
1647
|
-
return
|
|
1453
|
+
return fallback.toISOString();
|
|
1648
1454
|
}
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
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
|
+
};
|
|
1493
|
+
}
|
|
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 [];
|
|
1502
|
+
}
|
|
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
1678
|
}
|
|
1679
|
-
|
|
1680
|
-
|
|
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
|
+
};
|
|
2193
|
+
|
|
2194
|
+
// src/core/lib/actionRegistry/actions/domainSign.ts
|
|
2195
|
+
registerAction({
|
|
2196
|
+
type: "qi/domain.sign",
|
|
2197
|
+
can: "domain/sign",
|
|
2198
|
+
sideEffect: true,
|
|
2199
|
+
defaultRequiresConfirmation: true,
|
|
2200
|
+
requiredCapability: "flow/block/execute",
|
|
2201
|
+
outputSchema: [
|
|
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" }
|
|
2204
|
+
],
|
|
2205
|
+
run: async (inputs, ctx) => {
|
|
2206
|
+
const handlers = ctx.handlers;
|
|
2207
|
+
if (!handlers) {
|
|
2208
|
+
throw new Error("Handlers not available");
|
|
2209
|
+
}
|
|
2210
|
+
if (!handlers.requestPin) throw new Error("requestPin handler not available");
|
|
2211
|
+
if (!handlers.signCredential) throw new Error("signCredential handler not implemented");
|
|
2212
|
+
if (!handlers.publicFileUpload) throw new Error("publicFileUpload handler not available");
|
|
2213
|
+
if (!handlers.createDomain) throw new Error("createDomain handler not implemented");
|
|
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");
|
|
1681
2220
|
}
|
|
2221
|
+
} else if (inputs.domainCardData && typeof inputs.domainCardData === "object") {
|
|
2222
|
+
domainCardData = inputs.domainCardData;
|
|
2223
|
+
} else {
|
|
2224
|
+
throw new Error("domainCardData is required");
|
|
1682
2225
|
}
|
|
2226
|
+
if (!domainCardData?.credentialSubject?.name) {
|
|
2227
|
+
throw new Error("domainCardData is missing or invalid (credentialSubject.name required)");
|
|
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");
|
|
1683
2231
|
const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
|
|
1684
2232
|
if (!issuerDid) throw new Error("Unable to determine issuer DID");
|
|
1685
|
-
const
|
|
1686
|
-
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
|
+
};
|
|
1687
2244
|
const unsignedCredential = buildVerifiableCredential({
|
|
1688
|
-
entityDid,
|
|
2245
|
+
entityDid: entityDidPlaceholder,
|
|
1689
2246
|
issuerDid,
|
|
1690
2247
|
credentialSubject,
|
|
1691
|
-
validFrom
|
|
1692
|
-
validUntil
|
|
2248
|
+
validFrom,
|
|
2249
|
+
validUntil
|
|
1693
2250
|
});
|
|
1694
2251
|
const pin = await handlers.requestPin({
|
|
1695
2252
|
title: "Sign Domain Card",
|
|
@@ -1710,24 +2267,160 @@ registerAction({
|
|
|
1710
2267
|
});
|
|
1711
2268
|
const uploadResult = await handlers.publicFileUpload(credentialFile);
|
|
1712
2269
|
const domainCardLinkedResource = buildDomainCardLinkedResource({
|
|
1713
|
-
entityDid,
|
|
2270
|
+
entityDid: entityDidPlaceholder,
|
|
1714
2271
|
cid: uploadResult.cid,
|
|
1715
2272
|
serviceEndpoint: uploadResult.url,
|
|
1716
|
-
description: `Domain Card for ${
|
|
2273
|
+
description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
|
|
1717
2274
|
});
|
|
1718
|
-
|
|
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;
|
|
1719
2288
|
const { entityDid: newEntityDid, transactionHash } = await handlers.createDomain({
|
|
1720
|
-
entityType
|
|
2289
|
+
entityType,
|
|
1721
2290
|
linkedResource: [domainCardLinkedResource],
|
|
1722
|
-
|
|
1723
|
-
|
|
2291
|
+
linkedEntity: governanceGroupLinkedEntities.length > 0 ? governanceGroupLinkedEntities : void 0,
|
|
2292
|
+
startDate: validFrom,
|
|
2293
|
+
endDate
|
|
1724
2294
|
});
|
|
1725
2295
|
return {
|
|
1726
2296
|
output: {
|
|
1727
2297
|
entityDid: newEntityDid,
|
|
1728
|
-
transactionHash
|
|
1729
|
-
|
|
1730
|
-
|
|
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()
|
|
1731
2424
|
}
|
|
1732
2425
|
};
|
|
1733
2426
|
}
|
|
@@ -3546,7 +4239,8 @@ var ICON_DEFAULTS = {
|
|
|
3546
4239
|
"matrix/dm": "message-circle",
|
|
3547
4240
|
"proposal/create": "scroll",
|
|
3548
4241
|
"proposal/vote": "vote",
|
|
3549
|
-
"domain/
|
|
4242
|
+
"domain/card-build": "file-text",
|
|
4243
|
+
"domain/card-preview": "id",
|
|
3550
4244
|
"domain/sign": "feather",
|
|
3551
4245
|
"credential/store": "shield",
|
|
3552
4246
|
"payment/execute": "credit-card",
|
|
@@ -4385,12 +5079,7 @@ export {
|
|
|
4385
5079
|
buildServicesFromHandlers,
|
|
4386
5080
|
getDiffResolver,
|
|
4387
5081
|
hasDiffResolver,
|
|
4388
|
-
|
|
4389
|
-
buildDomainCardLinkedResource,
|
|
4390
|
-
parseLinkedEntities,
|
|
4391
|
-
buildGovernanceGroupLinkedEntities,
|
|
4392
|
-
transformSurveyToCredentialSubject,
|
|
4393
|
-
extractSurveyAnswersTemplate,
|
|
5082
|
+
tempDomainCreatorSurvey,
|
|
4394
5083
|
getHomeserver,
|
|
4395
5084
|
didToMatrixUserId,
|
|
4396
5085
|
findOrCreateDMRoom,
|
|
@@ -4433,4 +5122,4 @@ export {
|
|
|
4433
5122
|
readFlow,
|
|
4434
5123
|
setupFlowFromBaseUcan
|
|
4435
5124
|
};
|
|
4436
|
-
//# sourceMappingURL=chunk-
|
|
5125
|
+
//# sourceMappingURL=chunk-4ETFMWQR.mjs.map
|