@capxul/sdk-react 4.20.0-beta.35 → 4.20.0-beta.36

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/index.d.mts CHANGED
@@ -360,7 +360,7 @@ type SentPayment = {
360
360
  * Refusal CODES, never sentences (#1447 ruling 8). The app maps each code to
361
361
  * the words it already prints; no English refusal string ships from here.
362
362
  */
363
- type CapxulSendMoneyBlockedReason = "signer-not-ready" | "amount-invalid" | "recipient-unresolved" | "no-source" | "no-asset" | "asset-unnamed";
363
+ type CapxulSendMoneyBlockedReason = "signer-not-ready" | "amount-invalid" | "recipient-unresolved" | "no-source" | "no-asset";
364
364
  /**
365
365
  * One Budget the member can spend from — the id the payment carries, and
366
366
  * nothing else.
@@ -999,7 +999,7 @@ interface PayrollRecipientOption {
999
999
  * false fact in the fixed order below, so the same composer state always
1000
1000
  * yields the same code.
1001
1001
  */
1002
- type CapxulPayrollRunBlockedReason = "signer-not-ready" | "no-source" | "ambiguous-source" | "no-asset" | "no-recipients" | "amount-invalid" | "insufficient-funds" | "asset-unnamed";
1002
+ type CapxulPayrollRunBlockedReason = "signer-not-ready" | "no-source" | "ambiguous-source" | "no-asset" | "no-recipients" | "amount-invalid" | "insufficient-funds";
1003
1003
  interface PayrollRunGroupOption {
1004
1004
  readonly id: PayrollGroupId;
1005
1005
  readonly label: string;
package/dist/index.mjs CHANGED
@@ -1418,26 +1418,6 @@ function useCapxulOrganizationPayBatch(orgId) {
1418
1418
  });
1419
1419
  }
1420
1420
  //#endregion
1421
- //#region src/payments/write-names-asset.ts
1422
- /**
1423
- * Identity law: "A payment names an asset or inherits it from an authorized
1424
- * fact. Missing asset refuses." The rule was recorded in the retired
1425
- * treasury-cut handoff (removed from the current tree by the exact-asset
1426
- * contraction; its record survives in Git history).
1427
- *
1428
- * A Capxul payment writer takes `PaymentMoney` — a peg currency, a value and
1429
- * `decimals` — and settles one fixed legacy token. No `AssetId` crosses that
1430
- * seam, so a payment composed from a named position cannot name the asset it
1431
- * moves: a position selected as USDT authorizes a different token.
1432
- *
1433
- * `false` until the writer takes the command's asset. The Send and Payroll
1434
- * composers read this to refuse a submission rather than authorize a token the
1435
- * person did not pick.
1436
- */
1437
- function writeNamesAsset() {
1438
- return false;
1439
- }
1440
- //#endregion
1441
1421
  //#region src/platform/signer-status.ts
1442
1422
  const NO_SUBSCRIPTION = () => () => {};
1443
1423
  function useSignerStatus(client) {
@@ -1592,9 +1572,6 @@ function useSendMoney(input) {
1592
1572
  const client = useCapxulClientOrNull();
1593
1573
  const signerStatus = useSignerStatus(client);
1594
1574
  const orgId = actor.kind === "organization" ? actor.orgId : void 0;
1595
- const meReading = useOrgMeReading(orgId);
1596
- const sourceOptions = useMemo(() => meReading.kind === "ready" ? meReading.me.budgets.map((budget) => ({ id: budget.id })) : [], [meReading]);
1597
- const [selectedSource, selectSource] = useSelectedOption(sourceOptions);
1598
1575
  const balance = useCapxulAccountBalance({ enabled: actor.kind === "personal" });
1599
1576
  const treasury = useCapxulOrgTreasury(orgId, { enabled: actor.kind === "organization" });
1600
1577
  const accountQuery = actor.kind === "personal" ? balance : treasury;
@@ -1603,6 +1580,9 @@ function useSendMoney(input) {
1603
1580
  const assetOptions = useMemo(() => assetSelections.map((selection) => selection.option), [assetSelections]);
1604
1581
  const [selectedAssetOption, selectAsset] = useSelectedOption(assetOptions);
1605
1582
  const selectedAssetMoney = useMemo(() => assetSelections.find((selection) => selection.option.id === selectedAssetOption?.id)?.money ?? null, [assetSelections, selectedAssetOption]);
1583
+ const meReading = useOrgMeReading(orgId);
1584
+ const sourceOptions = useMemo(() => meReading.kind === "ready" ? meReading.me.budgets.filter((budget) => selectedAssetOption === null || budget.asset.assetId === selectedAssetOption.id).map((budget) => ({ id: budget.id })) : [], [meReading, selectedAssetOption]);
1585
+ const [selectedSource, selectSource] = useSelectedOption(sourceOptions);
1606
1586
  const [amountText, setAmountText] = useState("");
1607
1587
  const parsed = useMemo(() => selectedAssetMoney === null || amountText.trim() === "" ? null : parseAssetAmount(amountText, requireAsset(selectedAssetMoney.asset)), [amountText, selectedAssetMoney]);
1608
1588
  const parsedMoney = parsed !== null && !isMoneyParseError(parsed) ? parsed : null;
@@ -1616,7 +1596,7 @@ function useSendMoney(input) {
1616
1596
  const personalPay = useCapxulPay();
1617
1597
  const organizationPay = useCapxulOrganizationPay(orgId);
1618
1598
  const pay = actor.kind === "personal" ? personalPay : organizationPay;
1619
- const blockedReason = signerStatus !== "ready" ? "signer-not-ready" : actor.kind === "organization" && selectedSource === null ? "no-source" : selectedAssetOption === null ? "no-asset" : parsedMoney === null ? "amount-invalid" : resolvedReference === null ? "recipient-unresolved" : writeNamesAsset() ? null : "asset-unnamed";
1599
+ const blockedReason = signerStatus !== "ready" ? "signer-not-ready" : actor.kind === "organization" && selectedSource === null ? "no-source" : selectedAssetOption === null ? "no-asset" : parsedMoney === null ? "amount-invalid" : resolvedReference === null ? "recipient-unresolved" : null;
1620
1600
  const submitGate = useRef(false);
1621
1601
  const submit = useCallback(() => {
1622
1602
  if (blockedReason !== null || submitGate.current) return;
@@ -3362,8 +3342,8 @@ function freshRunDraft(input) {
3362
3342
  }
3363
3343
  };
3364
3344
  }
3365
- function hasRequiredCompensation(frozen, writerNamesSelectedAsset, selected, terms) {
3366
- return frozen || !writerNamesSelectedAsset || selected.every((recipientId) => terms.has(recipientId));
3345
+ function hasRequiredCompensation(frozen, selected, terms) {
3346
+ return frozen || selected.every((recipientId) => terms.has(recipientId));
3367
3347
  }
3368
3348
  /**
3369
3349
  * WHICH run the composer is composing, by MEANING rather than by object shape.
@@ -3406,10 +3386,14 @@ function remainingBalanceDisplay(available, total, asset) {
3406
3386
  }));
3407
3387
  return remaining < 0n ? `-${formatted}` : formatted;
3408
3388
  }
3409
- /** Persisted replay keeps its authorized Budget and asset; a prior debit cannot block its own recovery. */
3389
+ /**
3390
+ * Persisted replay keeps its authorized Budget and asset; a prior debit cannot
3391
+ * block its own recovery. A restored run names its Budget, so it counts only
3392
+ * whether that Budget is still offered, never how many others are.
3393
+ */
3410
3394
  function runAuthorityFacts(draft, budgets, asset, money, funds) {
3411
3395
  return {
3412
- budgetCount: draft !== null && !budgets.some((budget) => budget.id === draft.input.permissionId) ? 0 : budgets.length,
3396
+ budgetCount: draft === null ? budgets.length : budgets.filter((budget) => budget.id === draft.input.permissionId).length,
3413
3397
  hasAsset: asset !== null && (draft === null || draft.asset.id === asset.id && draft.input.asset === money?.asset),
3414
3398
  funds: draft?.input.requestKey === void 0 ? funds : "available"
3415
3399
  };
@@ -3426,8 +3410,7 @@ function firstFalseFact(facts) {
3426
3410
  if (!facts.hasAsset) return "no-asset";
3427
3411
  if (facts.recipientCount === 0) return "no-recipients";
3428
3412
  if (!facts.amountsParse) return "amount-invalid";
3429
- if (facts.funds === "insufficient") return "insufficient-funds";
3430
- return facts.writeNamesAsset ? null : "asset-unnamed";
3413
+ return facts.funds === "insufficient" ? "insufficient-funds" : null;
3431
3414
  }
3432
3415
  //#endregion
3433
3416
  //#region src/payroll/use-run-amounts.ts
@@ -3510,14 +3493,15 @@ function useRunAmounts(input) {
3510
3493
  * share one account id, and a symbol is display only (ADR-0028 R3). The run
3511
3494
  * writer receives the selected asset explicitly.
3512
3495
  */
3513
- function useRunAsset(account, canSelect) {
3496
+ function useRunAsset(account, canSelect, restoredAssetId) {
3514
3497
  const assetSelections = useMemo(() => assetSelectionsFromAccount(account), [account]);
3515
3498
  const assetOptions = useMemo(() => assetSelections.map((selection) => selection.option), [assetSelections]);
3516
3499
  const [selectedAssetId, setSelectedAssetId] = useState(null);
3517
3500
  useEffect(() => {
3518
3501
  if (!assetOptions.some((option) => option.id === selectedAssetId)) setSelectedAssetId(assetOptions[0]?.id ?? null);
3519
3502
  }, [assetOptions, selectedAssetId]);
3520
- const selectedAsset = assetOptions.find((option) => option.id === selectedAssetId) ?? null;
3503
+ const effectiveAssetId = restoredAssetId ?? selectedAssetId;
3504
+ const selectedAsset = assetOptions.find((option) => option.id === effectiveAssetId) ?? null;
3521
3505
  return {
3522
3506
  assetOptions,
3523
3507
  selectedAsset,
@@ -3609,7 +3593,7 @@ function usePayrollRun(input) {
3609
3593
  draftError
3610
3594
  ]);
3611
3595
  const canSelectAsset = useCallback(() => !submitGate.current && !frozen, [frozen]);
3612
- const { assetOptions, selectedAsset, selectAsset, assetMoney } = useRunAsset(treasury.data ?? null, canSelectAsset);
3596
+ const { assetOptions, selectedAsset, selectAsset, assetMoney } = useRunAsset(treasury.data ?? null, canSelectAsset, draft?.input.asset ?? null);
3613
3597
  const { named, payableRefs, compensationTerms } = useRunRecipients({
3614
3598
  options: roster.options,
3615
3599
  refs: roster.refs,
@@ -3624,14 +3608,12 @@ function usePayrollRun(input) {
3624
3608
  names: named,
3625
3609
  change
3626
3610
  });
3627
- const budgets = me.data?.budgets ?? [];
3628
- const writerNamesSelectedAsset = writeNamesAsset();
3611
+ const budgets = (me.data?.budgets ?? []).filter((budget) => selectedAsset === null || budget.asset.assetId === selectedAsset.id);
3629
3612
  const blockedReason = firstFalseFact({
3630
3613
  signerReady: signerStatus === "ready",
3631
3614
  ...runAuthorityFacts(draft, budgets, selectedAsset, assetMoney, funds),
3632
3615
  recipientCount: payableRefs === null ? 0 : selected.length,
3633
- amountsParse: total !== null && hasRequiredCompensation(frozen, writerNamesSelectedAsset, selected, compensationTerms),
3634
- writeNamesAsset: writerNamesSelectedAsset
3616
+ amountsParse: total !== null && hasRequiredCompensation(frozen, selected, compensationTerms)
3635
3617
  });
3636
3618
  const authorize = useAuthorizeRun({
3637
3619
  client,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capxul/sdk-react",
3
- "version": "4.20.0-beta.35",
3
+ "version": "4.20.0-beta.36",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Xelmar-tech/infrastructure.git",
@@ -56,7 +56,7 @@
56
56
  "access": "public"
57
57
  },
58
58
  "dependencies": {
59
- "@capxul/sdk": "4.20.0-beta.35"
59
+ "@capxul/sdk": "4.20.0-beta.36"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@tanstack/react-query": "^5.66.9",
@@ -75,7 +75,7 @@
75
75
  "vite": "npm:@voidzero-dev/vite-plus-core@1.0.0",
76
76
  "vite-plus": "1.0.0",
77
77
  "vitest": "5.0.1",
78
- "@capxul/protocol": "0.2.0-beta.6",
78
+ "@capxul/protocol": "0.2.0-beta.7",
79
79
  "@capxul/typescript-config": "0.0.0"
80
80
  },
81
81
  "peerDependencies": {