@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"
|
|
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"
|
|
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-
|
|
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.
|
|
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.
|
|
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.
|
|
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" :
|
|
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.
|
|
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,
|
|
3366
|
-
return frozen ||
|
|
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
|
-
/**
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
|
863
|
-
* auth
|
|
864
|
-
* path. `
|
|
865
|
-
* (
|
|
866
|
-
*
|
|
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) {
|
package/dist/testing/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as CapxulProvider, n as CapxulAuthenticationController, t as CapxulOnboardingController } from "../onboarding-controller-
|
|
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.
|
|
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.
|
|
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.
|
|
78
|
+
"@capxul/protocol": "0.2.0-beta.8",
|
|
79
79
|
"@capxul/typescript-config": "0.0.0"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|