@ixo/editor 6.30.3 → 6.31.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.
@@ -14,7 +14,7 @@ import {
14
14
  swapBlocksInFragment,
15
15
  writeActionState,
16
16
  writeCompiledBlocksToFragment
17
- } from "./chunk-LY32OATI.js";
17
+ } from "./chunk-ZXNBOVAA.js";
18
18
 
19
19
  // src/core/lib/flowCompiler/authoring.ts
20
20
  import * as Y from "yjs";
@@ -370,4 +370,4 @@ export {
370
370
  setFlowParticipantPowerLevel,
371
371
  setFlowParticipantRequirements
372
372
  };
373
- //# sourceMappingURL=chunk-OAAEXL7Q.js.map
373
+ //# sourceMappingURL=chunk-S7CAGFE3.js.map
@@ -1013,6 +1013,10 @@ function buildServicesFromHandlers(handlers) {
1013
1013
  // results, so we only forward calls here.
1014
1014
  collectionUsers: handlers?.collectionUsers?.grant && handlers?.collectionUsers?.revoke && handlers?.collectionUsers?.list && handlers?.collectionUsers?.classifyAddress && handlers?.collectionUsers?.enumerateMembers ? {
1015
1015
  grant: async (params) => handlers.collectionUsers.grant(params),
1016
+ // Optional (IXO-4396): only hosts that can broadcast every grant in
1017
+ // one transaction expose it. Left undefined, the dispatcher falls
1018
+ // back to one `grant` per grantee.
1019
+ grantMany: handlers.collectionUsers.grantMany ? async (params) => handlers.collectionUsers.grantMany(params) : void 0,
1016
1020
  revoke: async (params) => handlers.collectionUsers.revoke(params),
1017
1021
  list: async (params) => handlers.collectionUsers.list(params),
1018
1022
  classifyAddress: async (params) => handlers.collectionUsers.classifyAddress(params),
@@ -8428,12 +8432,19 @@ registerAction({
8428
8432
 
8429
8433
  // src/core/lib/actionRegistry/actions/collectionUsers/index.ts
8430
8434
  var COLLECTION_USERS_ACTION_TYPE = "qi/collection.users";
8435
+ var COLLECTION_USERS_MAX_GRANTS_PER_TX = 40;
8436
+ function collectionUsersBatchCount(count) {
8437
+ if (!Number.isFinite(count) || count <= 0) return 0;
8438
+ return Math.ceil(count / COLLECTION_USERS_MAX_GRANTS_PER_TX);
8439
+ }
8431
8440
  var COLLECTION_USERS_OUTPUT_SCHEMA = [
8441
+ { path: "operation", displayName: "Operation", type: "string", description: "Which op produced this output: add, revoke or list" },
8432
8442
  { path: "transactionHash", displayName: "Tx Hash", type: "string", description: "Broadcast transaction hash (add/revoke)" },
8433
8443
  { path: "grantedCount", displayName: "Granted Count", type: "number", description: "Number of grants broadcast (fan-out)" },
8434
8444
  { path: "role", displayName: "Role", type: "string", description: "submit or evaluate" },
8435
8445
  { path: "collectionId", displayName: "Collection ID", type: "string", description: "Target claim collection identifier" },
8436
8446
  { path: "granteeAddress", displayName: "Grantee Address", type: "string", description: "Address granted/revoked" },
8447
+ { path: "granteeAddresses", displayName: "Grantee Addresses", type: "array", description: "Every address granted by a bulk/fan-out add" },
8437
8448
  {
8438
8449
  path: "grantees",
8439
8450
  displayName: "Grantees",
@@ -8454,6 +8465,37 @@ function normalizeRole(value) {
8454
8465
  if (normalized === "submit" || normalized === "evaluate") return normalized;
8455
8466
  throw new Error('role must be either "submit" or "evaluate"');
8456
8467
  }
8468
+ function resolveAddGrantees(inputs) {
8469
+ const kind = inputs.granteeKind || "user";
8470
+ let candidates;
8471
+ if (kind === "address-list") {
8472
+ candidates = Array.isArray(inputs.granteeAddresses) ? inputs.granteeAddresses.map((address) => String(address || "").trim()) : [];
8473
+ if (candidates.filter(Boolean).length === 0) {
8474
+ throw new Error("add (address-list): no accounts in the pasted list. Paste at least one valid ixo1\u2026 address.");
8475
+ }
8476
+ } else if (kind === "group-members") {
8477
+ candidates = Array.isArray(inputs.members) ? inputs.members.map((member) => String(member?.address || "").trim()) : [];
8478
+ if (candidates.filter(Boolean).length === 0) {
8479
+ throw new Error("add (group-members): no members resolved to grant to. Enumerate the group members before signing.");
8480
+ }
8481
+ } else {
8482
+ candidates = [String(inputs.granteeAddress || "").trim()];
8483
+ if (!candidates[0]) throw new Error("add: granteeAddress is required");
8484
+ }
8485
+ return Array.from(new Set(candidates.filter(Boolean)));
8486
+ }
8487
+ function batchFailurePrefix(completedBatches, totalBatches, granted, total) {
8488
+ if (totalBatches === 1) return `add: the grant of ${total} accounts was not broadcast.`;
8489
+ const remaining = total - granted;
8490
+ return `add: batch ${completedBatches + 1} of ${totalBatches} failed. ${granted} of ${total} accounts ARE granted and stay granted; re-run with the remaining ${remaining}.`;
8491
+ }
8492
+ function chunkGrantees(grantees, size = COLLECTION_USERS_MAX_GRANTS_PER_TX) {
8493
+ const batches = [];
8494
+ for (let i = 0; i < grantees.length; i += size) {
8495
+ batches.push(grantees.slice(i, i + size));
8496
+ }
8497
+ return batches;
8498
+ }
8457
8499
  registerAction({
8458
8500
  type: COLLECTION_USERS_ACTION_TYPE,
8459
8501
  can: "collection/users",
@@ -8492,11 +8534,12 @@ registerAction({
8492
8534
  deedDid: { type: "string", description: "Entity (deed) DID forwarded to the handler." },
8493
8535
  granteeAddress: { type: "string", description: "The single grantee bech32 address for add/revoke." },
8494
8536
  granteeDid: { type: "string", description: "Optional resolved grantee DID for display or audit." },
8495
- granteeKind: { type: "string", description: "How to treat the add grantee: user, group-account, or group-members." },
8537
+ granteeKind: { type: "string", description: "How to treat the add grantee: user, group-account, group-members, or address-list." },
8496
8538
  agentQuota: { type: "string", description: "Remaining agent quota for add; 0 means unlimited." },
8497
8539
  maxAmount: { type: "array", description: "Per-claim max amount cap for the add evaluate role." },
8498
8540
  intentDurationNs: { type: "string", description: "Intent duration in nanoseconds for add, carried as a string." },
8499
- members: { type: "array", description: "Resolved members to fan the grant out to when granteeKind is group-members." }
8541
+ members: { type: "array", description: "Resolved members to fan the grant out to when granteeKind is group-members." },
8542
+ granteeAddresses: { type: "array", description: "Accounts pasted in bulk to grant in one transaction when granteeKind is address-list." }
8500
8543
  }
8501
8544
  },
8502
8545
  // Only the decision inputs are human-askable: `operation` selects the
@@ -8523,12 +8566,12 @@ registerAction({
8523
8566
  if (operation === "list") {
8524
8567
  if (!collectionId) throw new Error("list: collectionId is required");
8525
8568
  if (!adminAddress) throw new Error("list: adminAddress (entity admin account) is required");
8526
- const result2 = await service.list({ granterAdminAddress: adminAddress, collectionId });
8527
- const grantees = Array.isArray(result2?.grantees) ? result2.grantees : void 0;
8528
- if (!grantees) {
8569
+ const result = await service.list({ granterAdminAddress: adminAddress, collectionId });
8570
+ const grantees2 = Array.isArray(result?.grantees) ? result.grantees : void 0;
8571
+ if (!grantees2) {
8529
8572
  throw new Error("list: service returned no grantees array. Check the [collection:list] handler logs.");
8530
8573
  }
8531
- return { output: { grantees, collectionId } };
8574
+ return { output: { operation: "list", grantees: grantees2, collectionId } };
8532
8575
  }
8533
8576
  if (!collectionId) throw new Error(`${operation}: collectionId is required`);
8534
8577
  if (!adminAddress) throw new Error(`${operation}: adminAddress (entity admin account) is required`);
@@ -8541,18 +8584,21 @@ registerAction({
8541
8584
  throw new Error("Acting as a POD is not available: the host does not implement prepareGroupCollectionUserChange");
8542
8585
  }
8543
8586
  if (!deedDid) throw new Error(`${operation}: deedDid is required when acting as a POD`);
8544
- const grantees = [];
8545
- if (operation === "add" && inputs.granteeKind === "group-members") {
8546
- const members = Array.isArray(inputs.members) ? inputs.members.filter((m) => !!String(m?.address || "").trim()) : [];
8547
- if (members.length === 0) throw new Error("add (group-members): no members resolved to grant to.");
8548
- grantees.push(...members.map((m) => String(m.address).trim()));
8587
+ let grantees2;
8588
+ if (operation === "add") {
8589
+ grantees2 = resolveAddGrantees(inputs);
8590
+ if (grantees2.length > COLLECTION_USERS_MAX_GRANTS_PER_TX) {
8591
+ throw new Error(
8592
+ `add: ${grantees2.length} grantees exceed the ${COLLECTION_USERS_MAX_GRANTS_PER_TX} per proposal limit when acting as a POD (the proposal executes as one transaction). Grant them in groups of ${COLLECTION_USERS_MAX_GRANTS_PER_TX} or fewer.`
8593
+ );
8594
+ }
8549
8595
  } else {
8550
- const granteeAddress2 = String(inputs.granteeAddress || "").trim();
8551
- if (!granteeAddress2) throw new Error(`${operation}: granteeAddress is required`);
8552
- grantees.push(granteeAddress2);
8596
+ const granteeAddress = String(inputs.granteeAddress || "").trim();
8597
+ if (!granteeAddress) throw new Error(`${operation}: granteeAddress is required`);
8598
+ grantees2 = [granteeAddress];
8553
8599
  }
8554
8600
  const msgs = [];
8555
- for (const granteeAddress2 of grantees) {
8601
+ for (const granteeAddress of grantees2) {
8556
8602
  const prepared = await groupHandlers.prepareGroupCollectionUserChange({
8557
8603
  groupAddress: coreAddress,
8558
8604
  operation,
@@ -8560,7 +8606,7 @@ registerAction({
8560
8606
  collectionId,
8561
8607
  adminAddress,
8562
8608
  role,
8563
- granteeAddress: granteeAddress2,
8609
+ granteeAddress,
8564
8610
  quota: inputs.agentQuota !== void 0 && inputs.agentQuota !== null ? Number(inputs.agentQuota) : void 0,
8565
8611
  maxAmount: Array.isArray(inputs.maxAmount) ? inputs.maxAmount : void 0
8566
8612
  });
@@ -8572,69 +8618,95 @@ registerAction({
8572
8618
  description,
8573
8619
  msgs,
8574
8620
  expectedOutput: {
8621
+ operation,
8575
8622
  transactionHash: "",
8576
8623
  transactionHashes: [],
8577
- grantedCount: operation === "add" ? grantees.length : 0,
8624
+ grantedCount: operation === "add" ? grantees2.length : 0,
8578
8625
  role,
8579
8626
  collectionId,
8580
- granteeAddress: grantees.length === 1 ? grantees[0] : void 0
8627
+ granteeAddress: grantees2.length === 1 ? grantees2[0] : void 0,
8628
+ granteeAddresses: operation === "add" ? grantees2 : void 0
8581
8629
  }
8582
8630
  });
8583
8631
  }
8584
8632
  if (operation === "revoke") {
8585
- const granteeAddress2 = String(inputs.granteeAddress || "").trim();
8586
- if (!granteeAddress2) throw new Error("revoke: granteeAddress is required");
8587
- const result2 = await service.revoke({ granterAdminAddress: adminAddress, granteeAddress: granteeAddress2, collectionId, role });
8588
- const transactionHash2 = String(result2?.transactionHash || "").trim();
8589
- if (!transactionHash2) {
8633
+ const granteeAddress = String(inputs.granteeAddress || "").trim();
8634
+ if (!granteeAddress) throw new Error("revoke: granteeAddress is required");
8635
+ const result = await service.revoke({ granterAdminAddress: adminAddress, granteeAddress, collectionId, role });
8636
+ const transactionHash = String(result?.transactionHash || "").trim();
8637
+ if (!transactionHash) {
8590
8638
  throw new Error("revoke: service returned no transactionHash. The revoke was not broadcast.");
8591
8639
  }
8592
- return { output: { transactionHash: transactionHash2, role, collectionId, granteeAddress: granteeAddress2 } };
8640
+ return { output: { operation: "revoke", transactionHash, role, collectionId, granteeAddress } };
8593
8641
  }
8594
- const granteeKind = inputs.granteeKind || "user";
8595
8642
  const agentQuota = inputs.agentQuota !== void 0 && inputs.agentQuota !== null ? String(inputs.agentQuota).trim() || void 0 : void 0;
8596
8643
  const maxAmount = Array.isArray(inputs.maxAmount) ? inputs.maxAmount : void 0;
8597
8644
  const intentDurationNs = String(inputs.intentDurationNs || "").trim() || void 0;
8598
- if (granteeKind === "group-members") {
8599
- const members = Array.isArray(inputs.members) ? inputs.members.filter((m) => !!String(m?.address || "").trim()) : [];
8600
- if (members.length === 0) {
8601
- throw new Error("add (group-members): no members resolved to grant to. Enumerate the group members before signing.");
8602
- }
8603
- const transactionHashes = [];
8604
- for (const member of members) {
8605
- const granteeAddress2 = String(member.address).trim();
8606
- const res = await service.grant({ granterAdminAddress: adminAddress, granteeAddress: granteeAddress2, collectionId, role, agentQuota, maxAmount, intentDurationNs, deedDid });
8607
- const hash = String(res?.transactionHash || "").trim();
8645
+ const grantees = resolveAddGrantees(inputs);
8646
+ const grantConfig = { granterAdminAddress: adminAddress, collectionId, role, agentQuota, maxAmount, intentDurationNs, deedDid };
8647
+ if (grantees.length > 1 && typeof service.grantMany === "function") {
8648
+ const batches = chunkGrantees(grantees);
8649
+ const transactionHashes2 = [];
8650
+ let granted = 0;
8651
+ for (const batch of batches) {
8652
+ let result;
8653
+ try {
8654
+ result = await service.grantMany({ ...grantConfig, granteeAddresses: batch });
8655
+ } catch (error) {
8656
+ throw new Error(`${batchFailurePrefix(transactionHashes2.length, batches.length, granted, grantees.length)} ${error instanceof Error ? error.message : String(error)}`);
8657
+ }
8658
+ const hash = String(result?.transactionHash || "").trim();
8608
8659
  if (!hash) {
8609
- throw new Error(`add (group-members): grant to ${granteeAddress2} returned no transactionHash. ${transactionHashes.length} of ${members.length} grants completed.`);
8660
+ throw new Error(`${batchFailurePrefix(transactionHashes2.length, batches.length, granted, grantees.length)} The service returned no transactionHash.`);
8610
8661
  }
8611
- transactionHashes.push(hash);
8662
+ transactionHashes2.push(hash);
8663
+ granted += batch.length;
8612
8664
  }
8613
8665
  return {
8614
8666
  output: {
8615
- transactionHash: transactionHashes[transactionHashes.length - 1],
8616
- transactionHashes,
8617
- grantedCount: transactionHashes.length,
8667
+ operation: "add",
8668
+ transactionHash: transactionHashes2[transactionHashes2.length - 1],
8669
+ transactionHashes: transactionHashes2,
8670
+ grantedCount: grantees.length,
8618
8671
  role,
8619
- collectionId
8672
+ collectionId,
8673
+ granteeAddresses: grantees,
8674
+ batched: true,
8675
+ batchCount: batches.length
8620
8676
  }
8621
8677
  };
8622
8678
  }
8623
- const granteeAddress = String(inputs.granteeAddress || "").trim();
8624
- if (!granteeAddress) throw new Error("add: granteeAddress is required");
8625
- const result = await service.grant({ granterAdminAddress: adminAddress, granteeAddress, collectionId, role, agentQuota, maxAmount, intentDurationNs, deedDid });
8626
- const transactionHash = String(result?.transactionHash || "").trim();
8627
- if (!transactionHash) {
8628
- throw new Error("add: service returned no transactionHash. The grant was not broadcast.");
8679
+ const transactionHashes = [];
8680
+ for (const granteeAddress of grantees) {
8681
+ let result;
8682
+ try {
8683
+ result = await service.grant({ ...grantConfig, granteeAddress });
8684
+ } catch (error) {
8685
+ const cause = error instanceof Error ? error.message : String(error);
8686
+ if (grantees.length === 1) throw error instanceof Error ? error : new Error(cause);
8687
+ throw new Error(
8688
+ `add: the grant to ${granteeAddress} failed. ${transactionHashes.length} of ${grantees.length} accounts ARE granted and stay granted; re-run with the rest. ${cause}`
8689
+ );
8690
+ }
8691
+ const hash = String(result?.transactionHash || "").trim();
8692
+ if (!hash) {
8693
+ throw new Error(
8694
+ grantees.length === 1 ? "add: service returned no transactionHash. The grant was not broadcast." : `add: the grant to ${granteeAddress} returned no transactionHash. ${transactionHashes.length} of ${grantees.length} accounts ARE granted and stay granted; re-run with the rest.`
8695
+ );
8696
+ }
8697
+ transactionHashes.push(hash);
8629
8698
  }
8630
8699
  return {
8631
8700
  output: {
8632
- transactionHash,
8633
- transactionHashes: [transactionHash],
8634
- grantedCount: 1,
8701
+ operation: "add",
8702
+ transactionHash: transactionHashes[transactionHashes.length - 1],
8703
+ transactionHashes,
8704
+ grantedCount: transactionHashes.length,
8635
8705
  role,
8636
8706
  collectionId,
8637
- granteeAddress
8707
+ granteeAddress: grantees.length === 1 ? grantees[0] : void 0,
8708
+ granteeAddresses: grantees,
8709
+ batched: false
8638
8710
  }
8639
8711
  };
8640
8712
  }
@@ -13023,6 +13095,7 @@ function roleLabel(value) {
13023
13095
  var IXO_DENOM = "uixo";
13024
13096
  var USDC_DENOM2 = "ibc/6BBE9BD4246F8E04948D5A4EEE7164B2630263B9EBB5E7DC5F0A46C62A2FF97B";
13025
13097
  var DENOM_DECIMALS = 6;
13098
+ var MAX_LISTED_ADDRESSES = 5;
13026
13099
  function formatCoin4(value) {
13027
13100
  const coin = value;
13028
13101
  const denomValue = String(coin?.denom || "");
@@ -13039,16 +13112,34 @@ function diffAdd(inputs) {
13039
13112
  if (inputs.collectionId) {
13040
13113
  results.push({ key: "collectionId", label: "Collection", before: null, after: String(inputs.collectionId), changeType: "add" });
13041
13114
  }
13042
- if (kind === "group-members") {
13043
- const count = Array.isArray(inputs.members) ? inputs.members.filter((m) => !!String(m?.address || "").trim()).length : 0;
13115
+ if (kind === "address-list" || kind === "group-members") {
13116
+ const addresses = kind === "address-list" ? (Array.isArray(inputs.granteeAddresses) ? inputs.granteeAddresses : []).map((a) => String(a || "").trim()).filter(Boolean) : (Array.isArray(inputs.members) ? inputs.members : []).map((m) => String(m?.address || "").trim()).filter(Boolean);
13044
13117
  results.push({
13045
13118
  key: "grantees",
13046
- label: "Grantees (fan-out)",
13119
+ label: kind === "address-list" ? "Grantees (pasted list)" : "Grantees (fan-out)",
13047
13120
  before: null,
13048
- after: `${count} group member${count === 1 ? "" : "s"}`,
13121
+ after: kind === "address-list" ? `${addresses.length} account${addresses.length === 1 ? "" : "s"}` : `${addresses.length} group member${addresses.length === 1 ? "" : "s"}`,
13049
13122
  changeType: "add",
13050
13123
  severity: "warning"
13051
13124
  });
13125
+ if (addresses.length > 0) {
13126
+ results.push({
13127
+ key: "granteeAddresses",
13128
+ label: "Accounts",
13129
+ before: null,
13130
+ after: addresses.length > MAX_LISTED_ADDRESSES ? `${addresses.slice(0, MAX_LISTED_ADDRESSES).join(", ")} \u2026 +${addresses.length - MAX_LISTED_ADDRESSES} more` : addresses.join(", "),
13131
+ changeType: "add"
13132
+ });
13133
+ const batches = collectionUsersBatchCount(addresses.length);
13134
+ results.push({
13135
+ key: "transactions",
13136
+ label: "Transactions to sign",
13137
+ before: null,
13138
+ after: `${batches} (up to ${COLLECTION_USERS_MAX_GRANTS_PER_TX} grants each)`,
13139
+ changeType: "add",
13140
+ severity: batches > 1 ? "warning" : void 0
13141
+ });
13142
+ }
13052
13143
  } else {
13053
13144
  const label = kind === "group-account" ? "Grantee (group account)" : "Grantee";
13054
13145
  results.push({ key: "grantee", label, before: null, after: String(inputs.granteeAddress || "\u2014"), changeType: "add" });
@@ -20262,6 +20353,8 @@ export {
20262
20353
  buildGovernanceGroupLinkedEntities,
20263
20354
  tempDomainCreatorSurvey,
20264
20355
  resolveEntityTypeFromSchema,
20356
+ COLLECTION_USERS_MAX_GRANTS_PER_TX,
20357
+ collectionUsersBatchCount,
20265
20358
  REPEAT_SUBMISSIONS_OPTIONS,
20266
20359
  DIFFERENT_WHEN_OPTIONS,
20267
20360
  WHAT_IS_COLLECTED_MAX,
@@ -20509,4 +20602,4 @@ export {
20509
20602
  executeQueuedFlowAgentCoreCommands,
20510
20603
  FlowAgentService
20511
20604
  };
20512
- //# sourceMappingURL=chunk-LY32OATI.js.map
20605
+ //# sourceMappingURL=chunk-ZXNBOVAA.js.map