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

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
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { _ as orgKeySegment, a as entered, c as useCapxulIdentity, d as useCapxulTransitions, f as toInvocationControls, g as capxulKeys, h as actingAccount, i as CapxulProvider, l as useCapxulIdentityOrNull, m as accountKey, n as CapxulAuthenticationController, o as useCapxulAuth, p as toInvocationOptions, r as absurd, s as useCapxulDestination, t as CapxulOnboardingController, u as useCapxulSend, v as useCapxulClientOrNull, y as useCapxul } from "./onboarding-controller-DWuvVuC8.mjs";
2
+ import { _ as orgKeySegment, a as entered, c as useCapxulIdentity, d as useCapxulTransitions, f as toInvocationControls, g as capxulKeys, h as actingAccount, i as CapxulProvider, l as useCapxulIdentityOrNull, m as accountKey, n as CapxulAuthenticationController, o as useCapxulAuth, p as toInvocationOptions, r as absurd, s as useCapxulDestination, t as CapxulOnboardingController, u as useCapxulSend, v as useCapxulClientOrNull, y as useCapxul } from "./onboarding-controller-BCrkmLxQ.mjs";
3
3
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
4
4
  import { useInfiniteQuery, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5
5
  import { CAPXUL_OPERATIONS, CapxulError, EVM_ADDRESS_RE, Errors, HANDLE_RE, PAYMENT_DIRECTIONS, PAYMENT_STATUSES, assetSymbolFor, fingerprintPaymentIntent, formatAssetAmount, formatMoney, isCapxulError, isClaimed, isClaimed as isClaimed$1, isMoneyParseError, isRestoring, isRestoring as isRestoring$1, parseAssetAmount, parseMoney, paymentPhase, requireAsset, resolveIdentityDestination, toAssetId, toCurrencyCode, toEvmAddress, toOrgId, toPartyId, toRaw, valueActivitySummary } from "@capxul/sdk";
@@ -1204,14 +1204,24 @@ async function storageKey$1(operation, intent) {
1204
1204
  }
1205
1205
  function paymentLockManager() {
1206
1206
  const manager = navigator.locks;
1207
- if (manager === void 0 || typeof manager.query !== "function") throw Errors.providerError("sdk-react", "paymentRequestKey", /* @__PURE__ */ new Error("Web Locks are required for payment request keys"));
1207
+ if (manager === void 0 || typeof manager.query !== "function") throw Errors.providerUnavailable({
1208
+ provider: "sdk-react",
1209
+ operation: "paymentRequestKey",
1210
+ mode: "no-secure-context",
1211
+ details: { reason: "web-locks-unavailable" }
1212
+ });
1208
1213
  return manager;
1209
1214
  }
1210
1215
  function readState(key) {
1211
1216
  const stored = localStorage.getItem(key);
1212
1217
  if (stored === null) return null;
1213
1218
  const state = JSON.parse(stored);
1214
- if (!isPaymentRequestKeyState(state)) throw Errors.providerError("sdk-react", "paymentRequestKey", /* @__PURE__ */ new TypeError("Invalid payment request key state"));
1219
+ if (!isPaymentRequestKeyState(state)) throw Errors.providerUnavailable({
1220
+ provider: "sdk-react",
1221
+ operation: "paymentRequestKey",
1222
+ mode: "defect",
1223
+ details: { reason: "invalid-stored-state" }
1224
+ });
1215
1225
  return state;
1216
1226
  }
1217
1227
  async function beginPaymentRequestKey(operation, intent) {
@@ -1267,7 +1277,12 @@ async function beginPaymentRequestKey(operation, intent) {
1267
1277
  } catch (cause) {
1268
1278
  forgetPagehideRelease?.();
1269
1279
  releaseAttemptLock?.();
1270
- throw Errors.providerError("sdk-react", "paymentRequestKey", cause);
1280
+ throw Errors.providerUnavailable({
1281
+ provider: "sdk-react",
1282
+ operation: "paymentRequestKey",
1283
+ mode: "unknown",
1284
+ cause
1285
+ });
1271
1286
  }
1272
1287
  }
1273
1288
  async function withPaymentRequestKey(operation, intent, work) {
@@ -1418,26 +1433,6 @@ function useCapxulOrganizationPayBatch(orgId) {
1418
1433
  });
1419
1434
  }
1420
1435
  //#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
1436
  //#region src/platform/signer-status.ts
1442
1437
  const NO_SUBSCRIPTION = () => () => {};
1443
1438
  function useSignerStatus(client) {
@@ -1592,9 +1587,6 @@ function useSendMoney(input) {
1592
1587
  const client = useCapxulClientOrNull();
1593
1588
  const signerStatus = useSignerStatus(client);
1594
1589
  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
1590
  const balance = useCapxulAccountBalance({ enabled: actor.kind === "personal" });
1599
1591
  const treasury = useCapxulOrgTreasury(orgId, { enabled: actor.kind === "organization" });
1600
1592
  const accountQuery = actor.kind === "personal" ? balance : treasury;
@@ -1603,6 +1595,9 @@ function useSendMoney(input) {
1603
1595
  const assetOptions = useMemo(() => assetSelections.map((selection) => selection.option), [assetSelections]);
1604
1596
  const [selectedAssetOption, selectAsset] = useSelectedOption(assetOptions);
1605
1597
  const selectedAssetMoney = useMemo(() => assetSelections.find((selection) => selection.option.id === selectedAssetOption?.id)?.money ?? null, [assetSelections, selectedAssetOption]);
1598
+ const meReading = useOrgMeReading(orgId);
1599
+ 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]);
1600
+ const [selectedSource, selectSource] = useSelectedOption(sourceOptions);
1606
1601
  const [amountText, setAmountText] = useState("");
1607
1602
  const parsed = useMemo(() => selectedAssetMoney === null || amountText.trim() === "" ? null : parseAssetAmount(amountText, requireAsset(selectedAssetMoney.asset)), [amountText, selectedAssetMoney]);
1608
1603
  const parsedMoney = parsed !== null && !isMoneyParseError(parsed) ? parsed : null;
@@ -1616,7 +1611,7 @@ function useSendMoney(input) {
1616
1611
  const personalPay = useCapxulPay();
1617
1612
  const organizationPay = useCapxulOrganizationPay(orgId);
1618
1613
  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";
1614
+ 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
1615
  const submitGate = useRef(false);
1621
1616
  const submit = useCallback(() => {
1622
1617
  if (blockedReason !== null || submitGate.current) return;
@@ -2844,8 +2839,8 @@ function decodeDraft(value, scope) {
2844
2839
  };
2845
2840
  try {
2846
2841
  if (toRaw(selectedAmount, selectedAsset).toString() !== net) throw Errors.invalidInput("payrollDraft", "Draft payout units differ from net");
2847
- } catch {
2848
- throw Errors.invalidInput("payrollDraft", "Invalid draft payout amount");
2842
+ } catch (cause) {
2843
+ throw Errors.invalidInput("payrollDraft", "Invalid draft payout amount", cause);
2849
2844
  }
2850
2845
  return {
2851
2846
  to: {
@@ -2902,8 +2897,14 @@ function minorAmount(value) {
2902
2897
  if (typeof value !== "string" || !/^\d+$/u.test(value) || BigInt(value) <= 0n) throw Errors.invalidInput("payrollDraft", "Invalid draft amount");
2903
2898
  return value;
2904
2899
  }
2900
+ /** A draft failure that is not already typed: local storage failed, and nothing says how. */
2905
2901
  function runDraftError(cause) {
2906
- return cause instanceof CapxulError ? cause : Errors.providerError("sdk-react", "payrollDraft", cause);
2902
+ return cause instanceof CapxulError ? cause : Errors.providerUnavailable({
2903
+ provider: "sdk-react",
2904
+ operation: "payrollDraft",
2905
+ mode: "unknown",
2906
+ cause
2907
+ });
2907
2908
  }
2908
2909
  function storageKey(scope) {
2909
2910
  return `capxul.payroll.run-draft.v1:${scope}`;
@@ -2915,8 +2916,8 @@ function readRunDraft(scope) {
2915
2916
  let value;
2916
2917
  try {
2917
2918
  value = JSON.parse(raw);
2918
- } catch {
2919
- throw Errors.invalidInput("payrollDraft", "Invalid run draft JSON");
2919
+ } catch (cause) {
2920
+ throw Errors.invalidInput("payrollDraft", "Invalid run draft JSON", cause);
2920
2921
  }
2921
2922
  return decodeDraft(value, scope);
2922
2923
  } catch (cause) {
@@ -3362,8 +3363,8 @@ function freshRunDraft(input) {
3362
3363
  }
3363
3364
  };
3364
3365
  }
3365
- function hasRequiredCompensation(frozen, writerNamesSelectedAsset, selected, terms) {
3366
- return frozen || !writerNamesSelectedAsset || selected.every((recipientId) => terms.has(recipientId));
3366
+ function hasRequiredCompensation(frozen, selected, terms) {
3367
+ return frozen || selected.every((recipientId) => terms.has(recipientId));
3367
3368
  }
3368
3369
  /**
3369
3370
  * WHICH run the composer is composing, by MEANING rather than by object shape.
@@ -3406,10 +3407,14 @@ function remainingBalanceDisplay(available, total, asset) {
3406
3407
  }));
3407
3408
  return remaining < 0n ? `-${formatted}` : formatted;
3408
3409
  }
3409
- /** Persisted replay keeps its authorized Budget and asset; a prior debit cannot block its own recovery. */
3410
+ /**
3411
+ * Persisted replay keeps its authorized Budget and asset; a prior debit cannot
3412
+ * block its own recovery. A restored run names its Budget, so it counts only
3413
+ * whether that Budget is still offered, never how many others are.
3414
+ */
3410
3415
  function runAuthorityFacts(draft, budgets, asset, money, funds) {
3411
3416
  return {
3412
- budgetCount: draft !== null && !budgets.some((budget) => budget.id === draft.input.permissionId) ? 0 : budgets.length,
3417
+ budgetCount: draft === null ? budgets.length : budgets.filter((budget) => budget.id === draft.input.permissionId).length,
3413
3418
  hasAsset: asset !== null && (draft === null || draft.asset.id === asset.id && draft.input.asset === money?.asset),
3414
3419
  funds: draft?.input.requestKey === void 0 ? funds : "available"
3415
3420
  };
@@ -3426,8 +3431,7 @@ function firstFalseFact(facts) {
3426
3431
  if (!facts.hasAsset) return "no-asset";
3427
3432
  if (facts.recipientCount === 0) return "no-recipients";
3428
3433
  if (!facts.amountsParse) return "amount-invalid";
3429
- if (facts.funds === "insufficient") return "insufficient-funds";
3430
- return facts.writeNamesAsset ? null : "asset-unnamed";
3434
+ return facts.funds === "insufficient" ? "insufficient-funds" : null;
3431
3435
  }
3432
3436
  //#endregion
3433
3437
  //#region src/payroll/use-run-amounts.ts
@@ -3510,14 +3514,15 @@ function useRunAmounts(input) {
3510
3514
  * share one account id, and a symbol is display only (ADR-0028 R3). The run
3511
3515
  * writer receives the selected asset explicitly.
3512
3516
  */
3513
- function useRunAsset(account, canSelect) {
3517
+ function useRunAsset(account, canSelect, restoredAssetId) {
3514
3518
  const assetSelections = useMemo(() => assetSelectionsFromAccount(account), [account]);
3515
3519
  const assetOptions = useMemo(() => assetSelections.map((selection) => selection.option), [assetSelections]);
3516
3520
  const [selectedAssetId, setSelectedAssetId] = useState(null);
3517
3521
  useEffect(() => {
3518
3522
  if (!assetOptions.some((option) => option.id === selectedAssetId)) setSelectedAssetId(assetOptions[0]?.id ?? null);
3519
3523
  }, [assetOptions, selectedAssetId]);
3520
- const selectedAsset = assetOptions.find((option) => option.id === selectedAssetId) ?? null;
3524
+ const effectiveAssetId = restoredAssetId ?? selectedAssetId;
3525
+ const selectedAsset = assetOptions.find((option) => option.id === effectiveAssetId) ?? null;
3521
3526
  return {
3522
3527
  assetOptions,
3523
3528
  selectedAsset,
@@ -3609,7 +3614,7 @@ function usePayrollRun(input) {
3609
3614
  draftError
3610
3615
  ]);
3611
3616
  const canSelectAsset = useCallback(() => !submitGate.current && !frozen, [frozen]);
3612
- const { assetOptions, selectedAsset, selectAsset, assetMoney } = useRunAsset(treasury.data ?? null, canSelectAsset);
3617
+ const { assetOptions, selectedAsset, selectAsset, assetMoney } = useRunAsset(treasury.data ?? null, canSelectAsset, draft?.input.asset ?? null);
3613
3618
  const { named, payableRefs, compensationTerms } = useRunRecipients({
3614
3619
  options: roster.options,
3615
3620
  refs: roster.refs,
@@ -3624,14 +3629,12 @@ function usePayrollRun(input) {
3624
3629
  names: named,
3625
3630
  change
3626
3631
  });
3627
- const budgets = me.data?.budgets ?? [];
3628
- const writerNamesSelectedAsset = writeNamesAsset();
3632
+ const budgets = (me.data?.budgets ?? []).filter((budget) => selectedAsset === null || budget.asset.assetId === selectedAsset.id);
3629
3633
  const blockedReason = firstFalseFact({
3630
3634
  signerReady: signerStatus === "ready",
3631
3635
  ...runAuthorityFacts(draft, budgets, selectedAsset, assetMoney, funds),
3632
3636
  recipientCount: payableRefs === null ? 0 : selected.length,
3633
- amountsParse: total !== null && hasRequiredCompensation(frozen, writerNamesSelectedAsset, selected, compensationTerms),
3634
- writeNamesAsset: writerNamesSelectedAsset
3637
+ amountsParse: total !== null && hasRequiredCompensation(frozen, selected, compensationTerms)
3635
3638
  });
3636
3639
  const authorize = useAuthorizeRun({
3637
3640
  client,
@@ -859,11 +859,13 @@ function CapxulProvider(props) {
859
859
  //#endregion
860
860
  //#region ../protocol/src/errors/failure-modes.ts
861
861
  /**
862
- * Why an operation failed — the one flat vocabulary. The first four are the
863
- * auth/provider diagnoses that predate this file. The rest name the chain
864
- * path. `FailureMode` is derived from this list so a runtime membership check
865
- * (the SDK's `$exception` projection, the observability schema) and the type
866
- * can never drift apart.
862
+ * Why an operation failed — the one flat vocabulary. The first five are the
863
+ * auth and signer diagnoses that predate this file. The next eleven name the
864
+ * chain path. `refused` and `defect` name a provider refusal and a Capxul
865
+ * fault on any path (ADR-0039 D2). `FailureMode` is derived from this list so
866
+ * a runtime membership check (the SDK's `$exception` projection, the
867
+ * observability schema) and the type can never drift apart. Every word has a
868
+ * failure class in `classes.ts`.
867
869
  */
868
870
  const FAILURE_MODES = [
869
871
  "auth-origin-mismatch",
@@ -882,6 +884,8 @@ const FAILURE_MODES = [
882
884
  "forbidden",
883
885
  "bad-request",
884
886
  "method-unsupported",
887
+ "refused",
888
+ "defect",
885
889
  "unknown"
886
890
  ];
887
891
  function isFailureMode(value) {
@@ -1,4 +1,4 @@
1
- import { i as CapxulProvider, n as CapxulAuthenticationController, t as CapxulOnboardingController } from "../onboarding-controller-DWuvVuC8.mjs";
1
+ import { i as CapxulProvider, n as CapxulAuthenticationController, t as CapxulOnboardingController } from "../onboarding-controller-BCrkmLxQ.mjs";
2
2
  import "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { createCapxulTestClient } from "@capxul/sdk/testing";
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.37",
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.37"
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.8",
79
79
  "@capxul/typescript-config": "0.0.0"
80
80
  },
81
81
  "peerDependencies": {