letagentpay 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.
- package/LICENSE +21 -0
- package/README.md +208 -0
- package/dist/index.d.mts +168 -0
- package/dist/index.d.ts +168 -0
- package/dist/index.js +259 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +230 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 LetAgentPay
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# letagentpay
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for [LetAgentPay](https://letagentpay.com) — AI agent spending policy middleware. Set budgets, define spending policies, and control AI agent purchases.
|
|
4
|
+
|
|
5
|
+
**Zero dependencies.** Uses the built-in `fetch` API (Node.js 18+, Bun, Deno).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install letagentpay
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { LetAgentPay } from "letagentpay";
|
|
17
|
+
|
|
18
|
+
const client = new LetAgentPay({ token: "agt_xxx" });
|
|
19
|
+
|
|
20
|
+
// Create a purchase request
|
|
21
|
+
const result = await client.requestPurchase({
|
|
22
|
+
amount: 15.0,
|
|
23
|
+
category: "api_calls",
|
|
24
|
+
description: "OpenAI GPT-4 call",
|
|
25
|
+
});
|
|
26
|
+
console.log(result.status); // "auto_approved" | "pending" | "rejected"
|
|
27
|
+
|
|
28
|
+
// Check budget
|
|
29
|
+
const budget = await client.checkBudget();
|
|
30
|
+
console.log(`Remaining: $${budget.remaining}`);
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### `requestPurchase(options)`
|
|
36
|
+
|
|
37
|
+
Create a purchase request. The policy engine runs 8 deterministic checks (budget, category, per-request limit, schedule, daily/weekly/monthly limits).
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
const result = await client.requestPurchase({
|
|
41
|
+
amount: 25.0,
|
|
42
|
+
category: "software",
|
|
43
|
+
merchantName: "GitHub", // optional
|
|
44
|
+
description: "Copilot license", // optional
|
|
45
|
+
agentComment: "Monthly renewal", // optional, shown to reviewers
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// result.status: "auto_approved" | "pending" | "rejected"
|
|
49
|
+
// result.requestId: "uuid"
|
|
50
|
+
// result.policyCheck: { passed: true, checks: [...] }
|
|
51
|
+
// result.budgetRemaining: 475.0 (only if auto_approved)
|
|
52
|
+
// result.expiresAt: "2026-..." (only if pending)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `checkRequest(requestId)`
|
|
56
|
+
|
|
57
|
+
Check the status of a purchase request.
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
const status = await client.checkRequest("request-uuid");
|
|
61
|
+
// status.status: "auto_approved" | "pending" | "approved" | "rejected" | "expired"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### `confirmPurchase(requestId, options)`
|
|
65
|
+
|
|
66
|
+
Confirm a purchase after approval. Use this to report the actual amount spent.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
await client.confirmPurchase("request-uuid", {
|
|
70
|
+
success: true,
|
|
71
|
+
actualAmount: 24.99, // optional, if different from requested
|
|
72
|
+
receiptUrl: "https://example.com/receipt", // optional
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### `checkBudget()`
|
|
77
|
+
|
|
78
|
+
Get current budget breakdown.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const budget = await client.checkBudget();
|
|
82
|
+
// budget.budget: 500.0
|
|
83
|
+
// budget.spent: 125.5
|
|
84
|
+
// budget.held: 25.0 (reserved for pending requests)
|
|
85
|
+
// budget.remaining: 349.5
|
|
86
|
+
// budget.currency: "USD"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `getPolicy()`
|
|
90
|
+
|
|
91
|
+
Get the current spending policy.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const policy = await client.getPolicy();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### `listCategories()`
|
|
98
|
+
|
|
99
|
+
List valid purchase categories.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const categories = await client.listCategories();
|
|
103
|
+
// ["groceries", "hardware", "software", "travel", ...]
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### `myRequests(options?)`
|
|
107
|
+
|
|
108
|
+
List agent's purchase requests with optional filters.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const list = await client.myRequests({ status: "pending", limit: 10 });
|
|
112
|
+
// list.requests: [{ requestId, status, amount, category, ... }]
|
|
113
|
+
// list.total: 42
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## guard()
|
|
117
|
+
|
|
118
|
+
Wrap an async function so it checks spending policy before executing:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import { guard } from "letagentpay";
|
|
122
|
+
|
|
123
|
+
const callOpenAI = guard(
|
|
124
|
+
async (prompt: string, cost: number) => {
|
|
125
|
+
// your OpenAI call here
|
|
126
|
+
return "response";
|
|
127
|
+
},
|
|
128
|
+
{ token: "agt_xxx", category: "api_calls" }
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// Automatically sends a purchase request for $0.03 before executing
|
|
132
|
+
await callOpenAI("Analyze this document", 0.03);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
With a fixed amount:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const sendEmail = guard(
|
|
139
|
+
async (to: string, body: string) => { /* ... */ },
|
|
140
|
+
{ token: "agt_xxx", category: "email", amount: 0.01 }
|
|
141
|
+
);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Self-Hosted
|
|
145
|
+
|
|
146
|
+
Point the SDK to your own LetAgentPay instance:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const client = new LetAgentPay({
|
|
150
|
+
token: "agt_xxx",
|
|
151
|
+
baseUrl: "http://localhost:8000/api/v1/agent-api",
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Environment Variables
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
export LETAGENTPAY_TOKEN=agt_xxx
|
|
159
|
+
export LETAGENTPAY_BASE_URL=https://api.letagentpay.com/api/v1/agent-api # optional
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// Token is taken from LETAGENTPAY_TOKEN
|
|
164
|
+
const client = new LetAgentPay();
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Error Handling
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { LetAgentPay, LetAgentPayError } from "letagentpay";
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
await client.requestPurchase({ amount: 100, category: "hardware" });
|
|
174
|
+
} catch (e) {
|
|
175
|
+
if (e instanceof LetAgentPayError) {
|
|
176
|
+
console.log(e.status); // 403
|
|
177
|
+
console.log(e.detail); // "Daily limit exceeded"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Security Model
|
|
183
|
+
|
|
184
|
+
LetAgentPay uses **server-side cooperative enforcement**. When your agent calls `requestPurchase()`, the request is evaluated by the policy engine on the LetAgentPay server. The agent receives only the result (approved/denied/pending) and cannot:
|
|
185
|
+
|
|
186
|
+
- Modify its own policies (the `agt_` token grants access only to the Agent API)
|
|
187
|
+
- Override policy check results (they come from the server)
|
|
188
|
+
- Approve its own pending requests (only a human can do that via the dashboard)
|
|
189
|
+
|
|
190
|
+
This is a **cooperative model** — it protects against budget overruns, category violations, and scheduling mistakes by well-behaved agents. It does not sandbox a malicious agent that has direct access to payment APIs.
|
|
191
|
+
|
|
192
|
+
### Best Practices
|
|
193
|
+
|
|
194
|
+
- **Don't give your agent raw payment credentials** (Stripe keys, credit card numbers). LetAgentPay should be the only spending channel
|
|
195
|
+
- Use `pending` + manual approval for high-value purchases
|
|
196
|
+
- Set per-request limits as an additional barrier
|
|
197
|
+
- Review the audit trail in the dashboard regularly
|
|
198
|
+
|
|
199
|
+
## Documentation
|
|
200
|
+
|
|
201
|
+
- [LetAgentPay docs](https://letagentpay.com/developers)
|
|
202
|
+
- [Agent API Reference](https://letagentpay.com/developers)
|
|
203
|
+
- [Python SDK](https://github.com/LetAgentPay/letagentpay-python)
|
|
204
|
+
- [GitHub](https://github.com/LetAgentPay/letagentpay-js)
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/** Individual policy check result. */
|
|
2
|
+
interface PolicyCheck {
|
|
3
|
+
rule: string;
|
|
4
|
+
result: "pass" | "fail";
|
|
5
|
+
detail: string;
|
|
6
|
+
}
|
|
7
|
+
/** Aggregated policy check result. */
|
|
8
|
+
interface PolicyResult {
|
|
9
|
+
passed: boolean;
|
|
10
|
+
checks: PolicyCheck[];
|
|
11
|
+
}
|
|
12
|
+
/** Response from creating a purchase request. */
|
|
13
|
+
interface PurchaseResult {
|
|
14
|
+
requestId: string;
|
|
15
|
+
status: "auto_approved" | "pending" | "rejected";
|
|
16
|
+
currency: string | null;
|
|
17
|
+
category: string | null;
|
|
18
|
+
originalCategory: string | null;
|
|
19
|
+
policyCheck: PolicyResult | null;
|
|
20
|
+
autoApproved: boolean;
|
|
21
|
+
budgetRemaining: number | null;
|
|
22
|
+
expiresAt: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** Response from checking a purchase request status. */
|
|
25
|
+
interface RequestStatus {
|
|
26
|
+
requestId: string;
|
|
27
|
+
status: string;
|
|
28
|
+
amount: number;
|
|
29
|
+
category: string;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
reviewedAt: string | null;
|
|
32
|
+
}
|
|
33
|
+
/** Response from confirming a purchase. */
|
|
34
|
+
interface ConfirmResult {
|
|
35
|
+
requestId: string;
|
|
36
|
+
status: "completed" | "failed";
|
|
37
|
+
actualAmount: number | null;
|
|
38
|
+
}
|
|
39
|
+
/** Current budget information. */
|
|
40
|
+
interface BudgetInfo {
|
|
41
|
+
budget: number;
|
|
42
|
+
spent: number;
|
|
43
|
+
held: number;
|
|
44
|
+
remaining: number;
|
|
45
|
+
currency: string | null;
|
|
46
|
+
}
|
|
47
|
+
/** Purchase request in a list response. */
|
|
48
|
+
interface PurchaseRequestInfo {
|
|
49
|
+
requestId: string;
|
|
50
|
+
status: string;
|
|
51
|
+
amount: number;
|
|
52
|
+
currency: string;
|
|
53
|
+
category: string;
|
|
54
|
+
merchant: string | null;
|
|
55
|
+
description: string | null;
|
|
56
|
+
createdAt: string | null;
|
|
57
|
+
reviewedAt: string | null;
|
|
58
|
+
expiresAt: string | null;
|
|
59
|
+
}
|
|
60
|
+
/** Paginated list of purchase requests. */
|
|
61
|
+
interface RequestList {
|
|
62
|
+
requests: PurchaseRequestInfo[];
|
|
63
|
+
total: number;
|
|
64
|
+
limit: number;
|
|
65
|
+
offset: number;
|
|
66
|
+
}
|
|
67
|
+
/** Options for creating a purchase request. */
|
|
68
|
+
interface PurchaseOptions {
|
|
69
|
+
amount: number;
|
|
70
|
+
category: string;
|
|
71
|
+
merchantName?: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
agentComment?: string;
|
|
74
|
+
}
|
|
75
|
+
/** Options for confirming a purchase. */
|
|
76
|
+
interface ConfirmOptions {
|
|
77
|
+
success: boolean;
|
|
78
|
+
actualAmount?: number;
|
|
79
|
+
receiptUrl?: string;
|
|
80
|
+
}
|
|
81
|
+
/** Options for listing requests. */
|
|
82
|
+
interface ListRequestsOptions {
|
|
83
|
+
status?: string;
|
|
84
|
+
limit?: number;
|
|
85
|
+
offset?: number;
|
|
86
|
+
}
|
|
87
|
+
/** Client configuration. */
|
|
88
|
+
interface LetAgentPayConfig {
|
|
89
|
+
token?: string;
|
|
90
|
+
baseUrl?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Client for the LetAgentPay Agent API.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const client = new LetAgentPay({ token: "agt_..." });
|
|
99
|
+
* const result = await client.requestPurchase({
|
|
100
|
+
* amount: 25.00,
|
|
101
|
+
* category: "groceries",
|
|
102
|
+
* description: "Weekly supplies",
|
|
103
|
+
* });
|
|
104
|
+
* console.log(result.status); // "auto_approved" | "pending" | "rejected"
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare class LetAgentPay {
|
|
108
|
+
private readonly token;
|
|
109
|
+
private readonly baseUrl;
|
|
110
|
+
constructor(config?: LetAgentPayConfig);
|
|
111
|
+
private request;
|
|
112
|
+
/** Create a purchase request. */
|
|
113
|
+
requestPurchase(options: PurchaseOptions): Promise<PurchaseResult>;
|
|
114
|
+
/** Check the status of a purchase request. */
|
|
115
|
+
checkRequest(requestId: string): Promise<RequestStatus>;
|
|
116
|
+
/** Confirm a purchase result after approval. */
|
|
117
|
+
confirmPurchase(requestId: string, options: ConfirmOptions): Promise<ConfirmResult>;
|
|
118
|
+
/** Get current budget, spent, and remaining. */
|
|
119
|
+
checkBudget(): Promise<BudgetInfo>;
|
|
120
|
+
/** Get the current spending policy. */
|
|
121
|
+
getPolicy(): Promise<Record<string, unknown>>;
|
|
122
|
+
/** List valid purchase categories. */
|
|
123
|
+
listCategories(): Promise<string[]>;
|
|
124
|
+
/** List agent's purchase requests. */
|
|
125
|
+
myRequests(options?: ListRequestsOptions): Promise<RequestList>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Error returned by the LetAgentPay API. */
|
|
129
|
+
declare class LetAgentPayError extends Error {
|
|
130
|
+
readonly status: number;
|
|
131
|
+
readonly detail: string;
|
|
132
|
+
constructor(status: number, detail: string);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Options for the guard wrapper. */
|
|
136
|
+
interface GuardOptions extends LetAgentPayConfig {
|
|
137
|
+
/** Existing client instance. Takes priority over token/baseUrl. */
|
|
138
|
+
client?: LetAgentPay;
|
|
139
|
+
/** Purchase category for the request. */
|
|
140
|
+
category?: string;
|
|
141
|
+
/** Fixed amount per call. If not set, must be passed to the guarded function. */
|
|
142
|
+
amount?: number;
|
|
143
|
+
/** Purchase description. */
|
|
144
|
+
description?: string;
|
|
145
|
+
/** Optional comment explaining the purchase. */
|
|
146
|
+
agentComment?: string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Wrap an async function so it checks spending policy before executing.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* const guardedBuy = guard(
|
|
154
|
+
* async (item: string, amount: number) => {
|
|
155
|
+
* return `Bought ${item} for $${amount}`;
|
|
156
|
+
* },
|
|
157
|
+
* { token: "agt_...", category: "groceries" }
|
|
158
|
+
* );
|
|
159
|
+
*
|
|
160
|
+
* // amount is extracted from the last numeric argument
|
|
161
|
+
* await guardedBuy("apples", 9.99);
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare function guard<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn | Promise<TReturn>, options: GuardOptions & {
|
|
165
|
+
amount?: number;
|
|
166
|
+
}): (...args: TArgs) => Promise<TReturn>;
|
|
167
|
+
|
|
168
|
+
export { type BudgetInfo, type ConfirmOptions, type ConfirmResult, type GuardOptions, LetAgentPay, type LetAgentPayConfig, LetAgentPayError, type ListRequestsOptions, type PolicyCheck, type PolicyResult, type PurchaseOptions, type PurchaseRequestInfo, type PurchaseResult, type RequestList, type RequestStatus, guard };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/** Individual policy check result. */
|
|
2
|
+
interface PolicyCheck {
|
|
3
|
+
rule: string;
|
|
4
|
+
result: "pass" | "fail";
|
|
5
|
+
detail: string;
|
|
6
|
+
}
|
|
7
|
+
/** Aggregated policy check result. */
|
|
8
|
+
interface PolicyResult {
|
|
9
|
+
passed: boolean;
|
|
10
|
+
checks: PolicyCheck[];
|
|
11
|
+
}
|
|
12
|
+
/** Response from creating a purchase request. */
|
|
13
|
+
interface PurchaseResult {
|
|
14
|
+
requestId: string;
|
|
15
|
+
status: "auto_approved" | "pending" | "rejected";
|
|
16
|
+
currency: string | null;
|
|
17
|
+
category: string | null;
|
|
18
|
+
originalCategory: string | null;
|
|
19
|
+
policyCheck: PolicyResult | null;
|
|
20
|
+
autoApproved: boolean;
|
|
21
|
+
budgetRemaining: number | null;
|
|
22
|
+
expiresAt: string | null;
|
|
23
|
+
}
|
|
24
|
+
/** Response from checking a purchase request status. */
|
|
25
|
+
interface RequestStatus {
|
|
26
|
+
requestId: string;
|
|
27
|
+
status: string;
|
|
28
|
+
amount: number;
|
|
29
|
+
category: string;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
reviewedAt: string | null;
|
|
32
|
+
}
|
|
33
|
+
/** Response from confirming a purchase. */
|
|
34
|
+
interface ConfirmResult {
|
|
35
|
+
requestId: string;
|
|
36
|
+
status: "completed" | "failed";
|
|
37
|
+
actualAmount: number | null;
|
|
38
|
+
}
|
|
39
|
+
/** Current budget information. */
|
|
40
|
+
interface BudgetInfo {
|
|
41
|
+
budget: number;
|
|
42
|
+
spent: number;
|
|
43
|
+
held: number;
|
|
44
|
+
remaining: number;
|
|
45
|
+
currency: string | null;
|
|
46
|
+
}
|
|
47
|
+
/** Purchase request in a list response. */
|
|
48
|
+
interface PurchaseRequestInfo {
|
|
49
|
+
requestId: string;
|
|
50
|
+
status: string;
|
|
51
|
+
amount: number;
|
|
52
|
+
currency: string;
|
|
53
|
+
category: string;
|
|
54
|
+
merchant: string | null;
|
|
55
|
+
description: string | null;
|
|
56
|
+
createdAt: string | null;
|
|
57
|
+
reviewedAt: string | null;
|
|
58
|
+
expiresAt: string | null;
|
|
59
|
+
}
|
|
60
|
+
/** Paginated list of purchase requests. */
|
|
61
|
+
interface RequestList {
|
|
62
|
+
requests: PurchaseRequestInfo[];
|
|
63
|
+
total: number;
|
|
64
|
+
limit: number;
|
|
65
|
+
offset: number;
|
|
66
|
+
}
|
|
67
|
+
/** Options for creating a purchase request. */
|
|
68
|
+
interface PurchaseOptions {
|
|
69
|
+
amount: number;
|
|
70
|
+
category: string;
|
|
71
|
+
merchantName?: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
agentComment?: string;
|
|
74
|
+
}
|
|
75
|
+
/** Options for confirming a purchase. */
|
|
76
|
+
interface ConfirmOptions {
|
|
77
|
+
success: boolean;
|
|
78
|
+
actualAmount?: number;
|
|
79
|
+
receiptUrl?: string;
|
|
80
|
+
}
|
|
81
|
+
/** Options for listing requests. */
|
|
82
|
+
interface ListRequestsOptions {
|
|
83
|
+
status?: string;
|
|
84
|
+
limit?: number;
|
|
85
|
+
offset?: number;
|
|
86
|
+
}
|
|
87
|
+
/** Client configuration. */
|
|
88
|
+
interface LetAgentPayConfig {
|
|
89
|
+
token?: string;
|
|
90
|
+
baseUrl?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Client for the LetAgentPay Agent API.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const client = new LetAgentPay({ token: "agt_..." });
|
|
99
|
+
* const result = await client.requestPurchase({
|
|
100
|
+
* amount: 25.00,
|
|
101
|
+
* category: "groceries",
|
|
102
|
+
* description: "Weekly supplies",
|
|
103
|
+
* });
|
|
104
|
+
* console.log(result.status); // "auto_approved" | "pending" | "rejected"
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare class LetAgentPay {
|
|
108
|
+
private readonly token;
|
|
109
|
+
private readonly baseUrl;
|
|
110
|
+
constructor(config?: LetAgentPayConfig);
|
|
111
|
+
private request;
|
|
112
|
+
/** Create a purchase request. */
|
|
113
|
+
requestPurchase(options: PurchaseOptions): Promise<PurchaseResult>;
|
|
114
|
+
/** Check the status of a purchase request. */
|
|
115
|
+
checkRequest(requestId: string): Promise<RequestStatus>;
|
|
116
|
+
/** Confirm a purchase result after approval. */
|
|
117
|
+
confirmPurchase(requestId: string, options: ConfirmOptions): Promise<ConfirmResult>;
|
|
118
|
+
/** Get current budget, spent, and remaining. */
|
|
119
|
+
checkBudget(): Promise<BudgetInfo>;
|
|
120
|
+
/** Get the current spending policy. */
|
|
121
|
+
getPolicy(): Promise<Record<string, unknown>>;
|
|
122
|
+
/** List valid purchase categories. */
|
|
123
|
+
listCategories(): Promise<string[]>;
|
|
124
|
+
/** List agent's purchase requests. */
|
|
125
|
+
myRequests(options?: ListRequestsOptions): Promise<RequestList>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Error returned by the LetAgentPay API. */
|
|
129
|
+
declare class LetAgentPayError extends Error {
|
|
130
|
+
readonly status: number;
|
|
131
|
+
readonly detail: string;
|
|
132
|
+
constructor(status: number, detail: string);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Options for the guard wrapper. */
|
|
136
|
+
interface GuardOptions extends LetAgentPayConfig {
|
|
137
|
+
/** Existing client instance. Takes priority over token/baseUrl. */
|
|
138
|
+
client?: LetAgentPay;
|
|
139
|
+
/** Purchase category for the request. */
|
|
140
|
+
category?: string;
|
|
141
|
+
/** Fixed amount per call. If not set, must be passed to the guarded function. */
|
|
142
|
+
amount?: number;
|
|
143
|
+
/** Purchase description. */
|
|
144
|
+
description?: string;
|
|
145
|
+
/** Optional comment explaining the purchase. */
|
|
146
|
+
agentComment?: string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Wrap an async function so it checks spending policy before executing.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* const guardedBuy = guard(
|
|
154
|
+
* async (item: string, amount: number) => {
|
|
155
|
+
* return `Bought ${item} for $${amount}`;
|
|
156
|
+
* },
|
|
157
|
+
* { token: "agt_...", category: "groceries" }
|
|
158
|
+
* );
|
|
159
|
+
*
|
|
160
|
+
* // amount is extracted from the last numeric argument
|
|
161
|
+
* await guardedBuy("apples", 9.99);
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
declare function guard<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn | Promise<TReturn>, options: GuardOptions & {
|
|
165
|
+
amount?: number;
|
|
166
|
+
}): (...args: TArgs) => Promise<TReturn>;
|
|
167
|
+
|
|
168
|
+
export { type BudgetInfo, type ConfirmOptions, type ConfirmResult, type GuardOptions, LetAgentPay, type LetAgentPayConfig, LetAgentPayError, type ListRequestsOptions, type PolicyCheck, type PolicyResult, type PurchaseOptions, type PurchaseRequestInfo, type PurchaseResult, type RequestList, type RequestStatus, guard };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
LetAgentPay: () => LetAgentPay,
|
|
24
|
+
LetAgentPayError: () => LetAgentPayError,
|
|
25
|
+
guard: () => guard
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
|
|
29
|
+
// src/errors.ts
|
|
30
|
+
var LetAgentPayError = class extends Error {
|
|
31
|
+
status;
|
|
32
|
+
detail;
|
|
33
|
+
constructor(status, detail) {
|
|
34
|
+
super(`[${status}] ${detail}`);
|
|
35
|
+
this.name = "LetAgentPayError";
|
|
36
|
+
this.status = status;
|
|
37
|
+
this.detail = detail;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/client.ts
|
|
42
|
+
var DEFAULT_BASE_URL = "https://api.letagentpay.com/api/v1/agent-api";
|
|
43
|
+
function getEnv(name) {
|
|
44
|
+
if (typeof process !== "undefined" && process.env) {
|
|
45
|
+
return process.env[name];
|
|
46
|
+
}
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
function parsePolicyCheck(data) {
|
|
50
|
+
return {
|
|
51
|
+
rule: data.rule,
|
|
52
|
+
result: data.result,
|
|
53
|
+
detail: data.detail
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function parsePolicyResult(data) {
|
|
57
|
+
if (!data) return null;
|
|
58
|
+
const checks = data.checks || [];
|
|
59
|
+
return {
|
|
60
|
+
passed: data.passed,
|
|
61
|
+
checks: checks.map(parsePolicyCheck)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function parsePurchaseResult(data) {
|
|
65
|
+
return {
|
|
66
|
+
requestId: data.request_id,
|
|
67
|
+
status: data.status,
|
|
68
|
+
currency: data.currency ?? null,
|
|
69
|
+
category: data.category ?? null,
|
|
70
|
+
originalCategory: data.original_category ?? null,
|
|
71
|
+
policyCheck: parsePolicyResult(
|
|
72
|
+
data.policy_check ?? null
|
|
73
|
+
),
|
|
74
|
+
autoApproved: data.auto_approved ?? false,
|
|
75
|
+
budgetRemaining: data.budget_remaining != null ? Number(data.budget_remaining) : null,
|
|
76
|
+
expiresAt: data.expires_at ?? null
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function parseRequestStatus(data) {
|
|
80
|
+
return {
|
|
81
|
+
requestId: data.request_id,
|
|
82
|
+
status: data.status,
|
|
83
|
+
amount: Number(data.amount),
|
|
84
|
+
category: data.category,
|
|
85
|
+
createdAt: String(data.created_at),
|
|
86
|
+
reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function parseConfirmResult(data) {
|
|
90
|
+
return {
|
|
91
|
+
requestId: data.request_id,
|
|
92
|
+
status: data.status,
|
|
93
|
+
actualAmount: data.actual_amount != null ? Number(data.actual_amount) : null
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function parseBudgetInfo(data) {
|
|
97
|
+
return {
|
|
98
|
+
budget: Number(data.budget),
|
|
99
|
+
spent: Number(data.spent),
|
|
100
|
+
held: Number(data.held),
|
|
101
|
+
remaining: Number(data.remaining),
|
|
102
|
+
currency: data.currency ?? null
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function parsePurchaseRequestInfo(data) {
|
|
106
|
+
return {
|
|
107
|
+
requestId: data.request_id,
|
|
108
|
+
status: data.status,
|
|
109
|
+
amount: Number(data.amount),
|
|
110
|
+
currency: data.currency ?? "USD",
|
|
111
|
+
category: data.category ?? "",
|
|
112
|
+
merchant: data.merchant ?? null,
|
|
113
|
+
description: data.description ?? null,
|
|
114
|
+
createdAt: data.created_at ? String(data.created_at) : null,
|
|
115
|
+
reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null,
|
|
116
|
+
expiresAt: data.expires_at ? String(data.expires_at) : null
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function parseRequestList(data) {
|
|
120
|
+
const requests = data.requests || [];
|
|
121
|
+
return {
|
|
122
|
+
requests: requests.map(parsePurchaseRequestInfo),
|
|
123
|
+
total: data.total ?? 0,
|
|
124
|
+
limit: data.limit ?? 20,
|
|
125
|
+
offset: data.offset ?? 0
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
var LetAgentPay = class {
|
|
129
|
+
token;
|
|
130
|
+
baseUrl;
|
|
131
|
+
constructor(config = {}) {
|
|
132
|
+
const resolvedToken = config.token ?? getEnv("LETAGENTPAY_TOKEN");
|
|
133
|
+
if (!resolvedToken) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
"Token is required. Pass token in config or set LETAGENTPAY_TOKEN env var."
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
this.token = resolvedToken;
|
|
139
|
+
this.baseUrl = (config.baseUrl ?? getEnv("LETAGENTPAY_BASE_URL") ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
140
|
+
}
|
|
141
|
+
async request(method, path, options) {
|
|
142
|
+
let url = `${this.baseUrl}${path}`;
|
|
143
|
+
if (options?.params) {
|
|
144
|
+
const searchParams = new URLSearchParams(options.params);
|
|
145
|
+
url += `?${searchParams.toString()}`;
|
|
146
|
+
}
|
|
147
|
+
const response = await fetch(url, {
|
|
148
|
+
method,
|
|
149
|
+
headers: {
|
|
150
|
+
Authorization: `Bearer ${this.token}`,
|
|
151
|
+
"Content-Type": "application/json"
|
|
152
|
+
},
|
|
153
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
154
|
+
});
|
|
155
|
+
const data = await response.json();
|
|
156
|
+
if (!response.ok) {
|
|
157
|
+
const detail = data.detail ?? response.statusText;
|
|
158
|
+
throw new LetAgentPayError(response.status, detail);
|
|
159
|
+
}
|
|
160
|
+
return data;
|
|
161
|
+
}
|
|
162
|
+
/** Create a purchase request. */
|
|
163
|
+
async requestPurchase(options) {
|
|
164
|
+
const body = {
|
|
165
|
+
amount: options.amount,
|
|
166
|
+
category: options.category
|
|
167
|
+
};
|
|
168
|
+
if (options.merchantName) body.merchant_name = options.merchantName;
|
|
169
|
+
if (options.description) body.description = options.description;
|
|
170
|
+
if (options.agentComment) body.agent_comment = options.agentComment;
|
|
171
|
+
const data = await this.request("POST", "/requests", { body });
|
|
172
|
+
return parsePurchaseResult(data);
|
|
173
|
+
}
|
|
174
|
+
/** Check the status of a purchase request. */
|
|
175
|
+
async checkRequest(requestId) {
|
|
176
|
+
const data = await this.request("GET", `/requests/${requestId}`);
|
|
177
|
+
return parseRequestStatus(data);
|
|
178
|
+
}
|
|
179
|
+
/** Confirm a purchase result after approval. */
|
|
180
|
+
async confirmPurchase(requestId, options) {
|
|
181
|
+
const body = { success: options.success };
|
|
182
|
+
if (options.actualAmount != null) body.actual_amount = options.actualAmount;
|
|
183
|
+
if (options.receiptUrl) body.receipt_url = options.receiptUrl;
|
|
184
|
+
const data = await this.request("POST", `/requests/${requestId}/confirm`, {
|
|
185
|
+
body
|
|
186
|
+
});
|
|
187
|
+
return parseConfirmResult(data);
|
|
188
|
+
}
|
|
189
|
+
/** Get current budget, spent, and remaining. */
|
|
190
|
+
async checkBudget() {
|
|
191
|
+
const data = await this.request("GET", "/budget");
|
|
192
|
+
return parseBudgetInfo(data);
|
|
193
|
+
}
|
|
194
|
+
/** Get the current spending policy. */
|
|
195
|
+
async getPolicy() {
|
|
196
|
+
return this.request("GET", "/policy");
|
|
197
|
+
}
|
|
198
|
+
/** List valid purchase categories. */
|
|
199
|
+
async listCategories() {
|
|
200
|
+
const data = await this.request("GET", "/categories");
|
|
201
|
+
return data.categories;
|
|
202
|
+
}
|
|
203
|
+
/** List agent's purchase requests. */
|
|
204
|
+
async myRequests(options = {}) {
|
|
205
|
+
const params = {};
|
|
206
|
+
if (options.status) params.status = options.status;
|
|
207
|
+
params.limit = String(options.limit ?? 20);
|
|
208
|
+
params.offset = String(options.offset ?? 0);
|
|
209
|
+
const data = await this.request("GET", "/requests", { params });
|
|
210
|
+
return parseRequestList(data);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// src/guard.ts
|
|
215
|
+
function guard(fn, options) {
|
|
216
|
+
return async (...args) => {
|
|
217
|
+
let resolvedAmount = options.amount;
|
|
218
|
+
if (resolvedAmount == null) {
|
|
219
|
+
for (const arg of args) {
|
|
220
|
+
if (typeof arg === "number") {
|
|
221
|
+
resolvedAmount = arg;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (resolvedAmount == null) {
|
|
227
|
+
throw new Error(
|
|
228
|
+
"guard: could not determine amount from arguments. Pass amount in guard options or as a numeric function argument."
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
const client = options.client ?? new LetAgentPay(options);
|
|
232
|
+
const result = await client.requestPurchase({
|
|
233
|
+
amount: resolvedAmount,
|
|
234
|
+
category: options.category ?? "other",
|
|
235
|
+
description: options.description ?? `Auto-guarded call to ${fn.name || "anonymous"}`,
|
|
236
|
+
agentComment: options.agentComment
|
|
237
|
+
});
|
|
238
|
+
if (result.status === "auto_approved" || result.status === "pending") {
|
|
239
|
+
if (result.status === "pending") {
|
|
240
|
+
throw new LetAgentPayError(
|
|
241
|
+
403,
|
|
242
|
+
`Purchase request pending approval: ${result.requestId}`
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
return fn(...args);
|
|
246
|
+
}
|
|
247
|
+
throw new LetAgentPayError(
|
|
248
|
+
403,
|
|
249
|
+
`Purchase request ${result.status}: ${result.requestId}`
|
|
250
|
+
);
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
254
|
+
0 && (module.exports = {
|
|
255
|
+
LetAgentPay,
|
|
256
|
+
LetAgentPayError,
|
|
257
|
+
guard
|
|
258
|
+
});
|
|
259
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts","../src/guard.ts"],"sourcesContent":["export { LetAgentPay } from \"./client.js\";\nexport { LetAgentPayError } from \"./errors.js\";\nexport { guard } from \"./guard.js\";\nexport type { GuardOptions } from \"./guard.js\";\nexport type {\n BudgetInfo,\n ConfirmOptions,\n ConfirmResult,\n LetAgentPayConfig,\n ListRequestsOptions,\n PolicyCheck,\n PolicyResult,\n PurchaseOptions,\n PurchaseRequestInfo,\n PurchaseResult,\n RequestList,\n RequestStatus,\n} from \"./types.js\";\n","/** Error returned by the LetAgentPay API. */\nexport class LetAgentPayError extends Error {\n readonly status: number;\n readonly detail: string;\n\n constructor(status: number, detail: string) {\n super(`[${status}] ${detail}`);\n this.name = \"LetAgentPayError\";\n this.status = status;\n this.detail = detail;\n }\n}\n","import { LetAgentPayError } from \"./errors.js\";\nimport type {\n BudgetInfo,\n ConfirmOptions,\n ConfirmResult,\n LetAgentPayConfig,\n ListRequestsOptions,\n PolicyCheck,\n PolicyResult,\n PurchaseOptions,\n PurchaseRequestInfo,\n PurchaseResult,\n RequestList,\n RequestStatus,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.letagentpay.com/api/v1/agent-api\";\n\nfunction getEnv(name: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n\nfunction parsePolicyCheck(data: Record<string, unknown>): PolicyCheck {\n return {\n rule: data.rule as string,\n result: data.result as \"pass\" | \"fail\",\n detail: data.detail as string,\n };\n}\n\nfunction parsePolicyResult(\n data: Record<string, unknown> | null,\n): PolicyResult | null {\n if (!data) return null;\n const checks = (data.checks as Record<string, unknown>[]) || [];\n return {\n passed: data.passed as boolean,\n checks: checks.map(parsePolicyCheck),\n };\n}\n\nfunction parsePurchaseResult(data: Record<string, unknown>): PurchaseResult {\n return {\n requestId: data.request_id as string,\n status: data.status as PurchaseResult[\"status\"],\n currency: (data.currency as string) ?? null,\n category: (data.category as string) ?? null,\n originalCategory: (data.original_category as string) ?? null,\n policyCheck: parsePolicyResult(\n (data.policy_check as Record<string, unknown>) ?? null,\n ),\n autoApproved: (data.auto_approved as boolean) ?? false,\n budgetRemaining:\n data.budget_remaining != null ? Number(data.budget_remaining) : null,\n expiresAt: (data.expires_at as string) ?? null,\n };\n}\n\nfunction parseRequestStatus(data: Record<string, unknown>): RequestStatus {\n return {\n requestId: data.request_id as string,\n status: data.status as string,\n amount: Number(data.amount),\n category: data.category as string,\n createdAt: String(data.created_at),\n reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null,\n };\n}\n\nfunction parseConfirmResult(data: Record<string, unknown>): ConfirmResult {\n return {\n requestId: data.request_id as string,\n status: data.status as ConfirmResult[\"status\"],\n actualAmount:\n data.actual_amount != null ? Number(data.actual_amount) : null,\n };\n}\n\nfunction parseBudgetInfo(data: Record<string, unknown>): BudgetInfo {\n return {\n budget: Number(data.budget),\n spent: Number(data.spent),\n held: Number(data.held),\n remaining: Number(data.remaining),\n currency: (data.currency as string) ?? null,\n };\n}\n\nfunction parsePurchaseRequestInfo(\n data: Record<string, unknown>,\n): PurchaseRequestInfo {\n return {\n requestId: data.request_id as string,\n status: data.status as string,\n amount: Number(data.amount),\n currency: (data.currency as string) ?? \"USD\",\n category: (data.category as string) ?? \"\",\n merchant: (data.merchant as string) ?? null,\n description: (data.description as string) ?? null,\n createdAt: data.created_at ? String(data.created_at) : null,\n reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null,\n expiresAt: data.expires_at ? String(data.expires_at) : null,\n };\n}\n\nfunction parseRequestList(data: Record<string, unknown>): RequestList {\n const requests = (data.requests as Record<string, unknown>[]) || [];\n return {\n requests: requests.map(parsePurchaseRequestInfo),\n total: (data.total as number) ?? 0,\n limit: (data.limit as number) ?? 20,\n offset: (data.offset as number) ?? 0,\n };\n}\n\n/**\n * Client for the LetAgentPay Agent API.\n *\n * @example\n * ```ts\n * const client = new LetAgentPay({ token: \"agt_...\" });\n * const result = await client.requestPurchase({\n * amount: 25.00,\n * category: \"groceries\",\n * description: \"Weekly supplies\",\n * });\n * console.log(result.status); // \"auto_approved\" | \"pending\" | \"rejected\"\n * ```\n */\nexport class LetAgentPay {\n private readonly token: string;\n private readonly baseUrl: string;\n\n constructor(config: LetAgentPayConfig = {}) {\n const resolvedToken = config.token ?? getEnv(\"LETAGENTPAY_TOKEN\");\n if (!resolvedToken) {\n throw new Error(\n \"Token is required. Pass token in config or set LETAGENTPAY_TOKEN env var.\",\n );\n }\n\n this.token = resolvedToken;\n this.baseUrl = (\n config.baseUrl ??\n getEnv(\"LETAGENTPAY_BASE_URL\") ??\n DEFAULT_BASE_URL\n ).replace(/\\/+$/, \"\");\n }\n\n private async request(\n method: string,\n path: string,\n options?: { body?: unknown; params?: Record<string, string> },\n ): Promise<Record<string, unknown>> {\n let url = `${this.baseUrl}${path}`;\n\n if (options?.params) {\n const searchParams = new URLSearchParams(options.params);\n url += `?${searchParams.toString()}`;\n }\n\n const response = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.token}`,\n \"Content-Type\": \"application/json\",\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n });\n\n const data = (await response.json()) as Record<string, unknown>;\n\n if (!response.ok) {\n const detail = (data.detail as string) ?? response.statusText;\n throw new LetAgentPayError(response.status, detail);\n }\n\n return data;\n }\n\n /** Create a purchase request. */\n async requestPurchase(options: PurchaseOptions): Promise<PurchaseResult> {\n const body: Record<string, unknown> = {\n amount: options.amount,\n category: options.category,\n };\n if (options.merchantName) body.merchant_name = options.merchantName;\n if (options.description) body.description = options.description;\n if (options.agentComment) body.agent_comment = options.agentComment;\n\n const data = await this.request(\"POST\", \"/requests\", { body });\n return parsePurchaseResult(data);\n }\n\n /** Check the status of a purchase request. */\n async checkRequest(requestId: string): Promise<RequestStatus> {\n const data = await this.request(\"GET\", `/requests/${requestId}`);\n return parseRequestStatus(data);\n }\n\n /** Confirm a purchase result after approval. */\n async confirmPurchase(\n requestId: string,\n options: ConfirmOptions,\n ): Promise<ConfirmResult> {\n const body: Record<string, unknown> = { success: options.success };\n if (options.actualAmount != null) body.actual_amount = options.actualAmount;\n if (options.receiptUrl) body.receipt_url = options.receiptUrl;\n\n const data = await this.request(\"POST\", `/requests/${requestId}/confirm`, {\n body,\n });\n return parseConfirmResult(data);\n }\n\n /** Get current budget, spent, and remaining. */\n async checkBudget(): Promise<BudgetInfo> {\n const data = await this.request(\"GET\", \"/budget\");\n return parseBudgetInfo(data);\n }\n\n /** Get the current spending policy. */\n async getPolicy(): Promise<Record<string, unknown>> {\n return this.request(\"GET\", \"/policy\");\n }\n\n /** List valid purchase categories. */\n async listCategories(): Promise<string[]> {\n const data = await this.request(\"GET\", \"/categories\");\n return data.categories as string[];\n }\n\n /** List agent's purchase requests. */\n async myRequests(options: ListRequestsOptions = {}): Promise<RequestList> {\n const params: Record<string, string> = {};\n if (options.status) params.status = options.status;\n params.limit = String(options.limit ?? 20);\n params.offset = String(options.offset ?? 0);\n\n const data = await this.request(\"GET\", \"/requests\", { params });\n return parseRequestList(data);\n }\n}\n","import { LetAgentPay } from \"./client.js\";\nimport { LetAgentPayError } from \"./errors.js\";\nimport type { LetAgentPayConfig } from \"./types.js\";\n\n/** Options for the guard wrapper. */\nexport interface GuardOptions extends LetAgentPayConfig {\n /** Existing client instance. Takes priority over token/baseUrl. */\n client?: LetAgentPay;\n /** Purchase category for the request. */\n category?: string;\n /** Fixed amount per call. If not set, must be passed to the guarded function. */\n amount?: number;\n /** Purchase description. */\n description?: string;\n /** Optional comment explaining the purchase. */\n agentComment?: string;\n}\n\n/**\n * Wrap an async function so it checks spending policy before executing.\n *\n * @example\n * ```ts\n * const guardedBuy = guard(\n * async (item: string, amount: number) => {\n * return `Bought ${item} for $${amount}`;\n * },\n * { token: \"agt_...\", category: \"groceries\" }\n * );\n *\n * // amount is extracted from the last numeric argument\n * await guardedBuy(\"apples\", 9.99);\n * ```\n */\nexport function guard<TArgs extends unknown[], TReturn>(\n fn: (...args: TArgs) => TReturn | Promise<TReturn>,\n options: GuardOptions & { amount?: number },\n): (...args: TArgs) => Promise<TReturn> {\n return async (...args: TArgs): Promise<TReturn> => {\n let resolvedAmount = options.amount;\n if (resolvedAmount == null) {\n // Try to find a numeric argument (first one)\n for (const arg of args) {\n if (typeof arg === \"number\") {\n resolvedAmount = arg;\n break;\n }\n }\n }\n\n if (resolvedAmount == null) {\n throw new Error(\n \"guard: could not determine amount from arguments. \" +\n \"Pass amount in guard options or as a numeric function argument.\",\n );\n }\n\n const client = options.client ?? new LetAgentPay(options);\n\n const result = await client.requestPurchase({\n amount: resolvedAmount,\n category: options.category ?? \"other\",\n description:\n options.description ?? `Auto-guarded call to ${fn.name || \"anonymous\"}`,\n agentComment: options.agentComment,\n });\n\n if (result.status === \"auto_approved\" || result.status === \"pending\") {\n if (result.status === \"pending\") {\n throw new LetAgentPayError(\n 403,\n `Purchase request pending approval: ${result.requestId}`,\n );\n }\n return fn(...args);\n }\n\n throw new LetAgentPayError(\n 403,\n `Purchase request ${result.status}: ${result.requestId}`,\n );\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var LetAgentPayError = class extends Error {
|
|
3
|
+
status;
|
|
4
|
+
detail;
|
|
5
|
+
constructor(status, detail) {
|
|
6
|
+
super(`[${status}] ${detail}`);
|
|
7
|
+
this.name = "LetAgentPayError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.detail = detail;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// src/client.ts
|
|
14
|
+
var DEFAULT_BASE_URL = "https://api.letagentpay.com/api/v1/agent-api";
|
|
15
|
+
function getEnv(name) {
|
|
16
|
+
if (typeof process !== "undefined" && process.env) {
|
|
17
|
+
return process.env[name];
|
|
18
|
+
}
|
|
19
|
+
return void 0;
|
|
20
|
+
}
|
|
21
|
+
function parsePolicyCheck(data) {
|
|
22
|
+
return {
|
|
23
|
+
rule: data.rule,
|
|
24
|
+
result: data.result,
|
|
25
|
+
detail: data.detail
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function parsePolicyResult(data) {
|
|
29
|
+
if (!data) return null;
|
|
30
|
+
const checks = data.checks || [];
|
|
31
|
+
return {
|
|
32
|
+
passed: data.passed,
|
|
33
|
+
checks: checks.map(parsePolicyCheck)
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function parsePurchaseResult(data) {
|
|
37
|
+
return {
|
|
38
|
+
requestId: data.request_id,
|
|
39
|
+
status: data.status,
|
|
40
|
+
currency: data.currency ?? null,
|
|
41
|
+
category: data.category ?? null,
|
|
42
|
+
originalCategory: data.original_category ?? null,
|
|
43
|
+
policyCheck: parsePolicyResult(
|
|
44
|
+
data.policy_check ?? null
|
|
45
|
+
),
|
|
46
|
+
autoApproved: data.auto_approved ?? false,
|
|
47
|
+
budgetRemaining: data.budget_remaining != null ? Number(data.budget_remaining) : null,
|
|
48
|
+
expiresAt: data.expires_at ?? null
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function parseRequestStatus(data) {
|
|
52
|
+
return {
|
|
53
|
+
requestId: data.request_id,
|
|
54
|
+
status: data.status,
|
|
55
|
+
amount: Number(data.amount),
|
|
56
|
+
category: data.category,
|
|
57
|
+
createdAt: String(data.created_at),
|
|
58
|
+
reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function parseConfirmResult(data) {
|
|
62
|
+
return {
|
|
63
|
+
requestId: data.request_id,
|
|
64
|
+
status: data.status,
|
|
65
|
+
actualAmount: data.actual_amount != null ? Number(data.actual_amount) : null
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function parseBudgetInfo(data) {
|
|
69
|
+
return {
|
|
70
|
+
budget: Number(data.budget),
|
|
71
|
+
spent: Number(data.spent),
|
|
72
|
+
held: Number(data.held),
|
|
73
|
+
remaining: Number(data.remaining),
|
|
74
|
+
currency: data.currency ?? null
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function parsePurchaseRequestInfo(data) {
|
|
78
|
+
return {
|
|
79
|
+
requestId: data.request_id,
|
|
80
|
+
status: data.status,
|
|
81
|
+
amount: Number(data.amount),
|
|
82
|
+
currency: data.currency ?? "USD",
|
|
83
|
+
category: data.category ?? "",
|
|
84
|
+
merchant: data.merchant ?? null,
|
|
85
|
+
description: data.description ?? null,
|
|
86
|
+
createdAt: data.created_at ? String(data.created_at) : null,
|
|
87
|
+
reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null,
|
|
88
|
+
expiresAt: data.expires_at ? String(data.expires_at) : null
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function parseRequestList(data) {
|
|
92
|
+
const requests = data.requests || [];
|
|
93
|
+
return {
|
|
94
|
+
requests: requests.map(parsePurchaseRequestInfo),
|
|
95
|
+
total: data.total ?? 0,
|
|
96
|
+
limit: data.limit ?? 20,
|
|
97
|
+
offset: data.offset ?? 0
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
var LetAgentPay = class {
|
|
101
|
+
token;
|
|
102
|
+
baseUrl;
|
|
103
|
+
constructor(config = {}) {
|
|
104
|
+
const resolvedToken = config.token ?? getEnv("LETAGENTPAY_TOKEN");
|
|
105
|
+
if (!resolvedToken) {
|
|
106
|
+
throw new Error(
|
|
107
|
+
"Token is required. Pass token in config or set LETAGENTPAY_TOKEN env var."
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
this.token = resolvedToken;
|
|
111
|
+
this.baseUrl = (config.baseUrl ?? getEnv("LETAGENTPAY_BASE_URL") ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
112
|
+
}
|
|
113
|
+
async request(method, path, options) {
|
|
114
|
+
let url = `${this.baseUrl}${path}`;
|
|
115
|
+
if (options?.params) {
|
|
116
|
+
const searchParams = new URLSearchParams(options.params);
|
|
117
|
+
url += `?${searchParams.toString()}`;
|
|
118
|
+
}
|
|
119
|
+
const response = await fetch(url, {
|
|
120
|
+
method,
|
|
121
|
+
headers: {
|
|
122
|
+
Authorization: `Bearer ${this.token}`,
|
|
123
|
+
"Content-Type": "application/json"
|
|
124
|
+
},
|
|
125
|
+
body: options?.body ? JSON.stringify(options.body) : void 0
|
|
126
|
+
});
|
|
127
|
+
const data = await response.json();
|
|
128
|
+
if (!response.ok) {
|
|
129
|
+
const detail = data.detail ?? response.statusText;
|
|
130
|
+
throw new LetAgentPayError(response.status, detail);
|
|
131
|
+
}
|
|
132
|
+
return data;
|
|
133
|
+
}
|
|
134
|
+
/** Create a purchase request. */
|
|
135
|
+
async requestPurchase(options) {
|
|
136
|
+
const body = {
|
|
137
|
+
amount: options.amount,
|
|
138
|
+
category: options.category
|
|
139
|
+
};
|
|
140
|
+
if (options.merchantName) body.merchant_name = options.merchantName;
|
|
141
|
+
if (options.description) body.description = options.description;
|
|
142
|
+
if (options.agentComment) body.agent_comment = options.agentComment;
|
|
143
|
+
const data = await this.request("POST", "/requests", { body });
|
|
144
|
+
return parsePurchaseResult(data);
|
|
145
|
+
}
|
|
146
|
+
/** Check the status of a purchase request. */
|
|
147
|
+
async checkRequest(requestId) {
|
|
148
|
+
const data = await this.request("GET", `/requests/${requestId}`);
|
|
149
|
+
return parseRequestStatus(data);
|
|
150
|
+
}
|
|
151
|
+
/** Confirm a purchase result after approval. */
|
|
152
|
+
async confirmPurchase(requestId, options) {
|
|
153
|
+
const body = { success: options.success };
|
|
154
|
+
if (options.actualAmount != null) body.actual_amount = options.actualAmount;
|
|
155
|
+
if (options.receiptUrl) body.receipt_url = options.receiptUrl;
|
|
156
|
+
const data = await this.request("POST", `/requests/${requestId}/confirm`, {
|
|
157
|
+
body
|
|
158
|
+
});
|
|
159
|
+
return parseConfirmResult(data);
|
|
160
|
+
}
|
|
161
|
+
/** Get current budget, spent, and remaining. */
|
|
162
|
+
async checkBudget() {
|
|
163
|
+
const data = await this.request("GET", "/budget");
|
|
164
|
+
return parseBudgetInfo(data);
|
|
165
|
+
}
|
|
166
|
+
/** Get the current spending policy. */
|
|
167
|
+
async getPolicy() {
|
|
168
|
+
return this.request("GET", "/policy");
|
|
169
|
+
}
|
|
170
|
+
/** List valid purchase categories. */
|
|
171
|
+
async listCategories() {
|
|
172
|
+
const data = await this.request("GET", "/categories");
|
|
173
|
+
return data.categories;
|
|
174
|
+
}
|
|
175
|
+
/** List agent's purchase requests. */
|
|
176
|
+
async myRequests(options = {}) {
|
|
177
|
+
const params = {};
|
|
178
|
+
if (options.status) params.status = options.status;
|
|
179
|
+
params.limit = String(options.limit ?? 20);
|
|
180
|
+
params.offset = String(options.offset ?? 0);
|
|
181
|
+
const data = await this.request("GET", "/requests", { params });
|
|
182
|
+
return parseRequestList(data);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// src/guard.ts
|
|
187
|
+
function guard(fn, options) {
|
|
188
|
+
return async (...args) => {
|
|
189
|
+
let resolvedAmount = options.amount;
|
|
190
|
+
if (resolvedAmount == null) {
|
|
191
|
+
for (const arg of args) {
|
|
192
|
+
if (typeof arg === "number") {
|
|
193
|
+
resolvedAmount = arg;
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (resolvedAmount == null) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
"guard: could not determine amount from arguments. Pass amount in guard options or as a numeric function argument."
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
const client = options.client ?? new LetAgentPay(options);
|
|
204
|
+
const result = await client.requestPurchase({
|
|
205
|
+
amount: resolvedAmount,
|
|
206
|
+
category: options.category ?? "other",
|
|
207
|
+
description: options.description ?? `Auto-guarded call to ${fn.name || "anonymous"}`,
|
|
208
|
+
agentComment: options.agentComment
|
|
209
|
+
});
|
|
210
|
+
if (result.status === "auto_approved" || result.status === "pending") {
|
|
211
|
+
if (result.status === "pending") {
|
|
212
|
+
throw new LetAgentPayError(
|
|
213
|
+
403,
|
|
214
|
+
`Purchase request pending approval: ${result.requestId}`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
return fn(...args);
|
|
218
|
+
}
|
|
219
|
+
throw new LetAgentPayError(
|
|
220
|
+
403,
|
|
221
|
+
`Purchase request ${result.status}: ${result.requestId}`
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
export {
|
|
226
|
+
LetAgentPay,
|
|
227
|
+
LetAgentPayError,
|
|
228
|
+
guard
|
|
229
|
+
};
|
|
230
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/guard.ts"],"sourcesContent":["/** Error returned by the LetAgentPay API. */\nexport class LetAgentPayError extends Error {\n readonly status: number;\n readonly detail: string;\n\n constructor(status: number, detail: string) {\n super(`[${status}] ${detail}`);\n this.name = \"LetAgentPayError\";\n this.status = status;\n this.detail = detail;\n }\n}\n","import { LetAgentPayError } from \"./errors.js\";\nimport type {\n BudgetInfo,\n ConfirmOptions,\n ConfirmResult,\n LetAgentPayConfig,\n ListRequestsOptions,\n PolicyCheck,\n PolicyResult,\n PurchaseOptions,\n PurchaseRequestInfo,\n PurchaseResult,\n RequestList,\n RequestStatus,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.letagentpay.com/api/v1/agent-api\";\n\nfunction getEnv(name: string): string | undefined {\n if (typeof process !== \"undefined\" && process.env) {\n return process.env[name];\n }\n return undefined;\n}\n\nfunction parsePolicyCheck(data: Record<string, unknown>): PolicyCheck {\n return {\n rule: data.rule as string,\n result: data.result as \"pass\" | \"fail\",\n detail: data.detail as string,\n };\n}\n\nfunction parsePolicyResult(\n data: Record<string, unknown> | null,\n): PolicyResult | null {\n if (!data) return null;\n const checks = (data.checks as Record<string, unknown>[]) || [];\n return {\n passed: data.passed as boolean,\n checks: checks.map(parsePolicyCheck),\n };\n}\n\nfunction parsePurchaseResult(data: Record<string, unknown>): PurchaseResult {\n return {\n requestId: data.request_id as string,\n status: data.status as PurchaseResult[\"status\"],\n currency: (data.currency as string) ?? null,\n category: (data.category as string) ?? null,\n originalCategory: (data.original_category as string) ?? null,\n policyCheck: parsePolicyResult(\n (data.policy_check as Record<string, unknown>) ?? null,\n ),\n autoApproved: (data.auto_approved as boolean) ?? false,\n budgetRemaining:\n data.budget_remaining != null ? Number(data.budget_remaining) : null,\n expiresAt: (data.expires_at as string) ?? null,\n };\n}\n\nfunction parseRequestStatus(data: Record<string, unknown>): RequestStatus {\n return {\n requestId: data.request_id as string,\n status: data.status as string,\n amount: Number(data.amount),\n category: data.category as string,\n createdAt: String(data.created_at),\n reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null,\n };\n}\n\nfunction parseConfirmResult(data: Record<string, unknown>): ConfirmResult {\n return {\n requestId: data.request_id as string,\n status: data.status as ConfirmResult[\"status\"],\n actualAmount:\n data.actual_amount != null ? Number(data.actual_amount) : null,\n };\n}\n\nfunction parseBudgetInfo(data: Record<string, unknown>): BudgetInfo {\n return {\n budget: Number(data.budget),\n spent: Number(data.spent),\n held: Number(data.held),\n remaining: Number(data.remaining),\n currency: (data.currency as string) ?? null,\n };\n}\n\nfunction parsePurchaseRequestInfo(\n data: Record<string, unknown>,\n): PurchaseRequestInfo {\n return {\n requestId: data.request_id as string,\n status: data.status as string,\n amount: Number(data.amount),\n currency: (data.currency as string) ?? \"USD\",\n category: (data.category as string) ?? \"\",\n merchant: (data.merchant as string) ?? null,\n description: (data.description as string) ?? null,\n createdAt: data.created_at ? String(data.created_at) : null,\n reviewedAt: data.reviewed_at ? String(data.reviewed_at) : null,\n expiresAt: data.expires_at ? String(data.expires_at) : null,\n };\n}\n\nfunction parseRequestList(data: Record<string, unknown>): RequestList {\n const requests = (data.requests as Record<string, unknown>[]) || [];\n return {\n requests: requests.map(parsePurchaseRequestInfo),\n total: (data.total as number) ?? 0,\n limit: (data.limit as number) ?? 20,\n offset: (data.offset as number) ?? 0,\n };\n}\n\n/**\n * Client for the LetAgentPay Agent API.\n *\n * @example\n * ```ts\n * const client = new LetAgentPay({ token: \"agt_...\" });\n * const result = await client.requestPurchase({\n * amount: 25.00,\n * category: \"groceries\",\n * description: \"Weekly supplies\",\n * });\n * console.log(result.status); // \"auto_approved\" | \"pending\" | \"rejected\"\n * ```\n */\nexport class LetAgentPay {\n private readonly token: string;\n private readonly baseUrl: string;\n\n constructor(config: LetAgentPayConfig = {}) {\n const resolvedToken = config.token ?? getEnv(\"LETAGENTPAY_TOKEN\");\n if (!resolvedToken) {\n throw new Error(\n \"Token is required. Pass token in config or set LETAGENTPAY_TOKEN env var.\",\n );\n }\n\n this.token = resolvedToken;\n this.baseUrl = (\n config.baseUrl ??\n getEnv(\"LETAGENTPAY_BASE_URL\") ??\n DEFAULT_BASE_URL\n ).replace(/\\/+$/, \"\");\n }\n\n private async request(\n method: string,\n path: string,\n options?: { body?: unknown; params?: Record<string, string> },\n ): Promise<Record<string, unknown>> {\n let url = `${this.baseUrl}${path}`;\n\n if (options?.params) {\n const searchParams = new URLSearchParams(options.params);\n url += `?${searchParams.toString()}`;\n }\n\n const response = await fetch(url, {\n method,\n headers: {\n Authorization: `Bearer ${this.token}`,\n \"Content-Type\": \"application/json\",\n },\n body: options?.body ? JSON.stringify(options.body) : undefined,\n });\n\n const data = (await response.json()) as Record<string, unknown>;\n\n if (!response.ok) {\n const detail = (data.detail as string) ?? response.statusText;\n throw new LetAgentPayError(response.status, detail);\n }\n\n return data;\n }\n\n /** Create a purchase request. */\n async requestPurchase(options: PurchaseOptions): Promise<PurchaseResult> {\n const body: Record<string, unknown> = {\n amount: options.amount,\n category: options.category,\n };\n if (options.merchantName) body.merchant_name = options.merchantName;\n if (options.description) body.description = options.description;\n if (options.agentComment) body.agent_comment = options.agentComment;\n\n const data = await this.request(\"POST\", \"/requests\", { body });\n return parsePurchaseResult(data);\n }\n\n /** Check the status of a purchase request. */\n async checkRequest(requestId: string): Promise<RequestStatus> {\n const data = await this.request(\"GET\", `/requests/${requestId}`);\n return parseRequestStatus(data);\n }\n\n /** Confirm a purchase result after approval. */\n async confirmPurchase(\n requestId: string,\n options: ConfirmOptions,\n ): Promise<ConfirmResult> {\n const body: Record<string, unknown> = { success: options.success };\n if (options.actualAmount != null) body.actual_amount = options.actualAmount;\n if (options.receiptUrl) body.receipt_url = options.receiptUrl;\n\n const data = await this.request(\"POST\", `/requests/${requestId}/confirm`, {\n body,\n });\n return parseConfirmResult(data);\n }\n\n /** Get current budget, spent, and remaining. */\n async checkBudget(): Promise<BudgetInfo> {\n const data = await this.request(\"GET\", \"/budget\");\n return parseBudgetInfo(data);\n }\n\n /** Get the current spending policy. */\n async getPolicy(): Promise<Record<string, unknown>> {\n return this.request(\"GET\", \"/policy\");\n }\n\n /** List valid purchase categories. */\n async listCategories(): Promise<string[]> {\n const data = await this.request(\"GET\", \"/categories\");\n return data.categories as string[];\n }\n\n /** List agent's purchase requests. */\n async myRequests(options: ListRequestsOptions = {}): Promise<RequestList> {\n const params: Record<string, string> = {};\n if (options.status) params.status = options.status;\n params.limit = String(options.limit ?? 20);\n params.offset = String(options.offset ?? 0);\n\n const data = await this.request(\"GET\", \"/requests\", { params });\n return parseRequestList(data);\n }\n}\n","import { LetAgentPay } from \"./client.js\";\nimport { LetAgentPayError } from \"./errors.js\";\nimport type { LetAgentPayConfig } from \"./types.js\";\n\n/** Options for the guard wrapper. */\nexport interface GuardOptions extends LetAgentPayConfig {\n /** Existing client instance. Takes priority over token/baseUrl. */\n client?: LetAgentPay;\n /** Purchase category for the request. */\n category?: string;\n /** Fixed amount per call. If not set, must be passed to the guarded function. */\n amount?: number;\n /** Purchase description. */\n description?: string;\n /** Optional comment explaining the purchase. */\n agentComment?: string;\n}\n\n/**\n * Wrap an async function so it checks spending policy before executing.\n *\n * @example\n * ```ts\n * const guardedBuy = guard(\n * async (item: string, amount: number) => {\n * return `Bought ${item} for $${amount}`;\n * },\n * { token: \"agt_...\", category: \"groceries\" }\n * );\n *\n * // amount is extracted from the last numeric argument\n * await guardedBuy(\"apples\", 9.99);\n * ```\n */\nexport function guard<TArgs extends unknown[], TReturn>(\n fn: (...args: TArgs) => TReturn | Promise<TReturn>,\n options: GuardOptions & { amount?: number },\n): (...args: TArgs) => Promise<TReturn> {\n return async (...args: TArgs): Promise<TReturn> => {\n let resolvedAmount = options.amount;\n if (resolvedAmount == null) {\n // Try to find a numeric argument (first one)\n for (const arg of args) {\n if (typeof arg === \"number\") {\n resolvedAmount = arg;\n break;\n }\n }\n }\n\n if (resolvedAmount == null) {\n throw new Error(\n \"guard: could not determine amount from arguments. \" +\n \"Pass amount in guard options or as a numeric function argument.\",\n );\n }\n\n const client = options.client ?? new LetAgentPay(options);\n\n const result = await client.requestPurchase({\n amount: resolvedAmount,\n category: options.category ?? \"other\",\n description:\n options.description ?? `Auto-guarded call to ${fn.name || \"anonymous\"}`,\n agentComment: options.agentComment,\n });\n\n if (result.status === \"auto_approved\" || result.status === \"pending\") {\n if (result.status === \"pending\") {\n throw new LetAgentPayError(\n 403,\n `Purchase request pending approval: ${result.requestId}`,\n );\n }\n return fn(...args);\n }\n\n throw new LetAgentPayError(\n 403,\n `Purchase request ${result.status}: ${result.requestId}`,\n );\n };\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "letagentpay",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for LetAgentPay — AI agent spending policy middleware",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsup",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
22
|
+
"lint": "tsc --noEmit",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"ai",
|
|
27
|
+
"agent",
|
|
28
|
+
"spending",
|
|
29
|
+
"policy",
|
|
30
|
+
"budget",
|
|
31
|
+
"llm",
|
|
32
|
+
"openclaw",
|
|
33
|
+
"letagentpay"
|
|
34
|
+
],
|
|
35
|
+
"author": "LetAgentPay <hello@letagentpay.com>",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/LetAgentPay/letagentpay-js"
|
|
40
|
+
},
|
|
41
|
+
"homepage": "https://letagentpay.com",
|
|
42
|
+
"bugs": {
|
|
43
|
+
"url": "https://github.com/LetAgentPay/letagentpay-js/issues"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^25.5.2",
|
|
50
|
+
"tsup": "^8.0.0",
|
|
51
|
+
"typescript": "^5.5.0",
|
|
52
|
+
"vitest": "^3.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|