@paydlux/agent 0.1.12 → 0.1.14
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/dist/cli.js +5 -1
- package/dist/desk.d.ts +16 -1
- package/dist/desk.js +33 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -612,8 +612,12 @@ const HELP = `paydlux — get paid by AI agents, with a human in the loop.
|
|
|
612
612
|
|
|
613
613
|
paydlux setup [--mainnet] [--token USDC] [--fund-seed S…]
|
|
614
614
|
create a vault. testnet by default (free, no wallet needed).
|
|
615
|
-
paydlux sell [--price 1] [--route /api/data] [--
|
|
615
|
+
paydlux sell [--price 1] [--route /api/data] [--max N] [--daily N]
|
|
616
|
+
[--split] [--tls] [--preauth]
|
|
616
617
|
start the gateway and the approval desk.
|
|
618
|
+
--max / --daily are your spending mandate: no single payment above --max,
|
|
619
|
+
and nothing past --daily in a day. The desk refuses at the approve button,
|
|
620
|
+
so a runaway agent cannot drain the vault even if you approve in error.
|
|
617
621
|
paydlux status
|
|
618
622
|
balances, signers, live mandates, ledger rent.
|
|
619
623
|
paydlux approver [--forget]
|
package/dist/desk.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export type DeskRecord = {
|
|
|
11
11
|
uri: string;
|
|
12
12
|
price: string;
|
|
13
13
|
body: string;
|
|
14
|
-
status: "pending" | "awaiting_phone" | "approved" | "denied" | "settled" | "failed";
|
|
14
|
+
status: "pending" | "awaiting_phone" | "approved" | "denied" | "settled" | "failed" | "expired";
|
|
15
15
|
content?: string;
|
|
16
16
|
tx?: string;
|
|
17
17
|
reason?: string;
|
|
@@ -80,6 +80,21 @@ export declare class ApprovalDesk {
|
|
|
80
80
|
private server?;
|
|
81
81
|
cfg: DeskConfig;
|
|
82
82
|
constructor(cfg: DeskConfig);
|
|
83
|
+
/**
|
|
84
|
+
* A request the human never answered is not waiting forever.
|
|
85
|
+
*
|
|
86
|
+
* The transaction the phone signs carries Stellar time bounds, so past
|
|
87
|
+
* `expiresAt` the ledger rejects it no matter who signs it. Until this sweep
|
|
88
|
+
* existed such a request stayed `awaiting_phone` for good: it showed in the
|
|
89
|
+
* queue as approvable, held its price against the daily budget so later
|
|
90
|
+
* payments were refused for a money that could never move, and the buyer's
|
|
91
|
+
* retry kept reusing the dead handle instead of parking a fresh one. Three
|
|
92
|
+
* wrong behaviours from one missing transition, which is why the transition
|
|
93
|
+
* lives here rather than in the page that draws the word "expired".
|
|
94
|
+
*
|
|
95
|
+
* Called from every read path, so no caller can observe a stale state.
|
|
96
|
+
*/
|
|
97
|
+
private sweepExpired;
|
|
83
98
|
enqueue(uri: string, price: string, body: string, content: string, key?: string): string;
|
|
84
99
|
/** Every record carrying this key, newest first. */
|
|
85
100
|
allByKey(key: string): DeskRecord[];
|
package/dist/desk.js
CHANGED
|
@@ -159,7 +159,35 @@ export class ApprovalDesk {
|
|
|
159
159
|
server;
|
|
160
160
|
cfg;
|
|
161
161
|
constructor(cfg) { this.cfg = cfg; }
|
|
162
|
+
/**
|
|
163
|
+
* A request the human never answered is not waiting forever.
|
|
164
|
+
*
|
|
165
|
+
* The transaction the phone signs carries Stellar time bounds, so past
|
|
166
|
+
* `expiresAt` the ledger rejects it no matter who signs it. Until this sweep
|
|
167
|
+
* existed such a request stayed `awaiting_phone` for good: it showed in the
|
|
168
|
+
* queue as approvable, held its price against the daily budget so later
|
|
169
|
+
* payments were refused for a money that could never move, and the buyer's
|
|
170
|
+
* retry kept reusing the dead handle instead of parking a fresh one. Three
|
|
171
|
+
* wrong behaviours from one missing transition, which is why the transition
|
|
172
|
+
* lives here rather than in the page that draws the word "expired".
|
|
173
|
+
*
|
|
174
|
+
* Called from every read path, so no caller can observe a stale state.
|
|
175
|
+
*/
|
|
176
|
+
sweepExpired() {
|
|
177
|
+
const now = Date.now();
|
|
178
|
+
for (const r of this.records.values()) {
|
|
179
|
+
if (r.status !== "awaiting_phone" && r.status !== "approved")
|
|
180
|
+
continue;
|
|
181
|
+
const exp = r.challenge?.summary.expiresAt;
|
|
182
|
+
if (!exp || Number(exp) * 1000 > now)
|
|
183
|
+
continue;
|
|
184
|
+
r.status = "expired";
|
|
185
|
+
r.reason = `nobody approved it before the deadline (${new Date(Number(exp) * 1000).toISOString()})`;
|
|
186
|
+
console.log(`[desk] ${r.id} expired: the deadline passed with no approval`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
162
189
|
enqueue(uri, price, body, content, key) {
|
|
190
|
+
this.sweepExpired();
|
|
163
191
|
// Re-use an existing request for the same buyer + body + price. A buyer who
|
|
164
192
|
// retries after a human approved must get their content, not a second
|
|
165
193
|
// payment waiting in the queue. Settled records are NOT reused here — the
|
|
@@ -176,6 +204,7 @@ export class ApprovalDesk {
|
|
|
176
204
|
}
|
|
177
205
|
/** Every record carrying this key, newest first. */
|
|
178
206
|
allByKey(key) {
|
|
207
|
+
this.sweepExpired();
|
|
179
208
|
if (!key)
|
|
180
209
|
return [];
|
|
181
210
|
return [...this.records.values()].filter((r) => r.key === key).sort((a, b) => b.at - a.at);
|
|
@@ -183,8 +212,8 @@ export class ApprovalDesk {
|
|
|
183
212
|
findByKey(key) {
|
|
184
213
|
return this.allByKey(key)[0] ?? null;
|
|
185
214
|
}
|
|
186
|
-
get(id) { return this.records.get(id) ?? null; }
|
|
187
|
-
list() { return [...this.records.values()]; }
|
|
215
|
+
get(id) { this.sweepExpired(); return this.records.get(id) ?? null; }
|
|
216
|
+
list() { this.sweepExpired(); return [...this.records.values()]; }
|
|
188
217
|
/**
|
|
189
218
|
* The human clicked Approve.
|
|
190
219
|
*
|
|
@@ -240,6 +269,7 @@ export class ApprovalDesk {
|
|
|
240
269
|
});
|
|
241
270
|
}
|
|
242
271
|
async approve(id) {
|
|
272
|
+
this.sweepExpired();
|
|
243
273
|
const rec = this.records.get(id);
|
|
244
274
|
if (!rec)
|
|
245
275
|
throw new Error("unknown handle " + id);
|
|
@@ -307,6 +337,7 @@ export class ApprovalDesk {
|
|
|
307
337
|
* ledger rejects it if the signature is not over this exact transaction.
|
|
308
338
|
*/
|
|
309
339
|
async complete(id, signedXdr) {
|
|
340
|
+
this.sweepExpired();
|
|
310
341
|
const rec = this.records.get(id);
|
|
311
342
|
if (!rec)
|
|
312
343
|
throw new Error("unknown handle " + id);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paydlux/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "Payments for AI agents that a human approves. Spending mandates enforced on the Stellar ledger: 2-of-2 vault, pre-authorised transaction envelopes, HTTP 402, USDC.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|