@venlyfinance/react 0.4.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/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, useSupportedAssets, useAccountSupportedAssets, } 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, useSupportedAssets, useAccountSupportedAssets, } 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
@@ -13,6 +13,10 @@ export declare const venlyKeys: {
13
13
  readonly accountSupportedAssets: (accountId: string) => readonly ["venly", "account", string, "supported-assets"];
14
14
  readonly virtualBankAccounts: (accountId: string, query?: unknown) => readonly ["venly", "account", string, "virtual-bank-accounts", {} | null];
15
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];
16
20
  readonly transfer: (accountId: string, transferId: string) => readonly ["venly", "account", string, "transfer", string];
17
21
  readonly rampRequests: (query?: unknown) => readonly ["venly", "ramp-requests", {} | null];
18
22
  readonly rampRequest: (id: string) => readonly ["venly", "ramp-request", string];
package/dist/keys.js CHANGED
@@ -13,6 +13,7 @@ export const venlyKeys = {
13
13
  accountSupportedAssets: (accountId) => ["venly", "account", accountId, "supported-assets"],
14
14
  virtualBankAccounts: (accountId, query) => ["venly", "account", accountId, "virtual-bank-accounts", query ?? null],
15
15
  transfers: (accountId, query) => ["venly", "account", accountId, "transfers", query ?? null],
16
+ transfersForPeriod: (accountId, period) => ["venly", "account", accountId, "transfers-for-period", period.start, period.end],
16
17
  transfer: (accountId, transferId) => ["venly", "account", accountId, "transfer", transferId],
17
18
  rampRequests: (query) => ["venly", "ramp-requests", query ?? null],
18
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,7 +56,7 @@ 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"];
@@ -65,7 +66,7 @@ type WalletsPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.wallets>["q
65
66
  * Tenant-wide supported assets. `decimals` per asset is the render contract
66
67
  * for amounts; cached hard (the asset set changes on deploys, not minutes).
67
68
  */
68
- export declare function useSupportedAssets(options?: Tune<SupportedAssetsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
69
+ export declare function useSupportedAssets(options?: Tune<SupportedAssetsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
69
70
  chain?: "AVALANCHE" | "BASE" | "ETHEREUM" | "POLYGON" | "SOLANA";
70
71
  cryptoCurrency?: string;
71
72
  decimals?: number;
@@ -76,7 +77,7 @@ type SupportedAssetsPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.sup
76
77
  * Account-scoped supported assets (adds `permitStatus`). Not frozen:
77
78
  * permit status moves while an asset activates.
78
79
  */
79
- export declare function useAccountSupportedAssets(accountId: string | undefined, options?: Tune<AccountSupportedAssetsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
80
+ export declare function useAccountSupportedAssets(accountId: string | undefined, options?: Tune<AccountSupportedAssetsPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
80
81
  chain?: "AVALANCHE" | "BASE" | "ETHEREUM" | "POLYGON" | "SOLANA";
81
82
  cryptoCurrency?: string;
82
83
  decimals?: number;
@@ -84,7 +85,7 @@ export declare function useAccountSupportedAssets(accountId: string | undefined,
84
85
  permitStatus?: "READY" | "ACTIVATING" | "ACTION_REQUIRED" | "PENDING" | "FAILED" | "NO_WALLET";
85
86
  }>>, Error>;
86
87
  type AccountSupportedAssetsPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.accountSupportedAssets>["queryFn"]>>;
87
- export declare function useVirtualBankAccounts(accountId: string | undefined, query?: VirtualBankAccountsQuery, options?: Tune<VibaPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<import("@venlyfinance/sdk").Page<{
88
+ export declare function useVirtualBankAccounts(accountId: string | undefined, query?: VirtualBankAccountsQuery, options?: Tune<VibaPage>): import("@tanstack/react-query").UseQueryResult<NoInfer<Page<{
88
89
  id?: string;
89
90
  accountId?: string;
90
91
  bankAccountType?: "EUR_SEPA" | "USD_ACH";
@@ -104,7 +105,7 @@ export declare function useVirtualBankAccounts(accountId: string | undefined, qu
104
105
  updatedAt?: string;
105
106
  }>>, Error>;
106
107
  type VibaPage = Awaited<ReturnType<ReturnType<typeof venlyQueries.virtualBankAccounts>["queryFn"]>>;
107
- 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<{
108
109
  id?: string;
109
110
  senderAccountId?: string;
110
111
  receiverAccountId?: string;
@@ -122,6 +123,27 @@ export declare function useTransfers(accountId: string | undefined, query?: Tran
122
123
  updatedAt?: string;
123
124
  }>>, Error>;
124
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>;
125
147
  export declare function useTransfer(accountId: string | undefined, transferId: string | undefined, options?: Tune<Transfer>): import("@tanstack/react-query").UseQueryResult<NoInfer<{
126
148
  id?: string;
127
149
  senderAccountId?: string;
@@ -140,7 +162,7 @@ export declare function useTransfer(accountId: string | undefined, transferId: s
140
162
  updatedAt?: string;
141
163
  }>, Error>;
142
164
  type Transfer = Awaited<ReturnType<ReturnType<typeof venlyQueries.transfer>["queryFn"]>>;
143
- 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<{
144
166
  id?: string;
145
167
  paymentReference?: string;
146
168
  rampType?: "ON_RAMP" | "OFF_RAMP";
@@ -220,7 +242,7 @@ export declare function useFeeQuote(input: FeeQuoteInput | undefined, options?:
220
242
  percentage?: number;
221
243
  }>, Error>;
222
244
  type FeeQuote = Awaited<ReturnType<ReturnType<typeof venlyQueries.feeQuote>["queryFn"]>>;
223
- 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<{
224
246
  id?: string;
225
247
  name?: string;
226
248
  bankName?: string;
@@ -268,7 +290,7 @@ export declare function useCompanyBankAccount(id: string | undefined, options?:
268
290
  currency?: string;
269
291
  }>, Error>;
270
292
  type BankAccountDetail = Awaited<ReturnType<ReturnType<typeof venlyQueries.companyBankAccount>["queryFn"]>>;
271
- 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<{
272
294
  id?: string;
273
295
  description?: string;
274
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 });
@@ -73,6 +75,34 @@ export function useTransfers(accountId, query, options) {
73
75
  ...options,
74
76
  });
75
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
+ }
76
106
  export function useTransfer(accountId, transferId, options) {
77
107
  const clients = useVenly();
78
108
  return useQuery({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venlyfinance/react",
3
- "version": "0.4.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",