@venlyfinance/react 0.1.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.
@@ -0,0 +1,114 @@
1
+ import type { Transfer, VenlyFinanceClient } from "@venlyfinance/sdk";
2
+ import { type VenlyClients } from "../provider.js";
3
+ type CreateFiatBody = Parameters<VenlyFinanceClient["transfers"]["createFiat"]>[1];
4
+ type CreateCryptoBody = Parameters<VenlyFinanceClient["transfers"]["createCrypto"]>[1];
5
+ /**
6
+ * The API contract requires an idempotencyKey on the create body; in this
7
+ * machine the key is pinned by stage(), so drafts may omit it (a provided
8
+ * key is honoured and pinned instead).
9
+ */
10
+ type DraftBody<B extends {
11
+ idempotencyKey: string;
12
+ }> = Omit<B, "idempotencyKey"> & {
13
+ idempotencyKey?: string;
14
+ };
15
+ /** What the operator is composing. Discriminated on the money rail. */
16
+ export type TransferDraft = {
17
+ kind: "fiat";
18
+ senderAccountId: string;
19
+ body: DraftBody<CreateFiatBody>;
20
+ } | {
21
+ kind: "crypto";
22
+ senderAccountId: string;
23
+ body: DraftBody<CreateCryptoBody>;
24
+ };
25
+ /**
26
+ * The exact request that will be sent on confirm. The idempotency key is
27
+ * pinned at staging time: however many times confirm() is retried (double
28
+ * click, flaky network, impatient operator), the API can only execute the
29
+ * movement once. This mirrors the settlement MCP's stage-then-confirm write
30
+ * gate, where the dry-run answer IS the request that later executes.
31
+ */
32
+ export interface StagedRequest {
33
+ draft: TransferDraft;
34
+ idempotencyKey: string;
35
+ stagedAt: string;
36
+ }
37
+ export type StagedTransferState = {
38
+ phase: "draft";
39
+ issues: string[];
40
+ } | {
41
+ phase: "staged";
42
+ staged: StagedRequest;
43
+ } | {
44
+ phase: "submitting";
45
+ staged: StagedRequest;
46
+ } | {
47
+ phase: "pending";
48
+ staged: StagedRequest;
49
+ transfer: Transfer;
50
+ } | {
51
+ phase: "completed";
52
+ staged: StagedRequest;
53
+ transfer: Transfer;
54
+ } | {
55
+ phase: "failed";
56
+ staged?: StagedRequest;
57
+ transfer?: Transfer;
58
+ error?: unknown;
59
+ reason: "submit-error" | "transfer-failed" | "poll-timeout";
60
+ };
61
+ /**
62
+ * Structural validation only: presence and sign, never business rules the
63
+ * API owns (limits, compliance, balance). A draft that passes here can still
64
+ * be rejected server-side; that surfaces as phase "failed".
65
+ */
66
+ export declare function validateDraft(draft: TransferDraft): string[];
67
+ export interface StagedTransferOptions {
68
+ /** Poll interval for status while the transfer is PENDING. Default 1500ms. */
69
+ pollIntervalMs?: number;
70
+ /** Give up polling after this long and report "poll-timeout". Default 120s. */
71
+ maxPollMs?: number;
72
+ }
73
+ /**
74
+ * Framework-agnostic core of the stage-then-confirm machine, so the whole
75
+ * lifecycle is testable without a DOM. The React hook below is a thin
76
+ * subscription over this class.
77
+ *
78
+ * draft → stage() → staged → confirm() → submitting → pending → completed
79
+ * │ ↑ ↘ failed
80
+ * edit() └──────────────────────────────────────┘
81
+ */
82
+ export declare class StagedTransferController {
83
+ #private;
84
+ private readonly clients;
85
+ private readonly options;
86
+ constructor(clients: VenlyClients, options?: StagedTransferOptions);
87
+ subscribe: (listener: () => void) => (() => void);
88
+ getSnapshot: () => StagedTransferState;
89
+ /** Validate and freeze the draft; pins the idempotency key. */
90
+ stage(draft: TransferDraft): boolean;
91
+ /** Back to composing; the staged request (and its key) is discarded. */
92
+ edit(): void;
93
+ reset(): void;
94
+ /** Execute the staged request, then poll until the transfer is terminal. */
95
+ confirm(): Promise<void>;
96
+ dispose(): void;
97
+ }
98
+ /**
99
+ * Stage-then-confirm transfer flow.
100
+ *
101
+ * ```tsx
102
+ * const t = useStagedTransfer();
103
+ * t.stage({ kind: "fiat", senderAccountId, body }); // review screen renders t.state.staged
104
+ * await t.confirm(); // executes once, then polls to terminal
105
+ * ```
106
+ */
107
+ export declare function useStagedTransfer(options?: StagedTransferOptions): {
108
+ state: StagedTransferState;
109
+ stage: (draft: TransferDraft) => boolean;
110
+ edit: () => void;
111
+ confirm: () => Promise<void>;
112
+ reset: () => void;
113
+ };
114
+ export {};
@@ -0,0 +1,182 @@
1
+ import { useEffect, useRef, useSyncExternalStore } from "react";
2
+ import { useVenly } from "../provider.js";
3
+ /**
4
+ * Structural validation only: presence and sign, never business rules the
5
+ * API owns (limits, compliance, balance). A draft that passes here can still
6
+ * be rejected server-side; that surfaces as phase "failed".
7
+ */
8
+ export function validateDraft(draft) {
9
+ const issues = [];
10
+ if (!draft.senderAccountId)
11
+ issues.push("senderAccountId is required");
12
+ if (!draft.body) {
13
+ issues.push("body is required");
14
+ return issues;
15
+ }
16
+ const amount = draft.body.amount;
17
+ if (typeof amount === "number" && !(amount > 0)) {
18
+ issues.push("amount must be greater than zero");
19
+ }
20
+ if (draft.kind === "fiat" && !draft.body.currency) {
21
+ issues.push("currency is required for a fiat transfer");
22
+ }
23
+ if (draft.kind === "crypto") {
24
+ if (!draft.body.asset)
25
+ issues.push("asset is required for a crypto transfer");
26
+ if (!draft.body.chain)
27
+ issues.push("chain is required for a crypto transfer");
28
+ }
29
+ return issues;
30
+ }
31
+ const INITIAL = { phase: "draft", issues: [] };
32
+ /**
33
+ * Framework-agnostic core of the stage-then-confirm machine, so the whole
34
+ * lifecycle is testable without a DOM. The React hook below is a thin
35
+ * subscription over this class.
36
+ *
37
+ * draft → stage() → staged → confirm() → submitting → pending → completed
38
+ * │ ↑ ↘ failed
39
+ * edit() └──────────────────────────────────────┘
40
+ */
41
+ export class StagedTransferController {
42
+ clients;
43
+ options;
44
+ #state = INITIAL;
45
+ #listeners = new Set();
46
+ #disposed = false;
47
+ #pollTimer;
48
+ constructor(clients, options = {}) {
49
+ this.clients = clients;
50
+ this.options = options;
51
+ }
52
+ subscribe = (listener) => {
53
+ this.#listeners.add(listener);
54
+ return () => this.#listeners.delete(listener);
55
+ };
56
+ getSnapshot = () => this.#state;
57
+ /** Validate and freeze the draft; pins the idempotency key. */
58
+ stage(draft) {
59
+ const issues = validateDraft(draft);
60
+ if (issues.length > 0) {
61
+ this.#set({ phase: "draft", issues });
62
+ return false;
63
+ }
64
+ const bodyKey = draft.body.idempotencyKey;
65
+ this.#set({
66
+ phase: "staged",
67
+ staged: {
68
+ draft,
69
+ idempotencyKey: bodyKey ?? crypto.randomUUID(),
70
+ stagedAt: new Date().toISOString(),
71
+ },
72
+ });
73
+ return true;
74
+ }
75
+ /** Back to composing; the staged request (and its key) is discarded. */
76
+ edit() {
77
+ if (this.#state.phase === "staged")
78
+ this.#set(INITIAL);
79
+ }
80
+ reset() {
81
+ this.#clearPoll();
82
+ this.#set(INITIAL);
83
+ }
84
+ /** Execute the staged request, then poll until the transfer is terminal. */
85
+ async confirm() {
86
+ if (this.#state.phase !== "staged")
87
+ return;
88
+ const staged = this.#state.staged;
89
+ this.#set({ phase: "submitting", staged });
90
+ let transfer;
91
+ try {
92
+ const { draft, idempotencyKey } = staged;
93
+ transfer =
94
+ draft.kind === "fiat"
95
+ ? await this.clients.finance.transfers.createFiat(draft.senderAccountId, { ...draft.body, idempotencyKey })
96
+ : await this.clients.finance.transfers.createCrypto(draft.senderAccountId, { ...draft.body, idempotencyKey });
97
+ }
98
+ catch (error) {
99
+ this.#set({ phase: "failed", staged, error, reason: "submit-error" });
100
+ return;
101
+ }
102
+ if (this.#disposed)
103
+ return;
104
+ const next = this.#applyTransfer(staged, transfer);
105
+ if (next.phase === "pending") {
106
+ this.#poll(staged, transfer, Date.now());
107
+ }
108
+ }
109
+ dispose() {
110
+ this.#disposed = true;
111
+ this.#clearPoll();
112
+ this.#listeners.clear();
113
+ }
114
+ #applyTransfer(staged, transfer) {
115
+ const next = transfer.status === "COMPLETED"
116
+ ? { phase: "completed", staged, transfer }
117
+ : transfer.status === "FAILED"
118
+ ? { phase: "failed", staged, transfer, reason: "transfer-failed" }
119
+ : { phase: "pending", staged, transfer };
120
+ this.#set(next);
121
+ return next;
122
+ }
123
+ #poll(staged, transfer, startedAt) {
124
+ const interval = this.options.pollIntervalMs ?? 1_500;
125
+ const maxPollMs = this.options.maxPollMs ?? 120_000;
126
+ this.#pollTimer = setTimeout(async () => {
127
+ if (this.#disposed)
128
+ return;
129
+ if (Date.now() - startedAt > maxPollMs) {
130
+ this.#set({ phase: "failed", staged, transfer, reason: "poll-timeout" });
131
+ return;
132
+ }
133
+ try {
134
+ const fresh = await this.clients.finance.transfers.get(staged.draft.senderAccountId, transfer.id ?? "");
135
+ if (this.#disposed)
136
+ return;
137
+ const next = this.#applyTransfer(staged, fresh);
138
+ if (next.phase === "pending")
139
+ this.#poll(staged, fresh, startedAt);
140
+ }
141
+ catch {
142
+ // Transient read failure: keep the last known state and try again.
143
+ if (!this.#disposed)
144
+ this.#poll(staged, transfer, startedAt);
145
+ }
146
+ }, interval);
147
+ }
148
+ #clearPoll() {
149
+ if (this.#pollTimer !== undefined)
150
+ clearTimeout(this.#pollTimer);
151
+ this.#pollTimer = undefined;
152
+ }
153
+ #set(state) {
154
+ this.#state = state;
155
+ for (const listener of this.#listeners)
156
+ listener();
157
+ }
158
+ }
159
+ /**
160
+ * Stage-then-confirm transfer flow.
161
+ *
162
+ * ```tsx
163
+ * const t = useStagedTransfer();
164
+ * t.stage({ kind: "fiat", senderAccountId, body }); // review screen renders t.state.staged
165
+ * await t.confirm(); // executes once, then polls to terminal
166
+ * ```
167
+ */
168
+ export function useStagedTransfer(options) {
169
+ const clients = useVenly();
170
+ const ref = useRef(null);
171
+ ref.current ??= new StagedTransferController(clients, options);
172
+ const controller = ref.current;
173
+ useEffect(() => () => controller.dispose(), [controller]);
174
+ const state = useSyncExternalStore(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
175
+ return {
176
+ state,
177
+ stage: (draft) => controller.stage(draft),
178
+ edit: () => controller.edit(),
179
+ confirm: () => controller.confirm(),
180
+ reset: () => controller.reset(),
181
+ };
182
+ }
@@ -0,0 +1,11 @@
1
+ export { VenlyProvider, useVenly, useVenlyMock, type VenlyClients, type VenlyProviderProps, type VenlyReactEnvironment, } from "./provider.js";
2
+ export { venlyKeys } from "./keys.js";
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, } from "./queries.js";
5
+ export { useCreateAccount, useCreateParty, useCreatePaymentSession, useCreateRampRequest, useCreateVirtualBankAccount, } from "./mutations.js";
6
+ export { StagedTransferController, useStagedTransfer, validateDraft, type StagedRequest, type StagedTransferOptions, type StagedTransferState, type TransferDraft, } from "./flows/staged-transfer.js";
7
+ export { approvalCapabilities, interpretApprovalError, useFourEyesApproval, type ApprovalCapability, type ApprovalFailureKind, type FourEyesState, } from "./flows/four-eyes.js";
8
+ export { describeRampStatus, useRampLifecycle, type RampLifecycleOptions, type RampStatus, type RampStatusDescriptor, } from "./flows/ramp-lifecycle.js";
9
+ export { proxyClientOptions, VENLY_PROXY_SECRET_SENTINEL, type ProxyClientOptions, } from "./proxy.js";
10
+ export { FundflowClient, VenlyApiError, VenlyAuthError, VenlyFinanceClient, } from "@venlyfinance/sdk";
11
+ export type { Account, Party, RampRequest, Transfer, VirtualBankAccount, Wallet, } from "@venlyfinance/sdk";
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ // Provider + context
2
+ export { VenlyProvider, useVenly, useVenlyMock, } from "./provider.js";
3
+ // Query keys + pure query factories (prefetching, loaders, tests)
4
+ export { venlyKeys } from "./keys.js";
5
+ export { venlyQueries, } from "./query-options.js";
6
+ // Read hooks
7
+ export { useAccount, useAccounts, useCompanyFees, useFeeQuote, useParties, useParty, useRampRequest, useRampRequests, useReferenceData, useTransfer, useTransfers, useVirtualBankAccounts, useWallets, } from "./queries.js";
8
+ // Write hooks
9
+ export { useCreateAccount, useCreateParty, useCreatePaymentSession, useCreateRampRequest, useCreateVirtualBankAccount, } from "./mutations.js";
10
+ // Flow machines: the regulated-money lifecycles
11
+ export { StagedTransferController, useStagedTransfer, validateDraft, } from "./flows/staged-transfer.js";
12
+ export { approvalCapabilities, interpretApprovalError, useFourEyesApproval, } from "./flows/four-eyes.js";
13
+ export { describeRampStatus, useRampLifecycle, } from "./flows/ramp-lifecycle.js";
14
+ // Browser-safe deployment shape
15
+ export { proxyClientOptions, VENLY_PROXY_SECRET_SENTINEL, } from "./proxy.js";
16
+ // Re-export the SDK surface consumers need alongside the hooks, so app code
17
+ // can import one package. The SDK remains the canonical home.
18
+ export { FundflowClient, VenlyApiError, VenlyAuthError, VenlyFinanceClient, } from "@venlyfinance/sdk";
package/dist/keys.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Query-key factory. Every hook and every cache invalidation goes through
3
+ * this object so keys can never drift apart. Keys are plain JSON values.
4
+ */
5
+ export declare const venlyKeys: {
6
+ readonly all: readonly ["venly"];
7
+ readonly parties: (query?: unknown) => readonly ["venly", "parties", {} | null];
8
+ readonly party: (partyId: string) => readonly ["venly", "party", string];
9
+ readonly accounts: (query?: unknown) => readonly ["venly", "accounts", {} | null];
10
+ readonly account: (accountId: string) => readonly ["venly", "account", string];
11
+ readonly wallets: (accountId: string, query?: unknown) => readonly ["venly", "account", string, "wallets", {} | null];
12
+ readonly virtualBankAccounts: (accountId: string, query?: unknown) => readonly ["venly", "account", string, "virtual-bank-accounts", {} | null];
13
+ readonly transfers: (accountId: string, query?: unknown) => readonly ["venly", "account", string, "transfers", {} | null];
14
+ readonly transfer: (accountId: string, transferId: string) => readonly ["venly", "account", string, "transfer", string];
15
+ readonly rampRequests: (query?: unknown) => readonly ["venly", "ramp-requests", {} | null];
16
+ readonly rampRequest: (id: string) => readonly ["venly", "ramp-request", string];
17
+ readonly referenceData: () => readonly ["venly", "reference-data"];
18
+ readonly companyFees: () => readonly ["venly", "company-fees"];
19
+ readonly feeQuote: (input: unknown) => readonly ["venly", "fee-quote", unknown];
20
+ };
package/dist/keys.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Query-key factory. Every hook and every cache invalidation goes through
3
+ * this object so keys can never drift apart. Keys are plain JSON values.
4
+ */
5
+ export const venlyKeys = {
6
+ all: ["venly"],
7
+ parties: (query) => ["venly", "parties", query ?? null],
8
+ party: (partyId) => ["venly", "party", partyId],
9
+ accounts: (query) => ["venly", "accounts", query ?? null],
10
+ account: (accountId) => ["venly", "account", accountId],
11
+ wallets: (accountId, query) => ["venly", "account", accountId, "wallets", query ?? null],
12
+ virtualBankAccounts: (accountId, query) => ["venly", "account", accountId, "virtual-bank-accounts", query ?? null],
13
+ transfers: (accountId, query) => ["venly", "account", accountId, "transfers", query ?? null],
14
+ transfer: (accountId, transferId) => ["venly", "account", accountId, "transfer", transferId],
15
+ rampRequests: (query) => ["venly", "ramp-requests", query ?? null],
16
+ rampRequest: (id) => ["venly", "ramp-request", id],
17
+ referenceData: () => ["venly", "reference-data"],
18
+ companyFees: () => ["venly", "company-fees"],
19
+ feeQuote: (input) => ["venly", "fee-quote", input],
20
+ };
@@ -0,0 +1,123 @@
1
+ import type { VenlyFinanceClient } from "@venlyfinance/sdk";
2
+ type CreateVibaBody = Parameters<VenlyFinanceClient["virtualBankAccounts"]["create"]>[1];
3
+ type CreatePaymentSessionBody = Parameters<VenlyFinanceClient["paymentSessions"]["create"]>[1];
4
+ /** Create a party (individual or organisation), then refresh party lists. */
5
+ export declare function useCreateParty(): import("@tanstack/react-query").UseMutationResult<{
6
+ id?: string;
7
+ externalId?: string;
8
+ partyType?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["PartyType"];
9
+ status?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["PartyStatus"];
10
+ firstName?: string;
11
+ lastName?: string;
12
+ kycStatus?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["KycStatus"];
13
+ name?: string;
14
+ vatNumber?: string;
15
+ kybStatus?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["KybStatus"];
16
+ address?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["Address"];
17
+ createdAt?: string;
18
+ updatedAt?: string;
19
+ version?: number;
20
+ }, Error, {
21
+ partyType: import("@venlyfinance/sdk").FinanceComponents["schemas"]["PartyType"];
22
+ externalId?: string;
23
+ firstName?: string;
24
+ lastName?: string;
25
+ name?: string;
26
+ vatNumber?: string;
27
+ address?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["Address"];
28
+ }, unknown>;
29
+ export declare function useCreateAccount(): import("@tanstack/react-query").UseMutationResult<{
30
+ id?: string;
31
+ externalId?: string;
32
+ name?: string;
33
+ kycStatus?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["KycStatus"];
34
+ status?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["AccountStatus"];
35
+ createdAt?: string;
36
+ version?: number;
37
+ }, Error, {
38
+ externalId: string;
39
+ name?: string;
40
+ chain: import("@venlyfinance/sdk").FinanceComponents["schemas"]["BlockchainNetwork"];
41
+ address?: string;
42
+ partyId?: string;
43
+ party?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["CreatePartyRequest"];
44
+ cardProviderReference?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["CardProviderReference"];
45
+ }, unknown>;
46
+ export declare function useCreateVirtualBankAccount(): import("@tanstack/react-query").UseMutationResult<{
47
+ id?: string;
48
+ accountId?: string;
49
+ bankAccountType?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["BankAccountType"];
50
+ name?: string;
51
+ status?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["VirtualBankAccountStatus"];
52
+ currency?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["FiatCurrency"];
53
+ targetCryptocurrency?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["Cryptocurrency"];
54
+ iban?: string;
55
+ bic?: string;
56
+ bankName?: string;
57
+ beneficiaryName?: string;
58
+ referenceCode?: string;
59
+ createdAt?: string;
60
+ updatedAt?: string;
61
+ }, Error, {
62
+ accountId: string;
63
+ body: CreateVibaBody;
64
+ }, unknown>;
65
+ export declare function useCreatePaymentSession(): import("@tanstack/react-query").UseMutationResult<{
66
+ id?: string;
67
+ accountId?: string;
68
+ status?: import("@venlyfinance/sdk").FinanceComponents["schemas"]["PaymentSessionStatus"];
69
+ inAmount?: number;
70
+ inCurrency?: string;
71
+ outCryptocurrency?: string;
72
+ paymentUrl?: string;
73
+ externalRef?: string;
74
+ walletId?: string;
75
+ blockchainTxId?: string | null;
76
+ cancellable?: boolean;
77
+ expiresAt?: string;
78
+ metadata?: {
79
+ [key: string]: string;
80
+ };
81
+ idempotencyKey?: string;
82
+ createdAt?: string;
83
+ updatedAt?: string;
84
+ }, Error, {
85
+ accountId: string;
86
+ body: CreatePaymentSessionBody;
87
+ }, unknown>;
88
+ export declare function useCreateRampRequest(): import("@tanstack/react-query").UseMutationResult<{
89
+ id?: string;
90
+ companyId?: string;
91
+ companyName?: string;
92
+ rampType?: "ON_RAMP" | "OFF_RAMP";
93
+ status?: "AWAITING_APPROVAL" | "AWAITING_FUNDS" | "PROCESSING" | "SUCCEEDED" | "FAILED" | "BLOCKED" | "DENIED" | "REJECTED" | "CANCELLED";
94
+ amount?: number;
95
+ netAmount?: number;
96
+ fiatAmount?: number;
97
+ fiatNetAmount?: number;
98
+ cryptoAmount?: number;
99
+ fiatFeeAmount?: number;
100
+ exchangeRate?: number;
101
+ feePercentage?: number;
102
+ paymentReference?: string;
103
+ paymentReceived?: boolean;
104
+ blockchainTransactionHash?: string;
105
+ createdAt?: string;
106
+ companyBankAccount?: import("@venlyfinance/sdk").FundflowComponents["schemas"]["EurSepaCompanyBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["GbpChapsCompanyBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["GbpFpsCompanyBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["OtherCurrencySwiftCompanyBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["UsAchCompanyBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["UsSwiftCompanyBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["UsWireCompanyBankAccountDto"];
107
+ companyWallet?: import("@venlyfinance/sdk").FundflowComponents["schemas"]["CompanyWalletDto"];
108
+ depositBankAccount?: import("@venlyfinance/sdk").FundflowComponents["schemas"]["EurSepaDepositBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["GbpChapsDepositBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["GbpFpsDepositBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["OtherCurrencySwiftDepositBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["UsAchDepositBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["UsSwiftDepositBankAccountDto"] | import("@venlyfinance/sdk").FundflowComponents["schemas"]["UsWireDepositBankAccountDto"];
109
+ depositWallet?: import("@venlyfinance/sdk").FundflowComponents["schemas"]["DepositWalletDto"];
110
+ fiatCurrency?: import("@venlyfinance/sdk").FundflowComponents["schemas"]["FiatCurrencyDto"];
111
+ cryptoCurrency?: import("@venlyfinance/sdk").FundflowComponents["schemas"]["CryptoCurrencyDto"];
112
+ events?: import("@venlyfinance/sdk").FundflowComponents["schemas"]["RampRequestEventDto"][];
113
+ version?: number;
114
+ amountReceived?: number;
115
+ }, Error, {
116
+ rampType: "ON_RAMP" | "OFF_RAMP";
117
+ amount: number;
118
+ companyBankAccountId?: string;
119
+ companyWalletId?: string;
120
+ fiatCurrencyId: string;
121
+ cryptoCurrencyId: string;
122
+ }, unknown>;
123
+ export {};
@@ -0,0 +1,58 @@
1
+ import { useMutation, useQueryClient } from "@tanstack/react-query";
2
+ import { useVenly } from "./provider.js";
3
+ import { venlyKeys } from "./keys.js";
4
+ /** Create a party (individual or organisation), then refresh party lists. */
5
+ export function useCreateParty() {
6
+ const { finance } = useVenly();
7
+ const queryClient = useQueryClient();
8
+ return useMutation({
9
+ mutationFn: (body) => finance.parties.create(body),
10
+ onSuccess: (party) => {
11
+ if (party.id)
12
+ queryClient.setQueryData(venlyKeys.party(party.id), party);
13
+ void queryClient.invalidateQueries({ queryKey: ["venly", "parties"] });
14
+ },
15
+ });
16
+ }
17
+ export function useCreateAccount() {
18
+ const { finance } = useVenly();
19
+ const queryClient = useQueryClient();
20
+ return useMutation({
21
+ mutationFn: (body) => finance.accounts.create(body),
22
+ onSuccess: (account) => {
23
+ if (account.id)
24
+ queryClient.setQueryData(venlyKeys.account(account.id), account);
25
+ void queryClient.invalidateQueries({ queryKey: ["venly", "accounts"] });
26
+ },
27
+ });
28
+ }
29
+ export function useCreateVirtualBankAccount() {
30
+ const { finance } = useVenly();
31
+ const queryClient = useQueryClient();
32
+ return useMutation({
33
+ mutationFn: (input) => finance.virtualBankAccounts.create(input.accountId, input.body),
34
+ onSuccess: (_viba, input) => {
35
+ void queryClient.invalidateQueries({
36
+ queryKey: ["venly", "account", input.accountId, "virtual-bank-accounts"],
37
+ });
38
+ },
39
+ });
40
+ }
41
+ export function useCreatePaymentSession() {
42
+ const { finance } = useVenly();
43
+ return useMutation({
44
+ mutationFn: (input) => finance.paymentSessions.create(input.accountId, input.body),
45
+ });
46
+ }
47
+ export function useCreateRampRequest() {
48
+ const { fundflow } = useVenly();
49
+ const queryClient = useQueryClient();
50
+ return useMutation({
51
+ mutationFn: (body) => fundflow.rampRequests.create(body),
52
+ onSuccess: (request) => {
53
+ if (request.id)
54
+ queryClient.setQueryData(venlyKeys.rampRequest(request.id), request);
55
+ void queryClient.invalidateQueries({ queryKey: ["venly", "ramp-requests"] });
56
+ },
57
+ });
58
+ }
@@ -0,0 +1,66 @@
1
+ import { type ReactNode } from "react";
2
+ import { QueryClient } from "@tanstack/react-query";
3
+ import { FundflowClient, VenlyFinanceClient, type FundflowClientOptions, type VenlyFinanceClientOptions } from "@venlyfinance/sdk";
4
+ /**
5
+ * Environments the provider accepts. "mock" constructs both clients with
6
+ * zero credentials and zero network (the SDK's stateful fixture store);
7
+ * "staging" and "production" require credentials or pre-built clients.
8
+ */
9
+ export type VenlyReactEnvironment = "mock" | "staging" | "production";
10
+ /** The pair of configured API clients every hook resolves from context. */
11
+ export interface VenlyClients {
12
+ environment: VenlyReactEnvironment;
13
+ finance: VenlyFinanceClient;
14
+ fundflow: FundflowClient;
15
+ }
16
+ export interface VenlyProviderProps {
17
+ /**
18
+ * Default "mock": zero credentials, zero network, seeded fixtures. The
19
+ * same component tree flips to staging/production by changing this prop
20
+ * and supplying credentials server-side or a proxy.
21
+ */
22
+ environment?: VenlyReactEnvironment;
23
+ /**
24
+ * OAuth2 client-credentials. SERVER-SIDE ONLY (React Server Components,
25
+ * route handlers, tests). The provider throws if a secret reaches a
26
+ * browser bundle outside mock mode: a leaked clientSecret is full API
27
+ * access. For browser apps use `proxyClientOptions()` and keep the
28
+ * credentials behind your own backend.
29
+ */
30
+ clientId?: string;
31
+ clientSecret?: string;
32
+ /** Pre-built clients (win over environment/credentials/options). */
33
+ finance?: VenlyFinanceClient;
34
+ fundflow?: FundflowClient;
35
+ /** Full per-client options, e.g. from `proxyClientOptions()`. */
36
+ financeOptions?: VenlyFinanceClientOptions;
37
+ fundflowOptions?: FundflowClientOptions;
38
+ /**
39
+ * Reuse the app's QueryClient. When omitted a private one is created with
40
+ * retry disabled: the SDK already retries transient failures (429/5xx
41
+ * with backoff), and stacking a second retry layer multiplies latency.
42
+ */
43
+ queryClient?: QueryClient;
44
+ children?: ReactNode;
45
+ }
46
+ /**
47
+ * Context provider for every hook in this package.
48
+ *
49
+ * ```tsx
50
+ * <VenlyProvider environment="mock">
51
+ * <App />
52
+ * </VenlyProvider>
53
+ * ```
54
+ */
55
+ export declare function VenlyProvider(props: VenlyProviderProps): import("react").FunctionComponentElement<import("@tanstack/react-query").QueryClientProviderProps>;
56
+ /** The configured clients. Throws outside a `<VenlyProvider>`. */
57
+ export declare function useVenly(): VenlyClients;
58
+ /**
59
+ * Mock controls (call log, failNext, lifecycle advancement). Defined only
60
+ * when the provider runs with environment "mock"; both fields are undefined
61
+ * otherwise, so demo/test affordances can never fire against live money.
62
+ */
63
+ export declare function useVenlyMock(): {
64
+ finance: import("@venlyfinance/sdk").VenlyFinanceMock | undefined;
65
+ fundflow: import("@venlyfinance/sdk").VenlyMock | undefined;
66
+ };