@venlyfinance/react 0.3.0 → 0.5.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.
package/AGENTS.md CHANGED
@@ -9,6 +9,7 @@ You are building a financial product UI on `@venlyfinance/react`. These rules ex
9
9
  3. **Never place `clientSecret` in browser code.** The provider throws if you try. For browser apps use `proxyClientOptions()` against your own backend route.
10
10
  4. **Money movement is stage-then-confirm.** Render a review step showing `state.staged` (the exact request) before calling `confirm()`. Never wire a form submit directly to execution.
11
11
  5. **Approval UIs render the rule, not the error.** Use `capability` from `useFourEyesApproval`: when `reason` is `"actor-is-creator"`, say that a second person must approve – do not show buttons that will be refused. On failure `"stale-version"`, refetch and let the operator re-decide; never auto-retry an approval.
12
+ 6. **Gate both the screen and its runtime contract, and wire both into CI.** Run `npx @venlyfinance/settlement-mcp review "src/**/*.tsx"` for the design contract and `npx @venlyfinance/settlement-mcp verify "src/**/*.{ts,tsx}"` for package/provider/hook/proxy composition. Each fails (exit 1) on any error-severity finding. A deliberate, justified exception carries `venly-allow:<rule-id>` on the offending line or the line above.
12
13
 
13
14
  ## Rendering money states
14
15
 
@@ -31,4 +32,4 @@ The UI kit's auth and team blocks therefore render against two adapter interface
31
32
  ## Demo choreography (mock mode)
32
33
 
33
34
  `useVenlyMock()` exposes the store controls. A credible end-to-end demo:
34
- create party → `advanceVerification(id)` → create account → virtual bank account (note its `referenceCode`) → stage + confirm a transfer → `advanceTransfer(id)` → show the ledger. Inject failures with `failNext("CONFLICT")` to show the stale-version approval path – error states are part of the product.
35
+ create party → `advanceVerification(id)` → create account → virtual bank account (note its `referenceCode`) → **fund it: `simulations.inbound.credit(vbaId, 500)`** (a new account holds nothing, as in production; an unfunded transfer is refused with `402 insufficient-funds`) → stage + confirm a transfer → `advanceTransfer(id)` → show the ledger, and `simulations.ledger.verify()` to prove it balances. Inject failures with `failNext("CONFLICT")` to show the stale-version approval path – error states are part of the product.
package/CHANGELOG.md CHANGED
@@ -14,3 +14,37 @@ Initial release.
14
14
  ## 0.1.1
15
15
 
16
16
  - Fix: `useStagedTransfer` stuck in "submitting" under React StrictMode – the hook cleanup's `dispose()` left the controller permanently dead for the remount, so `confirm()`'s continuation dropped its state updates. A new subscription now revives the controller. Found by driving the flow in a real browser; regression test added.
17
+
18
+ ## 0.2.0 – 2026-08-07
19
+
20
+ *(Entry backfilled 2026-08-15 – this release shipped without a changelog note.)*
21
+
22
+ - Read hooks for the fundflow company surface: `useCompanyBankAccounts`,
23
+ `useCompanyBankAccount`, `useCompanyWallets`, `useBankAccountConfig`,
24
+ `useDepositWallets`, `useRampPairs`, `useCompanyFees`.
25
+ - Write hooks with cache invalidation: `useCreateCompanyBankAccount`,
26
+ `useCreateCompanyWallet`, `useSetRampAmount`, `useInitiateRamp`.
27
+ - Matching `venlyKeys` / `venlyQueries` factories for every new read.
28
+
29
+ ## 0.3.0 – 2026-08-14
30
+
31
+ *(Entry backfilled 2026-08-15 – this release shipped without a changelog note.)*
32
+
33
+ - **BREAKING (inherited from `@venlyfinance/sdk` 0.4.0 / contract 1.3.0):**
34
+ the `Wallet` type no longer exists – `wallets.list` returns per-asset
35
+ `WalletBalance` rows and this package re-exports `WalletBalance` instead.
36
+ Monetary amounts are JSON numbers.
37
+ - Re-exports the payout types (`Payout`, `PayoutRoute`, `PayoutBankAccount`)
38
+ shipped by sdk 0.4.0.
39
+ - Requires `@venlyfinance/sdk` ^0.4.0.
40
+
41
+ ## 0.4.0 – 2026-08-15
42
+
43
+ - New read hooks: `useSupportedAssets()` (tenant-wide assets, each with its
44
+ on-chain `decimals` – the render contract for amounts; cached hard) and
45
+ `useAccountSupportedAssets(accountId)` (adds per-asset `permitStatus`,
46
+ not frozen because status moves while an asset activates).
47
+ - `venlyKeys.supportedAssets()` / `venlyKeys.accountSupportedAssets(id)` and
48
+ matching `venlyQueries` factories; the account-scoped key shares the
49
+ `["venly", "account", id]` prefix so account invalidations reach it.
50
+ - Requires `@venlyfinance/sdk` ^0.5.0 (the `supportedAssets` resource).
package/README.md CHANGED
@@ -6,6 +6,8 @@ Headless React layer for the [Venly Finance and Fundflow APIs](https://github.co
6
6
 
7
7
  No components, no CSS. This package owns data and state; your UI (or the one your coding agent assembles) owns the pixels. The full behaviour is covered by a node:test suite that runs with zero network.
8
8
 
9
+ Building with a coding agent? Start from [AGENTS.md](AGENTS.md).
10
+
9
11
  ## Try it in 0 minutes (mock mode)
10
12
 
11
13
  ```bash
@@ -36,7 +38,7 @@ Mock mode needs zero credentials and makes zero network calls: every hook answer
36
38
  | Export | What it does |
37
39
  |---|---|
38
40
  | `<VenlyProvider>` | Constructs the Finance + Fundflow clients for `mock`, `staging`, or `production`; brings its own QueryClient if the app has none |
39
- | `useParties` `useAccounts` `useWallets` `useVirtualBankAccounts` `useTransfers` `useRampRequests` `useReferenceData` `useFeeQuote` … | Read hooks, one per API resource, cache keys managed for you |
41
+ | `useParties` `useAccounts` `useWallets` `useSupportedAssets` `useAccountSupportedAssets` `useVirtualBankAccounts` `useTransfers` `useRampRequests` `useReferenceData` `useFeeQuote` … | Read hooks, one per API resource, cache keys managed for you |
40
42
  | `useCreateParty` `useCreateAccount` `useCreateVirtualBankAccount` `useCreatePaymentSession` `useCreateRampRequest` | Write hooks with cache invalidation wired |
41
43
  | `useStagedTransfer` | Stage-then-confirm machine: validate → freeze the exact request with a pinned idempotency key → execute once → poll to terminal |
42
44
  | `useFourEyesApproval` | Approve/reject/cancel with the optimistic-locking `version` carried through; 409 surfaces as `"stale-version"` (refetch and re-decide, never auto-retry) |
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export { VenlyProvider, useVenly, useVenlyMock, type VenlyClients, type VenlyProviderProps, type VenlyReactEnvironment, } from "./provider.js";
2
2
  export { venlyKeys } from "./keys.js";
3
3
  export { venlyQueries, type AccountsQuery, type FeeQuoteInput, type PartiesQuery, type RampRequestsQuery, type TransfersQuery, type VirtualBankAccountsQuery, type WalletsQuery, } from "./query-options.js";
4
- export { useAccount, useAccounts, useCompanyFees, useFeeQuote, useParties, useParty, useRampRequest, useRampRequests, useReferenceData, useTransfer, useTransfers, useVirtualBankAccounts, useWallets, useCompanyBankAccount, useCompanyBankAccounts, useCompanyWallets, useBankAccountConfig, useDepositWallets, useRampPairs, } from "./queries.js";
4
+ export { useAccount, useAccounts, useCompanyFees, useFeeQuote, useParties, useParty, useRampRequest, useRampRequests, useReferenceData, useTransfer, useTransfers, useTransfersForPeriod, collectTransfersForPeriod, type TransferPeriod, type TransfersForPeriodPage, useVirtualBankAccounts, useWallets, useCompanyBankAccount, useCompanyBankAccounts, useCompanyWallets, useBankAccountConfig, useDepositWallets, useRampPairs, useSupportedAssets, useAccountSupportedAssets, } from "./queries.js";
5
5
  export { useCreateAccount, useCreateParty, useCreatePaymentSession, useCreateRampRequest, useCreateVirtualBankAccount, useCreateCompanyBankAccount, useCreateCompanyWallet, useSetRampAmount, useInitiateRamp, } from "./mutations.js";
6
6
  export { StagedTransferController, useStagedTransfer, validateDraft, type StagedRequest, type StagedTransferOptions, type StagedTransferState, type TransferDraft, } from "./flows/staged-transfer.js";
7
7
  export { approvalCapabilities, interpretApprovalError, useFourEyesApproval, type ApprovalCapability, type ApprovalFailureKind, type FourEyesState, } from "./flows/four-eyes.js";
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ export { VenlyProvider, useVenly, useVenlyMock, } from "./provider.js";
4
4
  export { venlyKeys } from "./keys.js";
5
5
  export { venlyQueries, } from "./query-options.js";
6
6
  // Read hooks
7
- export { useAccount, useAccounts, useCompanyFees, useFeeQuote, useParties, useParty, useRampRequest, useRampRequests, useReferenceData, useTransfer, useTransfers, useVirtualBankAccounts, useWallets, useCompanyBankAccount, useCompanyBankAccounts, useCompanyWallets, useBankAccountConfig, useDepositWallets, useRampPairs, } from "./queries.js";
7
+ export { useAccount, useAccounts, useCompanyFees, useFeeQuote, useParties, useParty, useRampRequest, useRampRequests, useReferenceData, useTransfer, useTransfers, useTransfersForPeriod, collectTransfersForPeriod, useVirtualBankAccounts, useWallets, useCompanyBankAccount, useCompanyBankAccounts, useCompanyWallets, useBankAccountConfig, useDepositWallets, useRampPairs, useSupportedAssets, useAccountSupportedAssets, } from "./queries.js";
8
8
  // Write hooks
9
9
  export { useCreateAccount, useCreateParty, useCreatePaymentSession, useCreateRampRequest, useCreateVirtualBankAccount, useCreateCompanyBankAccount, useCreateCompanyWallet, useSetRampAmount, useInitiateRamp, } from "./mutations.js";
10
10
  // Flow machines: the regulated-money lifecycles
package/dist/keys.d.ts CHANGED
@@ -9,8 +9,14 @@ export declare const venlyKeys: {
9
9
  readonly accounts: (query?: unknown) => readonly ["venly", "accounts", {} | null];
10
10
  readonly account: (accountId: string) => readonly ["venly", "account", string];
11
11
  readonly wallets: (accountId: string, query?: unknown) => readonly ["venly", "account", string, "wallets", {} | null];
12
+ readonly supportedAssets: () => readonly ["venly", "supported-assets"];
13
+ readonly accountSupportedAssets: (accountId: string) => readonly ["venly", "account", string, "supported-assets"];
12
14
  readonly virtualBankAccounts: (accountId: string, query?: unknown) => readonly ["venly", "account", string, "virtual-bank-accounts", {} | null];
13
15
  readonly transfers: (accountId: string, query?: unknown) => readonly ["venly", "account", string, "transfers", {} | null];
16
+ readonly transfersForPeriod: (accountId: string, period: {
17
+ start: string;
18
+ end: string;
19
+ }) => readonly ["venly", "account", string, "transfers-for-period", string, string];
14
20
  readonly transfer: (accountId: string, transferId: string) => readonly ["venly", "account", string, "transfer", string];
15
21
  readonly rampRequests: (query?: unknown) => readonly ["venly", "ramp-requests", {} | null];
16
22
  readonly rampRequest: (id: string) => readonly ["venly", "ramp-request", string];
package/dist/keys.js CHANGED
@@ -9,8 +9,11 @@ export const venlyKeys = {
9
9
  accounts: (query) => ["venly", "accounts", query ?? null],
10
10
  account: (accountId) => ["venly", "account", accountId],
11
11
  wallets: (accountId, query) => ["venly", "account", accountId, "wallets", query ?? null],
12
+ supportedAssets: () => ["venly", "supported-assets"],
13
+ accountSupportedAssets: (accountId) => ["venly", "account", accountId, "supported-assets"],
12
14
  virtualBankAccounts: (accountId, query) => ["venly", "account", accountId, "virtual-bank-accounts", query ?? null],
13
15
  transfers: (accountId, query) => ["venly", "account", accountId, "transfers", query ?? null],
16
+ transfersForPeriod: (accountId, period) => ["venly", "account", accountId, "transfers-for-period", period.start, period.end],
14
17
  transfer: (accountId, transferId) => ["venly", "account", accountId, "transfer", transferId],
15
18
  rampRequests: (query) => ["venly", "ramp-requests", query ?? null],
16
19
  rampRequest: (id) => ["venly", "ramp-request", id],
package/dist/queries.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { type UseQueryOptions } from "@tanstack/react-query";
2
+ import { type Page, type Transfer as TransferRow } from "@venlyfinance/sdk";
2
3
  import { venlyQueries, type AccountsQuery, type FeeQuoteInput, type PartiesQuery, type RampRequestsQuery, type TransfersQuery, type VirtualBankAccountsQuery, type WalletsQuery, type CompanyBankAccountsQuery, type CompanyWalletsQuery, type DepositWalletsQuery } from "./query-options.js";
3
4
  type Tune<T> = Omit<UseQueryOptions<T, Error>, "queryKey" | "queryFn">;
4
- export declare function useParties(query?: PartiesQuery, options?: Tune<PartiesPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
5
+ export declare function useParties(query?: PartiesQuery, options?: Tune<PartiesPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
5
6
  id?: string;
6
7
  externalId?: string;
7
8
  partyType?: "INDIVIDUAL" | "ORGANISATION";
@@ -35,7 +36,7 @@ export declare function useParty(partyId: string | undefined, options?: Tune<Par
35
36
  version?: number;
36
37
  }>, Error>;
37
38
  type Party = Awaited<ReturnType<ReturnType<typeof venlyQueries.party>["queryFn"]>>;
38
- export declare function useAccounts(query?: AccountsQuery, options?: Tune<AccountsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
39
+ export declare function useAccounts(query?: AccountsQuery, options?: Tune<AccountsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
39
40
  id?: string;
40
41
  externalId?: string;
41
42
  name?: string;
@@ -55,13 +56,36 @@ export declare function useAccount(accountId: string | undefined, options?: Tune
55
56
  version?: number;
56
57
  }>, Error>;
57
58
  type Account = Awaited<ReturnType<ReturnType<typeof venlyQueries.account>["queryFn"]>>;
58
- export declare function useWallets(accountId: string | undefined, query?: WalletsQuery, options?: Tune<WalletsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
59
+ export declare function useWallets(accountId: string | undefined, query?: WalletsQuery, options?: Tune<WalletsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
59
60
  asset?: string;
60
61
  contractAddress?: string;
61
62
  amount?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["CryptoBalanceSummaryDto"];
62
63
  }>>, Error>;
63
64
  type WalletsPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.wallets>["queryFn"]>>;
64
- export declare function useVirtualBankAccounts(accountId: string | undefined, query?: VirtualBankAccountsQuery, options?: Tune<VibaPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
65
+ /**
66
+ * Tenant-wide supported assets. `decimals` per asset is the render contract
67
+ * for amounts; cached hard (the asset set changes on deploys, not minutes).
68
+ */
69
+ export declare function useSupportedAssets(options?: Tune<SupportedAssetsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
70
+ chain?: "AVALANCHE" | "BASE" | "ETHEREUM" | "POLYGON" | "SOLANA";
71
+ cryptoCurrency?: string;
72
+ decimals?: number;
73
+ contractAddress?: string;
74
+ }>>, Error>;
75
+ type SupportedAssetsPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.supportedAssets>["queryFn"]>>;
76
+ /**
77
+ * Account-scoped supported assets (adds `permitStatus`). Not frozen:
78
+ * permit status moves while an asset activates.
79
+ */
80
+ export declare function useAccountSupportedAssets(accountId: string | undefined, options?: Tune<AccountSupportedAssetsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
81
+ chain?: "AVALANCHE" | "BASE" | "ETHEREUM" | "POLYGON" | "SOLANA";
82
+ cryptoCurrency?: string;
83
+ decimals?: number;
84
+ contractAddress?: string;
85
+ permitStatus?: "READY" | "ACTIVATING" | "ACTION_REQUIRED" | "PENDING" | "FAILED" | "NO_WALLET";
86
+ }>>, Error>;
87
+ type AccountSupportedAssetsPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.accountSupportedAssets>["queryFn"]>>;
88
+ export declare function useVirtualBankAccounts(accountId: string | undefined, query?: VirtualBankAccountsQuery, options?: Tune<VibaPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
65
89
  id?: string;
66
90
  accountId?: string;
67
91
  bankAccountType?: "EUR_SEPA" | "USD_ACH";
@@ -81,7 +105,7 @@ export declare function useVirtualBankAccounts(accountId: string | undefined, qu
81
105
  updatedAt?: string;
82
106
  }>>, Error>;
83
107
  type VibaPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.virtualBankAccounts>["queryFn"]>>;
84
- export declare function useTransfers(accountId: string | undefined, query?: TransfersQuery, options?: Tune<TransfersPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
108
+ export declare function useTransfers(accountId: string | undefined, query?: TransfersQuery, options?: Tune<TransfersPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
85
109
  id?: string;
86
110
  senderAccountId?: string;
87
111
  receiverAccountId?: string;
@@ -99,6 +123,27 @@ export declare function useTransfers(accountId: string | undefined, query?: Tran
99
123
  updatedAt?: string;
100
124
  }>>, Error>;
101
125
  type TransfersPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.transfers>["queryFn"]>>;
126
+ export type TransferPeriod = {
127
+ start: string;
128
+ end: string;
129
+ };
130
+ export type TransfersForPeriodPage = {
131
+ /** Rows whose `createdAt` falls in `[start, end]`. */
132
+ items: TransferRow[];
133
+ /**
134
+ * Every transfer on the account after paging to completion. Opening and
135
+ * closing walk from the current wallet total through this full ledger;
136
+ * a window-only set would silently drop later movements.
137
+ */
138
+ ledger: TransferRow[];
139
+ resultPresent: boolean;
140
+ };
141
+ /**
142
+ * Page every transfer on the account (the list contract has no date filter),
143
+ * then keep the window. `iteratePages` walks `hasNextPage`.
144
+ */
145
+ export declare function collectTransfersForPeriod(list: (query?: TransfersQuery) => Promise<Page<Transfer>>, period: TransferPeriod, pageSize?: number): Promise<TransfersForPeriodPage>;
146
+ export declare function useTransfersForPeriod(accountId: string | undefined, period: TransferPeriod | undefined, options?: Tune<TransfersForPeriodPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<TransfersForPeriodPage>, Error>;
102
147
  export declare function useTransfer(accountId: string | undefined, transferId: string | undefined, options?: Tune<Transfer>): import("@tanstack/react-query").UseQueryResult<NoInfer<{
103
148
  id?: string;
104
149
  senderAccountId?: string;
@@ -117,7 +162,7 @@ export declare function useTransfer(accountId: string | undefined, transferId: s
117
162
  updatedAt?: string;
118
163
  }>, Error>;
119
164
  type Transfer = Awaited<ReturnType<ReturnType<typeof venlyQueries.transfer>["queryFn"]>>;
120
- export declare function useRampRequests(query?: RampRequestsQuery, options?: Tune<RampPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
165
+ export declare function useRampRequests(query?: RampRequestsQuery, options?: Tune<RampPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
121
166
  id?: string;
122
167
  paymentReference?: string;
123
168
  rampType?: "ON_RAMP" | "OFF_RAMP";
@@ -197,7 +242,7 @@ export declare function useFeeQuote(input: FeeQuoteInput | undefined, options?:
197
242
  percentage?: number;
198
243
  }>, Error>;
199
244
  type FeeQuote = Awaited<ReturnType<ReturnType<typeof venlyQueries.feeQuote>["queryFn"]>>;
200
- export declare function useCompanyBankAccounts(query?: CompanyBankAccountsQuery, options?: Tune<BankAccountsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
245
+ export declare function useCompanyBankAccounts(query?: CompanyBankAccountsQuery, options?: Tune<BankAccountsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
201
246
  id?: string;
202
247
  name?: string;
203
248
  bankName?: string;
@@ -245,7 +290,7 @@ export declare function useCompanyBankAccount(id: string | undefined, options?:
245
290
  currency?: string;
246
291
  }>, Error>;
247
292
  type BankAccountDetail = Awaited<ReturnType<ReturnType<typeof venlyQueries.companyBankAccount>["queryFn"]>>;
248
- export declare function useCompanyWallets(query?: CompanyWalletsQuery, options?: Tune<WalletsListPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
293
+ export declare function useCompanyWallets(query?: CompanyWalletsQuery, options?: Tune<WalletsListPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
249
294
  id?: string;
250
295
  description?: string;
251
296
  address?: string;
package/dist/queries.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { useQuery } from "@tanstack/react-query";
2
+ import { iteratePages } from "@venlyfinance/sdk";
2
3
  import { useVenly } from "./provider.js";
3
4
  import { venlyQueries, } from "./query-options.js";
5
+ import { venlyKeys } from "./keys.js";
4
6
  export function useParties(query, options) {
5
7
  const clients = useVenly();
6
8
  return useQuery({ ...venlyQueries.parties(clients, query), ...options });
@@ -33,6 +35,30 @@ export function useWallets(accountId, query, options) {
33
35
  ...options,
34
36
  });
35
37
  }
38
+ /**
39
+ * Tenant-wide supported assets. `decimals` per asset is the render contract
40
+ * for amounts; cached hard (the asset set changes on deploys, not minutes).
41
+ */
42
+ export function useSupportedAssets(options) {
43
+ const clients = useVenly();
44
+ return useQuery({
45
+ ...venlyQueries.supportedAssets(clients),
46
+ staleTime: Infinity,
47
+ ...options,
48
+ });
49
+ }
50
+ /**
51
+ * Account-scoped supported assets (adds `permitStatus`). Not frozen:
52
+ * permit status moves while an asset activates.
53
+ */
54
+ export function useAccountSupportedAssets(accountId, options) {
55
+ const clients = useVenly();
56
+ return useQuery({
57
+ ...venlyQueries.accountSupportedAssets(clients, accountId ?? ""),
58
+ enabled: Boolean(accountId) && (options?.enabled ?? true),
59
+ ...options,
60
+ });
61
+ }
36
62
  export function useVirtualBankAccounts(accountId, query, options) {
37
63
  const clients = useVenly();
38
64
  return useQuery({
@@ -49,6 +75,34 @@ export function useTransfers(accountId, query, options) {
49
75
  ...options,
50
76
  });
51
77
  }
78
+ /**
79
+ * Page every transfer on the account (the list contract has no date filter),
80
+ * then keep the window. `iteratePages` walks `hasNextPage`.
81
+ */
82
+ export async function collectTransfersForPeriod(list, period, pageSize = 20) {
83
+ const ledger = [];
84
+ for await (const item of iteratePages((params) => list({ page: params.page, size: params.size }), {
85
+ size: pageSize,
86
+ })) {
87
+ ledger.push(item);
88
+ }
89
+ const items = ledger.filter((transfer) => {
90
+ const at = transfer.createdAt;
91
+ return Boolean(at && at >= period.start && at <= period.end);
92
+ });
93
+ return { items, ledger, resultPresent: true };
94
+ }
95
+ export function useTransfersForPeriod(accountId, period, options) {
96
+ const clients = useVenly();
97
+ const start = period?.start ?? "";
98
+ const end = period?.end ?? "";
99
+ return useQuery({
100
+ queryKey: venlyKeys.transfersForPeriod(accountId ?? "", { start, end }),
101
+ queryFn: () => collectTransfersForPeriod((query) => clients.finance.transfers.list(accountId ?? "", query), { start, end }),
102
+ enabled: Boolean(accountId && start && end) && (options?.enabled ?? true),
103
+ ...options,
104
+ });
105
+ }
52
106
  export function useTransfer(accountId, transferId, options) {
53
107
  const clients = useVenly();
54
108
  return useQuery({
@@ -86,6 +86,27 @@ export declare const venlyQueries: {
86
86
  amount?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["CryptoBalanceSummaryDto"];
87
87
  }>>;
88
88
  };
89
+ /** Tenant-wide supported assets, each with its on-chain `decimals`. */
90
+ readonly supportedAssets: (clients: VenlyClients) => {
91
+ queryKey: readonly ["venly", "supported-assets"];
92
+ queryFn: () => Promise<import("@venlyfinance/sdk").Page<{
93
+ chain?: "AVALANCHE" | "BASE" | "ETHEREUM" | "POLYGON" | "SOLANA";
94
+ cryptoCurrency?: string;
95
+ decimals?: number;
96
+ contractAddress?: string;
97
+ }>>;
98
+ };
99
+ /** Account-scoped rows: the same assets plus per-asset `permitStatus`. */
100
+ readonly accountSupportedAssets: (clients: VenlyClients, accountId: string) => {
101
+ queryKey: readonly ["venly", "account", string, "supported-assets"];
102
+ queryFn: () => Promise<import("@venlyfinance/sdk").Page<{
103
+ chain?: "AVALANCHE" | "BASE" | "ETHEREUM" | "POLYGON" | "SOLANA";
104
+ cryptoCurrency?: string;
105
+ decimals?: number;
106
+ contractAddress?: string;
107
+ permitStatus?: "READY" | "ACTIVATING" | "ACTION_REQUIRED" | "PENDING" | "FAILED" | "NO_WALLET";
108
+ }>>;
109
+ };
89
110
  readonly virtualBankAccounts: (clients: VenlyClients, accountId: string, query?: VirtualBankAccountsQuery) => {
90
111
  queryKey: readonly ["venly", "account", string, "virtual-bank-accounts", {} | null];
91
112
  queryFn: () => Promise<import("@venlyfinance/sdk").Page<{
@@ -25,6 +25,16 @@ export const venlyQueries = {
25
25
  queryKey: venlyKeys.wallets(accountId, query),
26
26
  queryFn: () => clients.finance.wallets.list(accountId, query),
27
27
  }),
28
+ /** Tenant-wide supported assets, each with its on-chain `decimals`. */
29
+ supportedAssets: (clients) => ({
30
+ queryKey: venlyKeys.supportedAssets(),
31
+ queryFn: () => clients.finance.supportedAssets.list(),
32
+ }),
33
+ /** Account-scoped rows: the same assets plus per-asset `permitStatus`. */
34
+ accountSupportedAssets: (clients, accountId) => ({
35
+ queryKey: venlyKeys.accountSupportedAssets(accountId),
36
+ queryFn: () => clients.finance.supportedAssets.listForAccount(accountId),
37
+ }),
28
38
  virtualBankAccounts: (clients, accountId, query) => ({
29
39
  queryKey: venlyKeys.virtualBankAccounts(accountId, query),
30
40
  queryFn: () => clients.finance.virtualBankAccounts.list(accountId, query),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venlyfinance/react",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Headless React layer for the Venly Finance and Fundflow APIs: provider, TanStack Query hooks, and flow state machines for regulated money movement. Runs with zero credentials in mock mode.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "node": ">=20"
31
31
  },
32
32
  "dependencies": {
33
- "@venlyfinance/sdk": "^0.4.0"
33
+ "@venlyfinance/sdk": "^0.5.0"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "@tanstack/react-query": "^5.0.0",
@@ -62,4 +62,4 @@
62
62
  "directory": "react"
63
63
  },
64
64
  "homepage": "https://github.com/Venly/venly-settlement-sdk/tree/main/react#readme"
65
- }
65
+ }