@capxul/sdk-react 1.0.0-alpha.20 → 1.0.0-alpha.22

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.mjs CHANGED
@@ -355,6 +355,7 @@ function actorKey(actor) {
355
355
  }
356
356
  function targetKey(target) {
357
357
  if (target === void 0) return "all";
358
+ if ("self" in target) return "self";
358
359
  switch (target.kind) {
359
360
  case "handle": return `handle:${target.handle}`;
360
361
  case "email": return `email:${target.email}`;
@@ -396,6 +397,12 @@ const capxulKeys = {
396
397
  root: ["capxul"],
397
398
  session: ["capxul", "session"],
398
399
  profile: ["capxul", "profile"],
400
+ usernameAvailability: (username) => [
401
+ "capxul",
402
+ "profile",
403
+ "username-availability",
404
+ username
405
+ ],
399
406
  account: ["capxul", "account"],
400
407
  accountLifecycle: ["capxul", "accountLifecycle"],
401
408
  provisioning: ["capxul", "provisioning"],
@@ -575,10 +582,11 @@ function useCapxulSession() {
575
582
  //#region src/hooks/use-capxul-profile.ts
576
583
  function useCapxulProfile() {
577
584
  const client = useCapxulClientOrNull();
585
+ const session = useCapxulSession();
578
586
  return useQuery({
579
587
  queryKey: capxulKeys.profile,
580
588
  queryFn: async () => unwrapCapxulResult(await requireBootstrappedClient(client, "identity.loadCurrent").identity.loadCurrent(), client._internal.telemetry),
581
- enabled: client !== null
589
+ enabled: client !== null && session.data != null
582
590
  });
583
591
  }
584
592
  //#endregion
@@ -1445,12 +1453,51 @@ function useCapxulCompletePersonalOnboarding() {
1445
1453
  const bootstrappedClient = requireBootstrappedClient(client, "onboarding.completePersonal");
1446
1454
  return unwrapCapxulResult(await bootstrappedClient.onboarding.completePersonal(input), bootstrappedClient._internal.telemetry, "mutation");
1447
1455
  },
1448
- onSuccess: async () => {
1456
+ onSettled: async () => {
1449
1457
  await Promise.all([queryClient.invalidateQueries({ queryKey: capxulKeys.profile }), queryClient.invalidateQueries({ queryKey: capxulKeys.accountLifecycle })]);
1450
1458
  }
1451
1459
  });
1452
1460
  }
1453
1461
  //#endregion
1462
+ //#region ../types/src/index.ts
1463
+ const SUPPORTED_CURRENCIES = [
1464
+ {
1465
+ code: "USD",
1466
+ symbol: "$",
1467
+ name: "US Dollar"
1468
+ },
1469
+ {
1470
+ code: "NGN",
1471
+ symbol: "NGN",
1472
+ name: "Nigerian Naira"
1473
+ },
1474
+ {
1475
+ code: "GHS",
1476
+ symbol: "GHS",
1477
+ name: "Ghanaian Cedi"
1478
+ },
1479
+ {
1480
+ code: "KES",
1481
+ symbol: "KSh",
1482
+ name: "Kenyan Shilling"
1483
+ },
1484
+ {
1485
+ code: "UGX",
1486
+ symbol: "USh",
1487
+ name: "Ugandan Shilling"
1488
+ }
1489
+ ];
1490
+ SUPPORTED_CURRENCIES.map((currency) => currency.code);
1491
+ Object.fromEntries(SUPPORTED_CURRENCIES.map((currency) => [currency.code, currency.symbol]));
1492
+ Math.floor(Number.MAX_SAFE_INTEGER / 1e3);
1493
+ function toOrgId(raw) {
1494
+ return toNonEmptyStringBrand(raw, "orgId");
1495
+ }
1496
+ function toNonEmptyStringBrand(raw, field) {
1497
+ if (typeof raw !== "string" || raw.length === 0) throw Errors.invalidInput(field, "must be a non-empty string");
1498
+ return raw;
1499
+ }
1500
+ //#endregion
1454
1501
  //#region src/hooks/use-capxul-complete-organization-onboarding.ts
1455
1502
  function useCapxulCompleteOrganizationOnboarding() {
1456
1503
  const client = useCapxulClientOrNull();
@@ -1460,16 +1507,23 @@ function useCapxulCompleteOrganizationOnboarding() {
1460
1507
  const bootstrappedClient = requireBootstrappedClient(client, "onboarding.completeOrganization");
1461
1508
  return unwrapCapxulResult(await bootstrappedClient.onboarding.completeOrganization(input), bootstrappedClient._internal.telemetry, "mutation");
1462
1509
  },
1463
- onSuccess: async ({ orgId }) => {
1464
- await Promise.all([
1465
- queryClient.invalidateQueries({ queryKey: capxulKeys.profile }),
1466
- queryClient.invalidateQueries({ queryKey: capxulKeys.accountLifecycle }),
1467
- queryClient.invalidateQueries({ queryKey: capxulKeys.orgs }),
1468
- queryClient.invalidateQueries({ queryKey: capxulKeys.org(orgId) })
1469
- ]);
1510
+ onSettled: async (data, error) => {
1511
+ const invalidations = [queryClient.invalidateQueries({ queryKey: capxulKeys.profile }), queryClient.invalidateQueries({ queryKey: capxulKeys.accountLifecycle })];
1512
+ const orgId = data?.orgId ?? organizationIdFromError(error);
1513
+ if (orgId !== void 0) invalidations.push(queryClient.invalidateQueries({ queryKey: capxulKeys.orgs }), queryClient.invalidateQueries({ queryKey: capxulKeys.org(orgId) }), queryClient.invalidateQueries({ queryKey: capxulKeys.orgLifecycle(orgId) }));
1514
+ await Promise.all(invalidations);
1470
1515
  }
1471
1516
  });
1472
1517
  }
1518
+ function organizationIdFromError(error) {
1519
+ const candidate = error?.details?.orgId;
1520
+ if (typeof candidate !== "string") return void 0;
1521
+ try {
1522
+ return toOrgId(candidate);
1523
+ } catch {
1524
+ return;
1525
+ }
1526
+ }
1473
1527
  //#endregion
1474
1528
  //#region src/hooks/use-capxul-invite-member.ts
1475
1529
  function useCapxulInviteMember(orgId) {
@@ -1632,38 +1686,6 @@ function toQuerySlotState(query) {
1632
1686
  };
1633
1687
  }
1634
1688
  //#endregion
1635
- //#region ../types/src/index.ts
1636
- const SUPPORTED_CURRENCIES = [
1637
- {
1638
- code: "USD",
1639
- symbol: "$",
1640
- name: "US Dollar"
1641
- },
1642
- {
1643
- code: "NGN",
1644
- symbol: "NGN",
1645
- name: "Nigerian Naira"
1646
- },
1647
- {
1648
- code: "GHS",
1649
- symbol: "GHS",
1650
- name: "Ghanaian Cedi"
1651
- },
1652
- {
1653
- code: "KES",
1654
- symbol: "KSh",
1655
- name: "Kenyan Shilling"
1656
- },
1657
- {
1658
- code: "UGX",
1659
- symbol: "USh",
1660
- name: "Ugandan Shilling"
1661
- }
1662
- ];
1663
- SUPPORTED_CURRENCIES.map((currency) => currency.code);
1664
- Object.fromEntries(SUPPORTED_CURRENCIES.map((currency) => [currency.code, currency.symbol]));
1665
- Math.floor(Number.MAX_SAFE_INTEGER / 1e3);
1666
- //#endregion
1667
1689
  //#region src/headless/money/SendMoney.tsx
1668
1690
  function SendMoney({ initialValue = null, slots, onSent }) {
1669
1691
  const pay = useCapxulPay();
@@ -1781,6 +1803,333 @@ function Destinations({ input, slots }) {
1781
1803
  return slots.root?.({ children }) ?? children;
1782
1804
  }
1783
1805
  //#endregion
1784
- export { AddressBook, CapxulProvider, Destinations, InsightsSummary, PayrollRoster, RequestInbox, SendMoney, capxulAccountScope, capxulOrgScope, useCapxul, useCapxulAccountBalance, useCapxulAccountFund, useCapxulAccountLifecycle, useCapxulActivity, useCapxulAddAddressBookEntry, useCapxulAddDestination, useCapxulAddPayrollRosterLine, useCapxulAddressBook, useCapxulAddressBookEntry, useCapxulApproveInboxRequest, useCapxulAssignRole, useCapxulCancelPayment, useCapxulCancelRequest, useCapxulClientOrNull, useCapxulCompleteOrganizationOnboarding, useCapxulCompletePersonalOnboarding, useCapxulCreateOrg, useCapxulCurrentUser, useCapxulDeclineInboxRequest, useCapxulDestinations, useCapxulHideAddressBookEntry, useCapxulInbox, useCapxulInsightsHistory, useCapxulInsightsSummary, useCapxulInviteMember, useCapxulIssueRequest, useCapxulLabelAddressBookEntry, useCapxulOfframpQuote, useCapxulOfframpStatus, useCapxulOrg, useCapxulOrgDeployRoles, useCapxulOrgLifecycle, useCapxulOrgMembers, useCapxulOrgRoles, useCapxulOrgTreasury, useCapxulOrganizationAccount, useCapxulOrganizationAuditLog, useCapxulOrgs, useCapxulPay, useCapxulPayment, useCapxulPayments, useCapxulPayout, useCapxulPayrollRoster, useCapxulProfile, useCapxulReconcileRequests, useCapxulRemoveDestination, useCapxulRemoveMember, useCapxulRemovePayrollRosterLine, useCapxulRequest, useCapxulRequests, useCapxulRunPayroll, useCapxulSession, useCapxulSignIn, useCapxulSignOut, useCapxulSubAccountCreate, useCapxulSubAccountDelete, useCapxulSubAccountRename, useCapxulSubAccountsList, useCapxulSwitchActingEntity, useCapxulTransfer, useCapxulUnhideAddressBookEntry, useCapxulUpdatePayrollRosterLine, useCapxulVerifyOtp, useCapxulWithdraw };
1806
+ //#region src/headless/journey/journey-state.ts
1807
+ const JOURNEY_KEY = "capxul.onboarding.journey.v1";
1808
+ const VALIDATED_OWNER_KEY = "capxul.onboarding.validated-owner.v1";
1809
+ const JOURNEY_VERSION = 1;
1810
+ const MAX_DRAFT_TEXT_LENGTH = 200;
1811
+ const MAX_ID_LENGTH = 160;
1812
+ const MAX_STORED_JOURNEY_LENGTH = 8192;
1813
+ const MAX_PAYOUT_DRAFT_ENTRIES = 10;
1814
+ /**
1815
+ * The owner whose stored journey may currently be attributed to observations.
1816
+ * Persisted in sessionStorage rather than module memory so `currentOnboarding-
1817
+ * JourneyId` is a pure function of durable state — attribution is the same
1818
+ * regardless of the order of renders, reloads, or telemetry emits. Established
1819
+ * only when an authenticated owner is (journey start, or an owner-matched load)
1820
+ * and cleared at every auth boundary or on discard.
1821
+ */
1822
+ function markOnboardingOwnerValidated(ownerId) {
1823
+ try {
1824
+ sessionStorage.setItem(VALIDATED_OWNER_KEY, ownerId);
1825
+ } catch {}
1826
+ }
1827
+ function clearValidatedOnboardingOwner() {
1828
+ try {
1829
+ sessionStorage.removeItem(VALIDATED_OWNER_KEY);
1830
+ } catch {}
1831
+ }
1832
+ function validatedOnboardingOwner() {
1833
+ try {
1834
+ return sessionStorage.getItem(VALIDATED_OWNER_KEY);
1835
+ } catch {
1836
+ return null;
1837
+ }
1838
+ }
1839
+ function startOnboardingJourney(input) {
1840
+ const journey = {
1841
+ version: JOURNEY_VERSION,
1842
+ ownerId: input.ownerId,
1843
+ journeyId: `journey_${createRandomId()}`,
1844
+ intent: input.intent,
1845
+ entryPoint: input.entryPoint,
1846
+ step: input.step ?? "profile",
1847
+ ...input.origin === void 0 ? {} : { origin: input.origin }
1848
+ };
1849
+ markOnboardingOwnerValidated(journey.ownerId);
1850
+ saveOnboardingJourney(journey);
1851
+ return journey;
1852
+ }
1853
+ function loadOnboardingJourney(expectedOwnerId) {
1854
+ try {
1855
+ const raw = sessionStorage.getItem(JOURNEY_KEY);
1856
+ if (raw === null) return null;
1857
+ if (raw.length > MAX_STORED_JOURNEY_LENGTH) return discardInvalidJourney();
1858
+ const value = JSON.parse(raw);
1859
+ if (!isValidJourney(value)) return discardInvalidJourney();
1860
+ if (expectedOwnerId !== void 0 && value.ownerId !== expectedOwnerId) return discardInvalidJourney();
1861
+ if (expectedOwnerId !== void 0) markOnboardingOwnerValidated(expectedOwnerId);
1862
+ return value;
1863
+ } catch {
1864
+ return discardInvalidJourney();
1865
+ }
1866
+ }
1867
+ function saveOnboardingJourney(journey) {
1868
+ if (!isValidJourney(journey)) {
1869
+ discardInvalidJourney();
1870
+ return;
1871
+ }
1872
+ try {
1873
+ sessionStorage.setItem(JOURNEY_KEY, JSON.stringify(journey));
1874
+ } catch {}
1875
+ }
1876
+ function currentOnboardingJourneyId() {
1877
+ const journey = loadOnboardingJourney();
1878
+ const owner = validatedOnboardingOwner();
1879
+ return journey !== null && owner !== null && journey.ownerId === owner ? journey.journeyId : void 0;
1880
+ }
1881
+ /** Stop observation attribution while no authenticated owner is established. */
1882
+ function invalidateOnboardingJourneyObservation() {
1883
+ clearValidatedOnboardingOwner();
1884
+ }
1885
+ /** Where the journey stands — the pure position apps map to their routes. */
1886
+ function onboardingJourneyPosition(journey) {
1887
+ const proof = journey.origin?.kind === "proof";
1888
+ if (journey.organizationId !== void 0) return {
1889
+ intent: journey.intent,
1890
+ step: "provisioning",
1891
+ organizationId: journey.organizationId,
1892
+ proof
1893
+ };
1894
+ return {
1895
+ intent: journey.intent,
1896
+ step: journey.step,
1897
+ proof
1898
+ };
1899
+ }
1900
+ /**
1901
+ * The interruption-recovery decision (behavior map §4): a journey that does
1902
+ * not match the ready destination the app just rendered must resume; a
1903
+ * matching one needs no recovery. Returns the journey to resume, or null.
1904
+ */
1905
+ function activeOnboardingRecovery(ownerId, renderedReadyDestination) {
1906
+ const journey = loadOnboardingJourney(ownerId);
1907
+ if (journey === null) return null;
1908
+ return (renderedReadyDestination?.kind === "personal" ? journey.intent === "personal" && journey.step === "provisioning" && journey.organizationId === void 0 : renderedReadyDestination?.kind === "organization" && journey.intent === "organization" && journey.step === "provisioning" && journey.organizationId === renderedReadyDestination.organizationId) ? null : journey;
1909
+ }
1910
+ function acknowledgeOnboardingDestination(destination, ownerId) {
1911
+ const journey = loadOnboardingJourney(ownerId);
1912
+ if (journey === null) return false;
1913
+ if (!(destination.kind === "personal" ? journey.intent === "personal" && journey.step === "provisioning" : journey.intent === "organization" && journey.step === "provisioning" && journey.organizationId === destination.organizationId)) return false;
1914
+ clearOnboardingJourney();
1915
+ return true;
1916
+ }
1917
+ function clearOnboardingJourney() {
1918
+ clearValidatedOnboardingOwner();
1919
+ try {
1920
+ sessionStorage.removeItem(JOURNEY_KEY);
1921
+ } catch {}
1922
+ }
1923
+ function isValidJourney(value) {
1924
+ if (!isRecord(value) || value.version !== JOURNEY_VERSION) return false;
1925
+ if (!hasOnlyKeys(value, [
1926
+ "version",
1927
+ "ownerId",
1928
+ "journeyId",
1929
+ "intent",
1930
+ "entryPoint",
1931
+ "origin",
1932
+ "step",
1933
+ "profile",
1934
+ "organization",
1935
+ "stableHandle",
1936
+ "organizationId"
1937
+ ])) return false;
1938
+ if (!isBoundedId(value.ownerId)) return false;
1939
+ if (!isBoundedId(value.journeyId) || !value.journeyId.startsWith("journey_")) return false;
1940
+ if (value.intent !== "personal" && value.intent !== "organization") return false;
1941
+ if (value.entryPoint !== "signup" && value.entryPoint !== "dashboard") return false;
1942
+ if (value.step !== "profile" && value.step !== "organization" && value.step !== "provisioning") return false;
1943
+ if (value.origin !== void 0 && !isOrigin(value.origin)) return false;
1944
+ if (value.profile !== void 0 && !isProfileDraft(value.profile)) return false;
1945
+ if (value.organization !== void 0 && !isOrganizationDraft(value.organization)) return false;
1946
+ if (value.stableHandle !== void 0 && !isDraftText(value.stableHandle)) return false;
1947
+ if (value.organizationId !== void 0 && !isBoundedId(value.organizationId)) return false;
1948
+ if (value.organization !== void 0 && value.stableHandle !== value.organization.handle) return false;
1949
+ if (value.stableHandle !== void 0 && value.organization === void 0) return false;
1950
+ if (value.intent === "personal" && (value.step === "organization" || value.organization !== void 0 || value.stableHandle !== void 0)) return false;
1951
+ if (value.step === "organization" && value.intent !== "organization") return false;
1952
+ if (value.organizationId !== void 0 && value.intent !== "organization") return false;
1953
+ if (value.organizationId !== void 0 && value.step !== "provisioning") return false;
1954
+ return true;
1955
+ }
1956
+ function isOrigin(value) {
1957
+ if (!isRecord(value)) return false;
1958
+ if (value.kind === "personal") return hasOnlyKeys(value, ["kind"]);
1959
+ if (value.kind === "organization") return hasOnlyKeys(value, ["kind", "organizationId"]) && isBoundedId(value.organizationId);
1960
+ return value.kind === "proof" && hasOnlyKeys(value, ["kind", "organizationId"]) && (value.organizationId === void 0 || isBoundedId(value.organizationId));
1961
+ }
1962
+ function isProfileDraft(value) {
1963
+ if (!isRecord(value) || !hasOnlyKeys(value, [
1964
+ "displayName",
1965
+ "country",
1966
+ "withdrawalAddress",
1967
+ "username",
1968
+ "payoutAddresses"
1969
+ ]) || !isDraftText(value.displayName) || !isDraftText(value.country) || !isDraftText(value.withdrawalAddress)) return false;
1970
+ if (value.username !== void 0 && !isDraftText(value.username)) return false;
1971
+ if (value.payoutAddresses !== void 0 && !isPayoutDraftList(value.payoutAddresses)) return false;
1972
+ return true;
1973
+ }
1974
+ function isPayoutDraftList(value) {
1975
+ return Array.isArray(value) && value.length <= MAX_PAYOUT_DRAFT_ENTRIES && value.every((entry) => isRecord(entry) && hasOnlyKeys(entry, ["chain", "address"]) && (entry.chain === "evm" || entry.chain === "solana" || entry.chain === "starknet") && isDraftText(entry.address));
1976
+ }
1977
+ function isOrganizationDraft(value) {
1978
+ if (!isRecord(value) || !hasOnlyKeys(value, [
1979
+ "name",
1980
+ "handle",
1981
+ "country",
1982
+ "bio",
1983
+ "size"
1984
+ ]) || !isDraftText(value.name) || !isDraftText(value.handle) || !isDraftText(value.country)) return false;
1985
+ if (value.bio !== void 0 && !isDraftText(value.bio)) return false;
1986
+ if (value.size !== void 0 && !isDraftText(value.size)) return false;
1987
+ return true;
1988
+ }
1989
+ function isDraftText(value) {
1990
+ return typeof value === "string" && value.length <= MAX_DRAFT_TEXT_LENGTH;
1991
+ }
1992
+ function isBoundedId(value) {
1993
+ return typeof value === "string" && value.length > 0 && value.length <= MAX_ID_LENGTH;
1994
+ }
1995
+ function discardInvalidJourney() {
1996
+ clearValidatedOnboardingOwner();
1997
+ try {
1998
+ sessionStorage.removeItem(JOURNEY_KEY);
1999
+ } catch {}
2000
+ return null;
2001
+ }
2002
+ function createRandomId() {
2003
+ if (typeof globalThis.crypto?.randomUUID === "function") return globalThis.crypto.randomUUID();
2004
+ return Math.random().toString(36).slice(2);
2005
+ }
2006
+ function isRecord(value) {
2007
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2008
+ }
2009
+ function hasOnlyKeys(value, allowed) {
2010
+ return Object.keys(value).every((key) => allowed.includes(key));
2011
+ }
2012
+ //#endregion
2013
+ //#region src/headless/routing/resolve-post-auth-destination.ts
2014
+ function resolvePostAuthDestination(inputs) {
2015
+ if (inputs.journey !== null) return {
2016
+ kind: "journey",
2017
+ position: onboardingJourneyPosition(inputs.journey)
2018
+ };
2019
+ if (!inputs.profileOnboarded) return { kind: "selectUserType" };
2020
+ if (!inputs.accountReady) return { kind: "provisioning" };
2021
+ return {
2022
+ kind: "dashboard",
2023
+ entity: inputs.lastActingEntity ?? { kind: "personal" }
2024
+ };
2025
+ }
2026
+ //#endregion
2027
+ //#region src/internal/use-debounced-value.ts
2028
+ /** The value as of `delayMs` after its last change (initial value immediate). */
2029
+ function useDebouncedValue(value, delayMs) {
2030
+ const [debounced, setDebounced] = useState(value);
2031
+ useEffect(() => {
2032
+ const timer = setTimeout(() => setDebounced(value), delayMs);
2033
+ return () => clearTimeout(timer);
2034
+ }, [value, delayMs]);
2035
+ return debounced;
2036
+ }
2037
+ //#endregion
2038
+ //#region src/headless/onboarding/use-capxul-username-availability.ts
2039
+ /**
2040
+ * #1062: debounced availability probe for the username the user is typing.
2041
+ * Disabled until the candidate reaches the 3-character floor; a malformed or
2042
+ * reserved candidate surfaces as the query's error (INVALID_INPUT with the
2043
+ * boundary's message), not as `available: false` — only a username someone
2044
+ * else owns is "taken".
2045
+ */
2046
+ function useCapxulUsernameAvailability(username, options) {
2047
+ const client = useCapxulClientOrNull();
2048
+ const candidate = useDebouncedValue(username.trim(), options?.debounceMs ?? 300);
2049
+ return useQuery({
2050
+ queryKey: capxulKeys.usernameAvailability(candidate),
2051
+ queryFn: async () => {
2052
+ const bootstrappedClient = requireBootstrappedClient(client, "identity.usernameAvailable");
2053
+ return unwrapCapxulResult(await bootstrappedClient.identity.usernameAvailable(candidate), bootstrappedClient._internal.telemetry);
2054
+ },
2055
+ enabled: client !== null && candidate.length >= 3 && (options?.enabled ?? true)
2056
+ });
2057
+ }
2058
+ //#endregion
2059
+ //#region src/headless/onboarding/use-capxul-persist-payout-entries.ts
2060
+ const CHAIN_TO_NETWORK = {
2061
+ evm: "base-sepolia",
2062
+ solana: "solana-devnet",
2063
+ starknet: "starknet-sepolia"
2064
+ };
2065
+ /**
2066
+ * #1063: persist onboarding payout entries as SELF-owned wallet destinations.
2067
+ * Per-entry failures are collected, never thrown — payout persistence is
2068
+ * additive to the journey (identity creation is the invariant; behavior map
2069
+ * §3 J1), so callers surface `failures` as a non-blocking notice.
2070
+ */
2071
+ function useCapxulPersistPayoutEntries() {
2072
+ const client = useCapxulClientOrNull();
2073
+ const queryClient = useQueryClient();
2074
+ return useMutation({
2075
+ mutationFn: async (entries) => {
2076
+ const bootstrappedClient = requireBootstrappedClient(client, "destinations.add");
2077
+ const failures = [];
2078
+ let persisted = 0;
2079
+ for (const entry of entries) {
2080
+ const result = await bootstrappedClient.destinations.add({
2081
+ target: { self: true },
2082
+ kind: "external_account",
2083
+ payload: {
2084
+ network: CHAIN_TO_NETWORK[entry.chain],
2085
+ address: entry.address
2086
+ }
2087
+ });
2088
+ if (result.ok) persisted += 1;
2089
+ else failures.push({
2090
+ entry,
2091
+ error: result.error
2092
+ });
2093
+ }
2094
+ return {
2095
+ persisted,
2096
+ failures
2097
+ };
2098
+ },
2099
+ onSuccess: async () => {
2100
+ await queryClient.invalidateQueries({ queryKey: capxulKeys.destinationsScope });
2101
+ }
2102
+ });
2103
+ }
2104
+ //#endregion
2105
+ //#region src/headless/media/use-capxul-image-upload.ts
2106
+ /**
2107
+ * #1061 / ADR-0014: the whole upload→record sequence as one mutation —
2108
+ * upload the blob, then bind the returned storage id to the profile image or
2109
+ * the org logo. The url is the resolved serving URL (re-read from queries,
2110
+ * never persisted by consumers).
2111
+ */
2112
+ function useCapxulImageUpload() {
2113
+ const client = useCapxulClientOrNull();
2114
+ const queryClient = useQueryClient();
2115
+ return useMutation({
2116
+ mutationFn: async ({ blob, target }) => {
2117
+ const bootstrappedClient = requireBootstrappedClient(client, "media.uploadImage");
2118
+ const media = bootstrappedClient.media;
2119
+ const telemetry = bootstrappedClient._internal.telemetry;
2120
+ const uploaded = unwrapCapxulResult(await media.uploadImage(blob), telemetry);
2121
+ if (target.kind === "profile") return { url: unwrapCapxulResult(await media.setProfileImage({ storageId: uploaded.storageId }), telemetry).imageUrl };
2122
+ return { url: unwrapCapxulResult(await media.setOrgLogo({
2123
+ orgId: target.orgId,
2124
+ storageId: uploaded.storageId
2125
+ }), telemetry).logoUrl };
2126
+ },
2127
+ onSuccess: async (_value, input) => {
2128
+ await queryClient.invalidateQueries({ queryKey: input.target.kind === "profile" ? capxulKeys.profile : capxulKeys.orgs });
2129
+ }
2130
+ });
2131
+ }
2132
+ //#endregion
2133
+ export { AddressBook, CapxulProvider, Destinations, InsightsSummary, PayrollRoster, RequestInbox, SendMoney, acknowledgeOnboardingDestination, activeOnboardingRecovery, capxulAccountScope, capxulOrgScope, clearOnboardingJourney, currentOnboardingJourneyId, invalidateOnboardingJourneyObservation, loadOnboardingJourney, onboardingJourneyPosition, resolvePostAuthDestination, saveOnboardingJourney, startOnboardingJourney, useCapxul, useCapxulAccountBalance, useCapxulAccountFund, useCapxulAccountLifecycle, useCapxulActivity, useCapxulAddAddressBookEntry, useCapxulAddDestination, useCapxulAddPayrollRosterLine, useCapxulAddressBook, useCapxulAddressBookEntry, useCapxulApproveInboxRequest, useCapxulAssignRole, useCapxulCancelPayment, useCapxulCancelRequest, useCapxulClientOrNull, useCapxulCompleteOrganizationOnboarding, useCapxulCompletePersonalOnboarding, useCapxulCreateOrg, useCapxulCurrentUser, useCapxulDeclineInboxRequest, useCapxulDestinations, useCapxulHideAddressBookEntry, useCapxulImageUpload, useCapxulInbox, useCapxulInsightsHistory, useCapxulInsightsSummary, useCapxulInviteMember, useCapxulIssueRequest, useCapxulLabelAddressBookEntry, useCapxulOfframpQuote, useCapxulOfframpStatus, useCapxulOrg, useCapxulOrgDeployRoles, useCapxulOrgLifecycle, useCapxulOrgMembers, useCapxulOrgRoles, useCapxulOrgTreasury, useCapxulOrganizationAccount, useCapxulOrganizationAuditLog, useCapxulOrgs, useCapxulPay, useCapxulPayment, useCapxulPayments, useCapxulPayout, useCapxulPayrollRoster, useCapxulPersistPayoutEntries, useCapxulProfile, useCapxulReconcileRequests, useCapxulRemoveDestination, useCapxulRemoveMember, useCapxulRemovePayrollRosterLine, useCapxulRequest, useCapxulRequests, useCapxulRunPayroll, useCapxulSession, useCapxulSignIn, useCapxulSignOut, useCapxulSubAccountCreate, useCapxulSubAccountDelete, useCapxulSubAccountRename, useCapxulSubAccountsList, useCapxulSwitchActingEntity, useCapxulTransfer, useCapxulUnhideAddressBookEntry, useCapxulUpdatePayrollRosterLine, useCapxulUsernameAvailability, useCapxulVerifyOtp, useCapxulWithdraw };
1785
2134
 
1786
2135
  //# sourceMappingURL=index.mjs.map