@ixo/editor 6.14.0 → 6.15.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.
@@ -649,7 +649,8 @@ function generateActionManifest() {
649
649
  proof: serializeProof(action),
650
650
  hasDynamicEvents: !!action.getDynamicEvents,
651
651
  hasDynamicOutputSchema: !!action.getDynamicOutputSchema,
652
- eligibleForEventTrigger: !!action.eligibleForEventTrigger
652
+ eligibleForEventTrigger: !!action.eligibleForEventTrigger,
653
+ hasCustomInputValidation: !!action.getMissingInputs
653
654
  };
654
655
  if (action.can) entry.can = action.can;
655
656
  if (action.requiredCapability) entry.requiredCapability = action.requiredCapability;
@@ -668,6 +669,49 @@ function generateActionManifest() {
668
669
  return { manifestVersion: "1", actions: actions2 };
669
670
  }
670
671
 
672
+ // src/core/lib/actionRegistry/inputRequirements.ts
673
+ function isBlankInputValue(value) {
674
+ if (value == null) return true;
675
+ if (typeof value === "string") return value.trim().length === 0;
676
+ if (Array.isArray(value)) return value.length === 0;
677
+ return false;
678
+ }
679
+ function parseMaybeJsonObject(value) {
680
+ if (value && typeof value === "object" && !Array.isArray(value)) return value;
681
+ if (typeof value === "string" && value.trim()) {
682
+ try {
683
+ const parsed = JSON.parse(value);
684
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) return parsed;
685
+ } catch {
686
+ return void 0;
687
+ }
688
+ }
689
+ return void 0;
690
+ }
691
+ function dedupe(values) {
692
+ return Array.from(new Set(values.filter((value) => typeof value === "string" && value.length > 0)));
693
+ }
694
+ function getMissingActionInputs(actionType, inputs) {
695
+ if (!actionType) return [];
696
+ const action = getAction(actionType);
697
+ if (!action) return [];
698
+ const merged = inputs ?? {};
699
+ if (action.getMissingInputs) {
700
+ try {
701
+ return dedupe(action.getMissingInputs(merged) || []);
702
+ } catch (error) {
703
+ warnOnce(
704
+ `missing-inputs:${action.type}`,
705
+ `[flow-config] action ${action.type}: getMissingInputs threw (${error instanceof Error ? error.message : String(error)}); reporting no missing inputs`
706
+ );
707
+ return [];
708
+ }
709
+ }
710
+ const schema = action.inputSchema;
711
+ const required = Array.isArray(schema?.required) ? schema.required.filter((name) => typeof name === "string") : [];
712
+ return dedupe(required.filter((name) => isBlankInputValue(merged[name])));
713
+ }
714
+
671
715
  // src/core/lib/actionRegistry/canMapping.ts
672
716
  var CAN_TO_TYPE = {
673
717
  "bid/submit": "qi/bid.submit",
@@ -1114,6 +1158,9 @@ registerAction({
1114
1158
  { path: "purposeDescription", displayName: "Purpose Description", type: "string", description: "The user-provided purpose text" },
1115
1159
  { path: "blueprintCandidates", displayName: "Blueprint Candidates", type: "array", description: "Ranked array of matching blueprint DIDs and metadata" }
1116
1160
  ],
1161
+ // Mirrors run(): either userMessage or purposeDescription satisfies the
1162
+ // purpose-text requirement, reported under the primary name.
1163
+ getMissingInputs: (inputs) => String(inputs.userMessage || inputs.purposeDescription || "").trim() ? [] : ["userMessage"],
1117
1164
  run: async (inputs) => {
1118
1165
  const purposeDescription = String(inputs.userMessage || inputs.purposeDescription || "").trim();
1119
1166
  if (!purposeDescription) throw new Error("userMessage is required");
@@ -1227,6 +1274,8 @@ registerAction({
1227
1274
  pendingDisplayFields: ["selectedEntityName", "selectedEntityDid"]
1228
1275
  }
1229
1276
  ],
1277
+ // Mirrors run(): a truthy `skipped` waives the selection entirely.
1278
+ getMissingInputs: (inputs) => inputs.skipped ? [] : isBlankInputValue(inputs.selectedEntityDid) ? ["selectedEntityDid"] : [],
1230
1279
  run: async (inputs) => {
1231
1280
  const skipped = !!inputs.skipped;
1232
1281
  if (skipped) {
@@ -1289,6 +1338,30 @@ registerAction({
1289
1338
  pendingDisplayFields: ["memberConfig.memberCount"]
1290
1339
  }
1291
1340
  ],
1341
+ // Mirrors run(), including its default: an absent groupType is treated as
1342
+ // 'categorical', not as a missing input.
1343
+ getMissingInputs: (inputs) => {
1344
+ const groupType = String(inputs.groupType || "").trim() || "categorical";
1345
+ if (groupType === "nftStaking") {
1346
+ return String(inputs.nftContractAddress || "").trim() ? [] : ["nftContractAddress"];
1347
+ }
1348
+ if (groupType === "tokenStaking") {
1349
+ const tokenConfig = inputs.tokenConfig;
1350
+ if (!tokenConfig || typeof tokenConfig !== "object") return ["tokenConfig"];
1351
+ if (tokenConfig.isExistingToken) {
1352
+ return String(tokenConfig.tokenAddress || "").trim() ? [] : ["tokenConfig.tokenAddress"];
1353
+ }
1354
+ const missing2 = [];
1355
+ if (!String(tokenConfig.tokenName || "").trim()) missing2.push("tokenConfig.tokenName");
1356
+ if (!String(tokenConfig.tokenSymbol || "").trim()) missing2.push("tokenConfig.tokenSymbol");
1357
+ if (isBlankInputValue(tokenConfig.tokenSupply)) missing2.push("tokenConfig.tokenSupply");
1358
+ return missing2;
1359
+ }
1360
+ const missing = [];
1361
+ if (!Array.isArray(inputs.members) || inputs.members.length === 0) missing.push("members");
1362
+ if (groupType === "multisig" && isBlankInputValue(inputs.multisigThreshold)) missing.push("multisigThreshold");
1363
+ return missing;
1364
+ },
1292
1365
  run: async (inputs) => {
1293
1366
  const groupType = inputs.groupType || "categorical";
1294
1367
  if (groupType === "nftStaking") {
@@ -1377,6 +1450,29 @@ registerAction({
1377
1450
  pendingDisplayFields: ["governanceConfig.groupName", "governanceConfig.groupType"]
1378
1451
  }
1379
1452
  ],
1453
+ // Mirrors run()'s presence preamble: base fields always, then the decision
1454
+ // policy fields the selected groupType demands. Value validity (quorum and
1455
+ // threshold ranges, veto sum) stays in run().
1456
+ getMissingInputs: (inputs) => {
1457
+ const missing = [];
1458
+ if (!String(inputs.groupName || "").trim()) missing.push("groupName");
1459
+ const groupType = String(inputs.groupType || "").trim();
1460
+ if (!groupType) missing.push("groupType");
1461
+ const governance = inputs.governance;
1462
+ if (!governance || typeof governance !== "object") {
1463
+ missing.push("governance", "governance.votingPeriod");
1464
+ return missing;
1465
+ }
1466
+ if (!governance.votingPeriod) missing.push("governance.votingPeriod");
1467
+ if (!groupType) return missing;
1468
+ if (groupType === "multisig") {
1469
+ if (!String(governance.threshold ?? "").trim()) missing.push("governance.threshold");
1470
+ } else {
1471
+ if (governance.quorum == null || String(governance.quorum).trim() === "") missing.push("governance.quorum");
1472
+ if (governance.threshold == null || String(governance.threshold).trim() === "") missing.push("governance.threshold");
1473
+ }
1474
+ return missing;
1475
+ },
1380
1476
  run: async (inputs) => {
1381
1477
  const groupName = String(inputs.groupName || "").trim();
1382
1478
  if (!groupName) throw new Error("groupName is required");
@@ -5561,6 +5657,14 @@ registerAction({
5561
5657
  pendingDisplayFields: ["entityDid", "governanceGroupCoreAddress"]
5562
5658
  }
5563
5659
  ],
5660
+ // Mirrors run(): the card envelope (object or JSON string) must carry
5661
+ // credentialSubject.name before signing can start.
5662
+ getMissingInputs: (inputs) => {
5663
+ const card = parseMaybeJsonObject(inputs.domainCardData);
5664
+ if (!card) return ["domainCardData"];
5665
+ const subject = card.credentialSubject;
5666
+ return subject && String(subject.name || "").trim() ? [] : ["domainCardData.credentialSubject.name"];
5667
+ },
5564
5668
  run: async (inputs, ctx) => {
5565
5669
  const handlers = ctx.handlers || {};
5566
5670
  let domainCardData;
@@ -5914,6 +6018,14 @@ registerAction({
5914
6018
  pendingDisplayFields: ["approvedAt"]
5915
6019
  }
5916
6020
  ],
6021
+ // Mirrors run(): the card envelope (object or JSON string) must carry
6022
+ // credentialSubject.name before a preview can render.
6023
+ getMissingInputs: (inputs) => {
6024
+ const card = parseMaybeJsonObject(inputs.domainCardData);
6025
+ if (!card) return ["domainCardData"];
6026
+ const subject = card.credentialSubject;
6027
+ return subject && String(subject.name || "").trim() ? [] : ["domainCardData.credentialSubject.name"];
6028
+ },
5917
6029
  run: async (inputs) => {
5918
6030
  let domainCardData = inputs.domainCardData;
5919
6031
  if (typeof domainCardData === "string") {
@@ -14882,6 +14994,8 @@ export {
14882
14994
  getEventsForBlock,
14883
14995
  getOutputSchemaForBlock,
14884
14996
  generateActionManifest,
14997
+ isBlankInputValue,
14998
+ getMissingActionInputs,
14885
14999
  canToType,
14886
15000
  typeToCan,
14887
15001
  getAllCanMappings,
@@ -15036,4 +15150,4 @@ export {
15036
15150
  executeQueuedFlowAgentCoreCommands,
15037
15151
  FlowAgentService
15038
15152
  };
15039
- //# sourceMappingURL=chunk-LMHIE6UG.js.map
15153
+ //# sourceMappingURL=chunk-WSRVRHND.js.map