@bondedhq/sdk 0.1.3 → 0.1.4
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/README.md +119 -5
- package/dist/ai-sdk.d.ts +19 -0
- package/dist/ai-sdk.js +46 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.js +36 -0
- package/dist/gate.d.ts +139 -0
- package/dist/gate.js +204 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -1
- package/dist/langchain.d.ts +19 -1
- package/dist/langchain.js +34 -0
- package/dist/mcp.d.ts +20 -0
- package/dist/mcp.js +30 -0
- package/dist/payments.d.ts +194 -0
- package/dist/payments.js +275 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* `@bondedhq/sdk/agentkit`, `@bondedhq/sdk/solana-agent-kit`, `@bondedhq/sdk/eliza`,
|
|
6
6
|
* `@bondedhq/sdk/langchain`, `@bondedhq/sdk/ai-sdk`. The episode's tools over MCP are in
|
|
7
7
|
* `@bondedhq/sdk/mcp`, and the Agent URL handler in `@bondedhq/sdk/agent-url`.
|
|
8
|
+
*
|
|
9
|
+
* Off chain, `paymentGuard` and `guardPayments` check an agent's payments against the payment
|
|
10
|
+
* mandate inside your own process (no network, no receipts); the framework subpaths wrap a pay
|
|
11
|
+
* tool with it.
|
|
8
12
|
*/
|
|
9
13
|
export { BondedVault, type ActionResult, type BondedVaultConfig, type VaultStatus, } from "./vault.js";
|
|
10
14
|
export { demoRouter, describeAction, type ApproveParams, type CallParams, type SwapParams, type SwapRouter, type TransferParams, type VaultAction, type VaultCall, } from "./actions.js";
|
|
@@ -12,8 +16,11 @@ export { breachReason, type DryRunResult, type VaultBreach } from "./breaches.js
|
|
|
12
16
|
export { guarded, GuardedVault, type GuardCheck, type GuardContext, type GuardedResult, type GuardOptions, type SentinelGuardOptions, type TokenInfo, } from "./guarded.js";
|
|
13
17
|
export { checkWithSentinel, type MessageSigner, type SentinelCheckRequest, type SentinelInput, } from "./sentinel.js";
|
|
14
18
|
export { buildMandate, describeMandate, type BuiltMandate, type EvmMandate, type EvmMandateParams, type EvmMandateRules, } from "./mandate.js";
|
|
15
|
-
export { BlockedByMandateError, BondedError, CallRevertedError, NotAgentError, PredictedBreachError, SentinelError, SentinelRefusedError, VaultFrozenError, type SentinelVerdict, } from "./errors.js";
|
|
19
|
+
export { BlockedByMandateError, BondedError, CallRevertedError, NotAgentError, PaymentBlockedError, PaymentFrozenError, PaymentGateError, PredictedBreachError, SentinelError, SentinelRefusedError, VaultFrozenError, type SentinelVerdict, } from "./errors.js";
|
|
16
20
|
export type { BreachType } from "@bondedhq/shared";
|
|
21
|
+
export { BONDED_API_URL, PaymentGate, paymentGate, type GateAnswer, type GateCheck, type GateDecision, type GatePayment, type GateReceiptProof, type GateVendorChange, type PaymentGateOptions, } from "./gate.js";
|
|
22
|
+
export { guardPayments, guardVendorChanges, isPaymentRefusal, PaymentGuard, paymentGuard, type GuardPaymentsOptions, type GuardVendorChangesOptions, type PaymentBreach, type PaymentGuardOptions, type PaymentGuardState, type PaymentMandate, type PaymentSource, type PaymentVendor, type PaymentVerdict, } from "./payments.js";
|
|
23
|
+
export { describePaymentMandate, PAYMENT_RULE_WORDS, PAYMENT_RULES, type PaidPayment, type PayableInvoice, type PayableRefund, type PaymentAttempt, type PaymentRule, type VerifiedChange, } from "@bondedhq/shared";
|
|
17
24
|
export { BONDED_VAULT_TOOLS, bondedVaultFromEnv, bondedVaultTools, type BondedVaultTool, type BondedVaultToolName, type BondedVaultToolsOptions, } from "./vault-tools.js";
|
|
18
25
|
export { bondedEpisodeEnv, episodeVault, fromBondedEnv, isBondedEpisode, type BondedEpisode, } from "./episode.js";
|
|
19
26
|
export { checkUnprotectedAllowances, deploymentTokens, unprotectedAllowancesWarning, type AllowanceCheck, type AllowanceFinding, type TokenRef, installMandateModule, type InstallMandateModuleInput, type ModuleAccountType, type ModuleInstallPlan, } from "./module.js";
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
* `@bondedhq/sdk/agentkit`, `@bondedhq/sdk/solana-agent-kit`, `@bondedhq/sdk/eliza`,
|
|
6
6
|
* `@bondedhq/sdk/langchain`, `@bondedhq/sdk/ai-sdk`. The episode's tools over MCP are in
|
|
7
7
|
* `@bondedhq/sdk/mcp`, and the Agent URL handler in `@bondedhq/sdk/agent-url`.
|
|
8
|
+
*
|
|
9
|
+
* Off chain, `paymentGuard` and `guardPayments` check an agent's payments against the payment
|
|
10
|
+
* mandate inside your own process (no network, no receipts); the framework subpaths wrap a pay
|
|
11
|
+
* tool with it.
|
|
8
12
|
*/
|
|
9
13
|
export { BondedVault, } from "./vault.js";
|
|
10
14
|
export { demoRouter, describeAction, } from "./actions.js";
|
|
@@ -12,7 +16,10 @@ export { breachReason } from "./breaches.js";
|
|
|
12
16
|
export { guarded, GuardedVault, } from "./guarded.js";
|
|
13
17
|
export { checkWithSentinel, } from "./sentinel.js";
|
|
14
18
|
export { buildMandate, describeMandate, } from "./mandate.js";
|
|
15
|
-
export { BlockedByMandateError, BondedError, CallRevertedError, NotAgentError, PredictedBreachError, SentinelError, SentinelRefusedError, VaultFrozenError, } from "./errors.js";
|
|
19
|
+
export { BlockedByMandateError, BondedError, CallRevertedError, NotAgentError, PaymentBlockedError, PaymentFrozenError, PaymentGateError, PredictedBreachError, SentinelError, SentinelRefusedError, VaultFrozenError, } from "./errors.js";
|
|
20
|
+
export { BONDED_API_URL, PaymentGate, paymentGate, } from "./gate.js";
|
|
21
|
+
export { guardPayments, guardVendorChanges, isPaymentRefusal, PaymentGuard, paymentGuard, } from "./payments.js";
|
|
22
|
+
export { describePaymentMandate, PAYMENT_RULE_WORDS, PAYMENT_RULES, } from "@bondedhq/shared";
|
|
16
23
|
export { BONDED_VAULT_TOOLS, bondedVaultFromEnv, bondedVaultTools, } from "./vault-tools.js";
|
|
17
24
|
export { bondedEpisodeEnv, episodeVault, fromBondedEnv, isBondedEpisode, } from "./episode.js";
|
|
18
25
|
export { checkUnprotectedAllowances, deploymentTokens, unprotectedAllowancesWarning, installMandateModule, } from "./module.js";
|
package/dist/langchain.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { DynamicStructuredTool } from "@langchain/core/tools";
|
|
1
|
+
import { DynamicStructuredTool, type StructuredToolInterface } from "@langchain/core/tools";
|
|
2
2
|
import { type EpisodeTools, type EpisodeToolsSource } from "./mcp.js";
|
|
3
|
+
import { type GuardPaymentsOptions } from "./payments.js";
|
|
3
4
|
import { type BondedVaultToolsOptions } from "./vault-tools.js";
|
|
4
5
|
export type { BondedVaultToolsOptions } from "./vault-tools.js";
|
|
6
|
+
export type { GuardPaymentsOptions } from "./payments.js";
|
|
5
7
|
/**
|
|
6
8
|
* The episode's tools as LangChain `StructuredTool`s, for LangChain and LangGraph agents
|
|
7
9
|
* (`createReactAgent`, `ToolNode`, `model.bindTools`). Each takes the tool's own JSON Schema and
|
|
@@ -36,4 +38,20 @@ export declare function bondedLangChainTools(from?: EpisodeTools | EpisodeToolsS
|
|
|
36
38
|
* ```
|
|
37
39
|
*/
|
|
38
40
|
export declare function bondedVaultLangChainTools(options: BondedVaultToolsOptions): DynamicStructuredTool[];
|
|
41
|
+
/**
|
|
42
|
+
* Your own LangChain pay tool, with every call checked against the payment mandate first (see
|
|
43
|
+
* `PaymentGuard`). Same name, description and schema. When the guard refuses (Enforce mode
|
|
44
|
+
* blocked it, the guard is frozen, or it can't read the payment) your tool is not called and the
|
|
45
|
+
* model gets `Error: ...` naming the rules broken, so it can react. In Monitor mode a breaking
|
|
46
|
+
* payment goes through and the guard's `onBreach` reports it. A local check: no receipts.
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* const guard = paymentGuard({ mandate, vendors, invoices, onBreach: alert });
|
|
50
|
+
* const tools = [...readOnlyTools, guardLangChainPayTool(payInvoice, { guard })];
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* The payment is read from the tool's arguments: `{ account, amountUsd, invoiceReference }` unless
|
|
54
|
+
* you pass `toPayment`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function guardLangChainPayTool(payTool: StructuredToolInterface, options: GuardPaymentsOptions<Record<string, unknown>>): DynamicStructuredTool;
|
|
39
57
|
//# sourceMappingURL=langchain.d.ts.map
|
package/dist/langchain.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DynamicStructuredTool } from "@langchain/core/tools";
|
|
2
2
|
import { resolveTools, resultText } from "./mcp.js";
|
|
3
|
+
import { guardPayments, isPaymentRefusal } from "./payments.js";
|
|
3
4
|
import { bondedVaultTools } from "./vault-tools.js";
|
|
4
5
|
/**
|
|
5
6
|
* The episode's tools as LangChain `StructuredTool`s, for LangChain and LangGraph agents
|
|
@@ -50,4 +51,37 @@ export function bondedVaultLangChainTools(options) {
|
|
|
50
51
|
func: async (args) => resultText(await t.call(args ?? {})),
|
|
51
52
|
}));
|
|
52
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Your own LangChain pay tool, with every call checked against the payment mandate first (see
|
|
56
|
+
* `PaymentGuard`). Same name, description and schema. When the guard refuses (Enforce mode
|
|
57
|
+
* blocked it, the guard is frozen, or it can't read the payment) your tool is not called and the
|
|
58
|
+
* model gets `Error: ...` naming the rules broken, so it can react. In Monitor mode a breaking
|
|
59
|
+
* payment goes through and the guard's `onBreach` reports it. A local check: no receipts.
|
|
60
|
+
*
|
|
61
|
+
* ```ts
|
|
62
|
+
* const guard = paymentGuard({ mandate, vendors, invoices, onBreach: alert });
|
|
63
|
+
* const tools = [...readOnlyTools, guardLangChainPayTool(payInvoice, { guard })];
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* The payment is read from the tool's arguments: `{ account, amountUsd, invoiceReference }` unless
|
|
67
|
+
* you pass `toPayment`.
|
|
68
|
+
*/
|
|
69
|
+
export function guardLangChainPayTool(payTool, options) {
|
|
70
|
+
const guarded = guardPayments((args, config) => payTool.invoke(args, config), options);
|
|
71
|
+
return new DynamicStructuredTool({
|
|
72
|
+
name: payTool.name,
|
|
73
|
+
description: payTool.description,
|
|
74
|
+
schema: payTool.schema,
|
|
75
|
+
func: async (args, _runManager, config) => {
|
|
76
|
+
try {
|
|
77
|
+
return await guarded(args ?? {}, config);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
if (isPaymentRefusal(error))
|
|
81
|
+
return `Error: ${error.message}`;
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
53
87
|
//# sourceMappingURL=langchain.js.map
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
3
|
import type { DoneRequest } from "@bondedhq/shared";
|
|
4
|
+
import { type GuardPaymentsOptions } from "./payments.js";
|
|
3
5
|
export { isBondedEpisode } from "./episode.js";
|
|
4
6
|
export { finishEpisode } from "./done.js";
|
|
7
|
+
export type { GuardPaymentsOptions } from "./payments.js";
|
|
5
8
|
/**
|
|
6
9
|
* Where an episode's tools are. A `BondedEpisode` (from `fromBondedEnv`, or the one an Agent URL
|
|
7
10
|
* handler hands you) has these, and so does the runner protocol's `EpisodeMessage`.
|
|
@@ -128,4 +131,21 @@ export declare function mcpConfigJson(episode?: {
|
|
|
128
131
|
mcp: string;
|
|
129
132
|
};
|
|
130
133
|
}, options?: McpConfigOptions): string;
|
|
134
|
+
/**
|
|
135
|
+
* Your MCP server's pay tool handler, with every call checked against the payment mandate first
|
|
136
|
+
* (see `PaymentGuard`). Register the result in its place:
|
|
137
|
+
*
|
|
138
|
+
* ```ts
|
|
139
|
+
* const guard = paymentGuard({ mandate, vendors, invoices, onBreach: alert });
|
|
140
|
+
* server.registerTool("pay_invoice", config, guardMcpPayHandler(payInvoice, { guard }));
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* When the guard refuses (Enforce mode blocked it, the guard is frozen, or it can't read the
|
|
144
|
+
* payment) your handler is not called and the client gets an error result (`isError: true`)
|
|
145
|
+
* naming the rules broken, so the model can react. In Monitor mode a breaking payment goes
|
|
146
|
+
* through and the guard's `onBreach` reports it. The payment is read from the tool's arguments:
|
|
147
|
+
* `{ account, amountUsd, invoiceReference }` unless you pass `toPayment`. A local check: no
|
|
148
|
+
* receipts.
|
|
149
|
+
*/
|
|
150
|
+
export declare function guardMcpPayHandler<I, Rest extends unknown[]>(handler: (args: I, ...rest: Rest) => CallToolResult | Promise<CallToolResult>, options: GuardPaymentsOptions<I>): (args: I, ...rest: Rest) => Promise<CallToolResult>;
|
|
131
151
|
//# sourceMappingURL=mcp.d.ts.map
|
package/dist/mcp.js
CHANGED
|
@@ -3,6 +3,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
|
|
|
3
3
|
import { BondedError } from "./errors.js";
|
|
4
4
|
import { finishEpisode } from "./done.js";
|
|
5
5
|
import { fromBondedEnv } from "./episode.js";
|
|
6
|
+
import { guardPayments, isPaymentRefusal } from "./payments.js";
|
|
6
7
|
export { isBondedEpisode } from "./episode.js";
|
|
7
8
|
export { finishEpisode } from "./done.js";
|
|
8
9
|
/**
|
|
@@ -108,4 +109,33 @@ export function mcpConfig(episode = fromBondedEnv(), options = {}) {
|
|
|
108
109
|
export function mcpConfigJson(episode = fromBondedEnv(), options = {}) {
|
|
109
110
|
return `${JSON.stringify(mcpConfig(episode, options), null, 2)}\n`;
|
|
110
111
|
}
|
|
112
|
+
/**
|
|
113
|
+
* Your MCP server's pay tool handler, with every call checked against the payment mandate first
|
|
114
|
+
* (see `PaymentGuard`). Register the result in its place:
|
|
115
|
+
*
|
|
116
|
+
* ```ts
|
|
117
|
+
* const guard = paymentGuard({ mandate, vendors, invoices, onBreach: alert });
|
|
118
|
+
* server.registerTool("pay_invoice", config, guardMcpPayHandler(payInvoice, { guard }));
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* When the guard refuses (Enforce mode blocked it, the guard is frozen, or it can't read the
|
|
122
|
+
* payment) your handler is not called and the client gets an error result (`isError: true`)
|
|
123
|
+
* naming the rules broken, so the model can react. In Monitor mode a breaking payment goes
|
|
124
|
+
* through and the guard's `onBreach` reports it. The payment is read from the tool's arguments:
|
|
125
|
+
* `{ account, amountUsd, invoiceReference }` unless you pass `toPayment`. A local check: no
|
|
126
|
+
* receipts.
|
|
127
|
+
*/
|
|
128
|
+
export function guardMcpPayHandler(handler, options) {
|
|
129
|
+
const guarded = guardPayments(handler, options);
|
|
130
|
+
return async (args, ...rest) => {
|
|
131
|
+
try {
|
|
132
|
+
return await guarded(args, ...rest);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (isPaymentRefusal(error))
|
|
136
|
+
return { content: [{ type: "text", text: error.message }], isError: true };
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
111
141
|
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { type PaidPayment, type PayableInvoice, type PayableRefund, type PaymentAttempt, type PaymentLimits, type PaymentRule, type SignedGateReceipt, type VerifiedChange } from "@bondedhq/shared";
|
|
2
|
+
import { BondedError, PaymentBlockedError, PaymentFrozenError, PaymentGateError } from "./errors.js";
|
|
3
|
+
/** The off-chain payment mandate an agent's payments are checked against. */
|
|
4
|
+
export interface PaymentMandate extends PaymentLimits {
|
|
5
|
+
/** Monitor lets a breaking payment through and reports it; Enforce blocks it. */
|
|
6
|
+
mode: "monitor" | "enforce";
|
|
7
|
+
/** After the first breach, refuse every payment until a person unfreezes the guard. */
|
|
8
|
+
freezeOnBreach: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** A supplier as your vendor master holds it. Its account is one the agent may pay. */
|
|
11
|
+
export interface PaymentVendor {
|
|
12
|
+
id: string;
|
|
13
|
+
/** Bank account (an IBAN or account number). Compared without spaces, case-insensitively. */
|
|
14
|
+
account: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
}
|
|
17
|
+
/** A list the guard reads on every check: fixed, or read from your own system each time. */
|
|
18
|
+
export type PaymentSource<T> = readonly T[] | (() => readonly T[] | Promise<readonly T[]>);
|
|
19
|
+
/** What the guard remembers between payments. Persist it to keep it across restarts. */
|
|
20
|
+
export interface PaymentGuardState {
|
|
21
|
+
/** Payments made through the guard (and any made before it, if you restore them), oldest first. */
|
|
22
|
+
payments: PaidPayment[];
|
|
23
|
+
/** Frozen after a breach: every payment is refused until `unfreeze()`. */
|
|
24
|
+
frozen: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Bank changes made without a verified ticket (let through in Monitor mode). The vendor master
|
|
27
|
+
* may now show these accounts, but they never count as the vendor's: paying one is
|
|
28
|
+
* `unknown_payee`.
|
|
29
|
+
*/
|
|
30
|
+
unverifiedChanges: VerifiedChange[];
|
|
31
|
+
}
|
|
32
|
+
/** One payment (or bank change) that broke the mandate, as the guard reports it. */
|
|
33
|
+
export interface PaymentBreach {
|
|
34
|
+
kind: "invoice" | "refund" | "vendor_change";
|
|
35
|
+
/** Every rule broken, most serious first. */
|
|
36
|
+
rules: PaymentRule[];
|
|
37
|
+
/** Each rule in plain words (`PAYMENT_RULE_WORDS`), in the same order. */
|
|
38
|
+
reasons: string[];
|
|
39
|
+
/** Enforce mode stopped it: the pay function was not called. */
|
|
40
|
+
blocked: boolean;
|
|
41
|
+
account: string;
|
|
42
|
+
/** The invoice or refund reference; empty for a bank change. */
|
|
43
|
+
reference: string;
|
|
44
|
+
/** The vendor whose verified account this is (or, for a bank change, the vendor changed). */
|
|
45
|
+
vendorId: string | null;
|
|
46
|
+
amountUsd: number;
|
|
47
|
+
/** If it went out: paid to an account outside the vendor master, gone for good. */
|
|
48
|
+
lossUsd: number;
|
|
49
|
+
/** If it went out: paid to a known payee beyond what it was owed, claimable back. */
|
|
50
|
+
overpaidUsd: number;
|
|
51
|
+
/** UTC day it counts against, YYYY-MM-DD. */
|
|
52
|
+
day: string;
|
|
53
|
+
/** From the hosted gate (`PaymentGate`): the decision's id in its log. */
|
|
54
|
+
decisionId?: string;
|
|
55
|
+
/** From the hosted gate: Bonded's signed receipt for the decision. */
|
|
56
|
+
receipt?: SignedGateReceipt;
|
|
57
|
+
}
|
|
58
|
+
/** The rule verdict for a payment, without making it. */
|
|
59
|
+
export interface PaymentVerdict {
|
|
60
|
+
/** Every rule the payment breaks, most serious first. Empty when it is allowed. */
|
|
61
|
+
rules: PaymentRule[];
|
|
62
|
+
reasons: string[];
|
|
63
|
+
amountUsd: number;
|
|
64
|
+
reference: string;
|
|
65
|
+
vendorId: string | null;
|
|
66
|
+
lossUsd: number;
|
|
67
|
+
overpaidUsd: number;
|
|
68
|
+
/** The guard is frozen: the payment would be refused whatever the rules say. */
|
|
69
|
+
frozen: boolean;
|
|
70
|
+
}
|
|
71
|
+
export interface PaymentGuardOptions {
|
|
72
|
+
mandate: PaymentMandate;
|
|
73
|
+
/** The vendor master: each vendor's account on file. */
|
|
74
|
+
vendors: PaymentSource<PaymentVendor>;
|
|
75
|
+
/** Invoices the business approved for payment. */
|
|
76
|
+
invoices?: PaymentSource<PayableInvoice>;
|
|
77
|
+
/** Customer refunds finance approved. */
|
|
78
|
+
refunds?: PaymentSource<PayableRefund>;
|
|
79
|
+
/**
|
|
80
|
+
* Bank changes finance verified out of band (a call to the number on file). A ticket's account
|
|
81
|
+
* is a known payee for its vendor, and the only way a vendor's account may change.
|
|
82
|
+
*/
|
|
83
|
+
changes?: PaymentSource<VerifiedChange>;
|
|
84
|
+
/** State to start from, as `onStateChange` last saved it (or `state()` returned). */
|
|
85
|
+
state?: PaymentGuardState;
|
|
86
|
+
/** Called with the new state after every change, inside the guard's lock. Save it here. */
|
|
87
|
+
onStateChange?: (state: PaymentGuardState) => void | Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Called with every breach before the guard acts on it: blocked in Enforce mode, let through
|
|
90
|
+
* in Monitor mode. If it throws, the payment is not made.
|
|
91
|
+
*/
|
|
92
|
+
onBreach?: (breach: PaymentBreach) => void | Promise<void>;
|
|
93
|
+
now?: () => Date;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The payment mandate, checked inside your own process: the same rules (`@bondedhq/shared`'s
|
|
97
|
+
* payment mandate) the Arena rates agents against, with no network and no model. You give it the
|
|
98
|
+
* mandate and your vendor master, approved invoices and refunds, and verified bank changes; it
|
|
99
|
+
* keeps the payments made and the frozen flag, and hands them to `onStateChange` to persist.
|
|
100
|
+
*
|
|
101
|
+
* Wrap your pay function with `guardPayments` (or a framework helper) so every payment is checked
|
|
102
|
+
* first. In Enforce mode a payment that breaks a rule throws `PaymentBlockedError` and your pay
|
|
103
|
+
* function is never called; in Monitor mode it goes through and `onBreach` reports it. A frozen
|
|
104
|
+
* guard refuses everything (`PaymentFrozenError`).
|
|
105
|
+
*
|
|
106
|
+
* It is a local check: the agent's code can still call the pay function without it, and it makes
|
|
107
|
+
* no receipts. Payments are checked and made one at a time, so two at once can't both pass the
|
|
108
|
+
* duplicate or daily checks.
|
|
109
|
+
*/
|
|
110
|
+
export declare class PaymentGuard {
|
|
111
|
+
#private;
|
|
112
|
+
readonly mandate: Readonly<PaymentMandate>;
|
|
113
|
+
constructor(options: PaymentGuardOptions);
|
|
114
|
+
get frozen(): boolean;
|
|
115
|
+
/** A copy of what the guard remembers, to persist or inspect. */
|
|
116
|
+
state(): PaymentGuardState;
|
|
117
|
+
/** Lets payments through again after a freeze. For a person who reviewed the breach. */
|
|
118
|
+
unfreeze(): Promise<void>;
|
|
119
|
+
/** The rule verdict for a payment, without making or recording it. */
|
|
120
|
+
check(attempt: PaymentAttempt, kind?: "invoice" | "refund"): Promise<PaymentVerdict>;
|
|
121
|
+
/**
|
|
122
|
+
* Checks a payment, then calls `pay` if the mandate allows it (or Monitor mode lets it through)
|
|
123
|
+
* and records it once `pay` returns. Throws `PaymentBlockedError` (Enforce), `PaymentFrozenError`
|
|
124
|
+
* or `BondedError` `INVALID_PAYMENT` without calling `pay`. A `pay` that throws records nothing.
|
|
125
|
+
*/
|
|
126
|
+
pay<R>(attempt: PaymentAttempt, pay: () => R | Promise<R>, kind?: "invoice" | "refund"): Promise<R>;
|
|
127
|
+
/**
|
|
128
|
+
* Checks a vendor bank change, then calls `update` if a verified ticket covers that vendor and
|
|
129
|
+
* account (or Monitor mode lets it through). An unverified change breaks
|
|
130
|
+
* `unverified_vendor_change`; let through in Monitor mode, its account still never counts as
|
|
131
|
+
* the vendor's.
|
|
132
|
+
*/
|
|
133
|
+
changeVendorAccount<R>(request: {
|
|
134
|
+
vendorId: string;
|
|
135
|
+
account: string;
|
|
136
|
+
}, update: () => R | Promise<R>): Promise<R>;
|
|
137
|
+
}
|
|
138
|
+
/** A payment guard: see `PaymentGuard`. */
|
|
139
|
+
export declare function paymentGuard(options: PaymentGuardOptions): PaymentGuard;
|
|
140
|
+
export interface GuardPaymentsOptions<I> {
|
|
141
|
+
/**
|
|
142
|
+
* A `PaymentGuard`, or the hosted `PaymentGate`. Share one between your invoice and refund
|
|
143
|
+
* functions, so limits and freezes are shared.
|
|
144
|
+
*/
|
|
145
|
+
guard: Pick<PaymentGuard, "pay">;
|
|
146
|
+
/** `invoice` (the default) pays approved invoices; `refund` pays approved customer refunds. */
|
|
147
|
+
kind?: "invoice" | "refund";
|
|
148
|
+
/**
|
|
149
|
+
* Reads the payment from your function's first argument. Default: `{ account, amountUsd,
|
|
150
|
+
* invoiceReference }` (or `reference`), the Arena's `pay_invoice` and `issue_refund` arguments.
|
|
151
|
+
*/
|
|
152
|
+
toPayment?: (input: I) => PaymentAttempt;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Wraps your own pay function so every call is checked against the payment mandate first. The
|
|
156
|
+
* wrapped function takes the same arguments and returns what yours returns. In Enforce mode a
|
|
157
|
+
* payment that breaks a rule throws `PaymentBlockedError` and your function is not called; in
|
|
158
|
+
* Monitor mode it is called and the guard's `onBreach` reports the breach. A frozen guard throws
|
|
159
|
+
* `PaymentFrozenError`.
|
|
160
|
+
*
|
|
161
|
+
* ```ts
|
|
162
|
+
* const guard = paymentGuard({ mandate, vendors, invoices, onBreach: alert });
|
|
163
|
+
* const pay = guardPayments(bank.pay, { guard });
|
|
164
|
+
* await pay({ account: "DE89 3704 0044 0532 0130 00", amountUsd: 1840.5, invoiceReference: "ACM-2291" });
|
|
165
|
+
* ```
|
|
166
|
+
*
|
|
167
|
+
* A local check: it makes no receipts, and code that calls your function directly skips it.
|
|
168
|
+
*/
|
|
169
|
+
export declare function guardPayments<I, Rest extends unknown[], R>(pay: (input: I, ...rest: Rest) => R | Promise<R>, options: GuardPaymentsOptions<I>): (input: I, ...rest: Rest) => Promise<R>;
|
|
170
|
+
export interface GuardVendorChangesOptions<I> {
|
|
171
|
+
/** A `PaymentGuard`, or the hosted `PaymentGate`. */
|
|
172
|
+
guard: Pick<PaymentGuard, "changeVendorAccount">;
|
|
173
|
+
/**
|
|
174
|
+
* Reads the change from your function's first argument. Default: `{ vendorId, account }`, and
|
|
175
|
+
* `ticket` when there is one (the hosted gate checks it).
|
|
176
|
+
*/
|
|
177
|
+
toChange?: (input: I) => {
|
|
178
|
+
vendorId: string;
|
|
179
|
+
account: string;
|
|
180
|
+
ticket?: string;
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Wraps your own "change a vendor's bank account" function: a change no verified ticket covers
|
|
185
|
+
* breaks `unverified_vendor_change`. Enforce mode throws `PaymentBlockedError` without calling
|
|
186
|
+
* it; Monitor mode calls it, reports the breach, and never treats the new account as the vendor's.
|
|
187
|
+
*/
|
|
188
|
+
export declare function guardVendorChanges<I, Rest extends unknown[], R>(update: (input: I, ...rest: Rest) => R | Promise<R>, options: GuardVendorChangesOptions<I>): (input: I, ...rest: Rest) => Promise<R>;
|
|
189
|
+
/**
|
|
190
|
+
* The payment guard or gate refused (blocked, frozen, arguments it can't check, or the gate gave no
|
|
191
|
+
* answer to act on): no money moved.
|
|
192
|
+
*/
|
|
193
|
+
export declare function isPaymentRefusal(error: unknown): error is PaymentBlockedError | PaymentFrozenError | PaymentGateError | BondedError;
|
|
194
|
+
//# sourceMappingURL=payments.d.ts.map
|