402-mcp 4.2.1 → 4.3.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/README.md +60 -22
- package/build/config.d.ts +12 -1
- package/build/config.js +53 -12
- package/build/config.js.map +1 -1
- package/build/fetch/resilient-fetch.d.ts +7 -2
- package/build/fetch/resilient-fetch.js +32 -10
- package/build/fetch/resilient-fetch.js.map +1 -1
- package/build/fetch/socks-proxy.d.ts +25 -0
- package/build/fetch/socks-proxy.js +41 -0
- package/build/fetch/socks-proxy.js.map +1 -0
- package/build/fetch/ssrf-guard.d.ts +10 -0
- package/build/fetch/ssrf-guard.js +17 -1
- package/build/fetch/ssrf-guard.js.map +1 -1
- package/build/fetch/transport.d.ts +1 -0
- package/build/fetch/transport.js +37 -14
- package/build/fetch/transport.js.map +1 -1
- package/build/http-security.d.ts +13 -0
- package/build/http-security.js +38 -0
- package/build/http-security.js.map +1 -0
- package/build/index.js +186 -120
- package/build/index.js.map +1 -1
- package/build/l402/bolt11.js +3 -2
- package/build/l402/bolt11.js.map +1 -1
- package/build/spend-tracker.d.ts +31 -4
- package/build/spend-tracker.js +102 -17
- package/build/spend-tracker.js.map +1 -1
- package/build/store/cashu-tokens.d.ts +19 -0
- package/build/store/cashu-tokens.js +32 -0
- package/build/store/cashu-tokens.js.map +1 -1
- package/build/store/credentials.d.ts +5 -0
- package/build/store/credentials.js +1 -0
- package/build/store/credentials.js.map +1 -1
- package/build/store/pending-payments.d.ts +36 -0
- package/build/store/pending-payments.js +88 -0
- package/build/store/pending-payments.js.map +1 -0
- package/build/tools/buy-credits.d.ts +9 -0
- package/build/tools/buy-credits.js +40 -3
- package/build/tools/buy-credits.js.map +1 -1
- package/build/tools/config.d.ts +5 -0
- package/build/tools/config.js.map +1 -1
- package/build/tools/confirm.d.ts +12 -0
- package/build/tools/confirm.js +27 -0
- package/build/tools/confirm.js.map +1 -0
- package/build/tools/fetch-preview.js +9 -3
- package/build/tools/fetch-preview.js.map +1 -1
- package/build/tools/fetch.d.ts +7 -1
- package/build/tools/fetch.js +281 -140
- package/build/tools/fetch.js.map +1 -1
- package/build/tools/nostr-subscribe.js.map +1 -1
- package/build/tools/pay.d.ts +9 -0
- package/build/tools/pay.js +65 -8
- package/build/tools/pay.js.map +1 -1
- package/build/tools/reconcile.d.ts +33 -0
- package/build/tools/reconcile.js +111 -0
- package/build/tools/reconcile.js.map +1 -0
- package/build/tools/redeem-cashu.js +1 -1
- package/build/tools/redeem-cashu.js.map +1 -1
- package/build/tools/register-widgets.js +5 -5
- package/build/tools/register-widgets.js.map +1 -1
- package/build/tools/search.js +17 -3
- package/build/tools/search.js.map +1 -1
- package/build/tools/untrusted.d.ts +3 -0
- package/build/tools/untrusted.js +18 -0
- package/build/tools/untrusted.js.map +1 -0
- package/build/wallet/cashu.js +101 -21
- package/build/wallet/cashu.js.map +1 -1
- package/build/wallet/lnurlcash.js +25 -7
- package/build/wallet/lnurlcash.js.map +1 -1
- package/build/wallet/nwc.js +51 -3
- package/build/wallet/nwc.js.map +1 -1
- package/build/wallet/types.d.ts +17 -0
- package/build/x402/parse.d.ts +15 -3
- package/build/x402/parse.js +23 -9
- package/build/x402/parse.js.map +1 -1
- package/build/x402/payment.js +11 -6
- package/build/x402/payment.js.map +1 -1
- package/llms-full.txt +73 -34
- package/llms.txt +52 -24
- package/package.json +6 -5
- package/src/widgets/dist/payment-confirmation.html +28 -28
- package/src/widgets/dist/service-directory.html +39 -30
- package/src/widgets/dist/wallet-dashboard.html +28 -28
package/build/spend-tracker.js
CHANGED
|
@@ -1,41 +1,76 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, renameSync, mkdirSync, existsSync, chmodSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
const MINUTE_MS = 60_000;
|
|
4
|
+
const DAY_MS = 24 * 60 * 60_000;
|
|
1
5
|
/**
|
|
2
|
-
* Rolling-window spend tracker to prevent runaway auto-pay.
|
|
3
|
-
*
|
|
6
|
+
* Rolling-window spend tracker to prevent runaway auto-pay. Enforces the
|
|
7
|
+
* per-minute limit its callers pass in and, when configured, a daily limit
|
|
8
|
+
* whose window is persisted across restarts.
|
|
9
|
+
*
|
|
10
|
+
* A limit of 0 blocks every spend. It never means "unlimited".
|
|
4
11
|
*/
|
|
5
12
|
export class SpendTracker {
|
|
6
13
|
entries = [];
|
|
7
|
-
windowMs = 60_000;
|
|
8
14
|
/** Hard cap on entries to prevent unbounded memory growth. */
|
|
9
15
|
static MAX_ENTRIES = 10_000;
|
|
16
|
+
maxPerDaySats;
|
|
17
|
+
statePath;
|
|
18
|
+
constructor(options = {}) {
|
|
19
|
+
this.maxPerDaySats = options.maxPerDaySats;
|
|
20
|
+
this.statePath = options.statePath;
|
|
21
|
+
this.load();
|
|
22
|
+
}
|
|
10
23
|
record(sats) {
|
|
11
24
|
if (sats <= 0)
|
|
12
25
|
return; // reject negative or zero values
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
this.entries
|
|
17
|
-
}
|
|
18
|
-
this.
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
this.prune(now);
|
|
28
|
+
if (this.entries.length >= SpendTracker.MAX_ENTRIES)
|
|
29
|
+
this.entries.shift();
|
|
30
|
+
this.entries.push({ sats, at: now });
|
|
31
|
+
this.save();
|
|
19
32
|
}
|
|
33
|
+
/** Sats spent in the last 60 seconds. */
|
|
20
34
|
recentSpend() {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
35
|
+
return this.spentWithin(MINUTE_MS);
|
|
36
|
+
}
|
|
37
|
+
/** Sats spent in the last 24 hours. */
|
|
38
|
+
dailySpend() {
|
|
39
|
+
return this.spentWithin(DAY_MS);
|
|
24
40
|
}
|
|
25
41
|
wouldExceed(sats, limit) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
42
|
+
return this.refusal(sats, limit) !== null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Why a spend of `sats` would be refused under `perMinuteLimit` and the
|
|
46
|
+
* daily limit, or null if it would be allowed.
|
|
47
|
+
*/
|
|
48
|
+
refusal(sats, perMinuteLimit) {
|
|
49
|
+
if (sats <= 0)
|
|
50
|
+
return null;
|
|
51
|
+
if (perMinuteLimit <= 0)
|
|
52
|
+
return 'Auto-pay is disabled: MAX_SPEND_PER_MINUTE_SATS is 0.';
|
|
53
|
+
if (this.recentSpend() + sats > perMinuteLimit) {
|
|
54
|
+
return `Per-minute spend limit reached (MAX_SPEND_PER_MINUTE_SATS ${perMinuteLimit}).`;
|
|
55
|
+
}
|
|
56
|
+
if (this.maxPerDaySats !== undefined) {
|
|
57
|
+
if (this.maxPerDaySats <= 0)
|
|
58
|
+
return 'Auto-pay is disabled: MAX_SPEND_PER_DAY_SATS is 0.';
|
|
59
|
+
if (this.dailySpend() + sats > this.maxPerDaySats) {
|
|
60
|
+
return `Daily spend limit reached (MAX_SPEND_PER_DAY_SATS ${this.maxPerDaySats} in any 24 hours).`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
29
64
|
}
|
|
30
65
|
/**
|
|
31
66
|
* Atomic check-and-record: returns true and records the spend if it
|
|
32
|
-
* would NOT exceed
|
|
67
|
+
* would NOT exceed either limit, false otherwise. Closes the TOCTOU gap
|
|
33
68
|
* between wouldExceed() and record() for concurrent callers.
|
|
34
69
|
*/
|
|
35
70
|
tryRecord(sats, limit) {
|
|
36
71
|
if (sats <= 0)
|
|
37
72
|
return true;
|
|
38
|
-
if (
|
|
73
|
+
if (this.refusal(sats, limit) !== null)
|
|
39
74
|
return false;
|
|
40
75
|
this.record(sats);
|
|
41
76
|
return true;
|
|
@@ -51,9 +86,59 @@ export class SpendTracker {
|
|
|
51
86
|
for (let i = this.entries.length - 1; i >= 0; i--) {
|
|
52
87
|
if (this.entries[i].sats === sats) {
|
|
53
88
|
this.entries.splice(i, 1);
|
|
89
|
+
this.save();
|
|
54
90
|
return;
|
|
55
91
|
}
|
|
56
92
|
}
|
|
57
93
|
}
|
|
94
|
+
spentWithin(windowMs) {
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
this.prune(now);
|
|
97
|
+
const cutoff = now - windowMs;
|
|
98
|
+
return this.entries.reduce((sum, e) => (e.at >= cutoff ? sum + e.sats : sum), 0);
|
|
99
|
+
}
|
|
100
|
+
/** Entries only matter for as long as the widest window that is enforced. */
|
|
101
|
+
prune(now) {
|
|
102
|
+
const keepMs = this.maxPerDaySats !== undefined ? DAY_MS : MINUTE_MS;
|
|
103
|
+
const cutoff = now - keepMs;
|
|
104
|
+
if (this.entries.length > 0 && this.entries[0].at < cutoff) {
|
|
105
|
+
this.entries = this.entries.filter(e => e.at >= cutoff);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
load() {
|
|
109
|
+
if (!this.statePath || !existsSync(this.statePath))
|
|
110
|
+
return;
|
|
111
|
+
try {
|
|
112
|
+
const raw = JSON.parse(readFileSync(this.statePath, 'utf-8'));
|
|
113
|
+
const list = raw.entries;
|
|
114
|
+
if (!Array.isArray(list))
|
|
115
|
+
throw new Error('bad shape');
|
|
116
|
+
this.entries = list
|
|
117
|
+
.filter((e) => typeof e === 'object' && e !== null &&
|
|
118
|
+
Number.isSafeInteger(e.sats) && e.sats > 0 &&
|
|
119
|
+
Number.isFinite(e.at))
|
|
120
|
+
.slice(-SpendTracker.MAX_ENTRIES);
|
|
121
|
+
this.prune(Date.now());
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Losing the window would quietly reset the daily cap. Refuse instead.
|
|
125
|
+
throw new Error(`Cannot read the spend ledger at ${this.statePath}. It records auto-pay spend for MAX_SPEND_PER_DAY_SATS; fix or move it aside to start again.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
save() {
|
|
129
|
+
if (!this.statePath)
|
|
130
|
+
return;
|
|
131
|
+
const dir = dirname(this.statePath);
|
|
132
|
+
if (!existsSync(dir)) {
|
|
133
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
134
|
+
try {
|
|
135
|
+
chmodSync(dir, 0o700);
|
|
136
|
+
}
|
|
137
|
+
catch { /* Windows safety net */ }
|
|
138
|
+
}
|
|
139
|
+
const tmpPath = this.statePath + '.tmp';
|
|
140
|
+
writeFileSync(tmpPath, JSON.stringify({ entries: this.entries }), { mode: 0o600 });
|
|
141
|
+
renameSync(tmpPath, this.statePath);
|
|
142
|
+
}
|
|
58
143
|
}
|
|
59
144
|
//# sourceMappingURL=spend-tracker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spend-tracker.js","sourceRoot":"","sources":["../src/spend-tracker.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"spend-tracker.js","sourceRoot":"","sources":["../src/spend-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,17 @@ export interface StoredToken {
|
|
|
4
4
|
amountSats: number;
|
|
5
5
|
addedAt: string;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Proofs handed to a mint for a melt whose outcome is not yet known. They are
|
|
9
|
+
* neither spendable nor lost: the mint may still pay the invoice with them, or
|
|
10
|
+
* may yet refuse and leave them valid. Keeping them out of the spendable pool
|
|
11
|
+
* stops them being offered again while a reconcile can still restore them.
|
|
12
|
+
*/
|
|
13
|
+
export interface ReservedToken extends StoredToken {
|
|
14
|
+
paymentHash: string;
|
|
15
|
+
quoteId: string;
|
|
16
|
+
reservedAt: string;
|
|
17
|
+
}
|
|
7
18
|
/** Encrypted persistent store for Cashu ecash tokens. */
|
|
8
19
|
export declare class CashuTokenStore {
|
|
9
20
|
private readonly path;
|
|
@@ -20,6 +31,14 @@ export declare class CashuTokenStore {
|
|
|
20
31
|
/** Removes and returns the first token (FIFO). Used during Cashu melt payments. */
|
|
21
32
|
consumeFirst(): StoredToken | undefined;
|
|
22
33
|
remove(tokenStr: string): void;
|
|
34
|
+
/** Holds proofs from an unresolved melt outside the spendable pool. */
|
|
35
|
+
reserve(token: ReservedToken): void;
|
|
36
|
+
listReserved(): ReservedToken[];
|
|
37
|
+
getReserved(paymentHash: string): ReservedToken | undefined;
|
|
38
|
+
/** The melt definitely failed: the reserved proofs are spendable again. */
|
|
39
|
+
releaseReserved(paymentHash: string): boolean;
|
|
40
|
+
/** The melt settled: the reserved proofs are spent and can be forgotten. */
|
|
41
|
+
dropReserved(paymentHash: string): boolean;
|
|
23
42
|
/** Returns all tokens from a specific mint (URL normalised — trailing slashes ignored). */
|
|
24
43
|
listByMint(mintUrl: string): StoredToken[];
|
|
25
44
|
/** Removes specific tokens from the store (matched by token string). */
|
|
@@ -38,6 +38,36 @@ export class CashuTokenStore {
|
|
|
38
38
|
this.data.tokens = this.data.tokens.filter(t => t.token !== tokenStr);
|
|
39
39
|
this.save();
|
|
40
40
|
}
|
|
41
|
+
/** Holds proofs from an unresolved melt outside the spendable pool. */
|
|
42
|
+
reserve(token) {
|
|
43
|
+
this.data.reserved = [...(this.data.reserved ?? []), token];
|
|
44
|
+
this.save();
|
|
45
|
+
}
|
|
46
|
+
listReserved() {
|
|
47
|
+
return [...(this.data.reserved ?? [])];
|
|
48
|
+
}
|
|
49
|
+
getReserved(paymentHash) {
|
|
50
|
+
return this.data.reserved?.find(t => t.paymentHash === paymentHash);
|
|
51
|
+
}
|
|
52
|
+
/** The melt definitely failed: the reserved proofs are spendable again. */
|
|
53
|
+
releaseReserved(paymentHash) {
|
|
54
|
+
const found = this.getReserved(paymentHash);
|
|
55
|
+
if (!found)
|
|
56
|
+
return false;
|
|
57
|
+
this.data.reserved = (this.data.reserved ?? []).filter(t => t !== found);
|
|
58
|
+
this.data.tokens.push({ token: found.token, mint: found.mint, amountSats: found.amountSats, addedAt: found.addedAt });
|
|
59
|
+
this.save();
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
/** The melt settled: the reserved proofs are spent and can be forgotten. */
|
|
63
|
+
dropReserved(paymentHash) {
|
|
64
|
+
const before = this.data.reserved?.length ?? 0;
|
|
65
|
+
this.data.reserved = (this.data.reserved ?? []).filter(t => t.paymentHash !== paymentHash);
|
|
66
|
+
if (this.data.reserved.length === before)
|
|
67
|
+
return false;
|
|
68
|
+
this.save();
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
41
71
|
/** Returns all tokens from a specific mint (URL normalised — trailing slashes ignored). */
|
|
42
72
|
listByMint(mintUrl) {
|
|
43
73
|
const normalised = mintUrl.replace(/\/+$/, '');
|
|
@@ -69,6 +99,8 @@ export class CashuTokenStore {
|
|
|
69
99
|
else {
|
|
70
100
|
this.data = { tokens: [] };
|
|
71
101
|
}
|
|
102
|
+
if (this.data.reserved !== undefined && !Array.isArray(this.data.reserved))
|
|
103
|
+
delete this.data.reserved;
|
|
72
104
|
}
|
|
73
105
|
catch {
|
|
74
106
|
this.data = { tokens: [] };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cashu-tokens.js","sourceRoot":"","sources":["../../src/store/cashu-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"cashu-tokens.js","sourceRoot":"","sources":["../../src/store/cashu-tokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export interface StoredCredential {
|
|
2
|
+
/**
|
|
3
|
+
* Origins this credential was obtained from, and the only ones it may be
|
|
4
|
+
* sent to. Absent on credentials keyed by their origin, and on older ones.
|
|
5
|
+
*/
|
|
6
|
+
origins?: string[];
|
|
2
7
|
macaroon: string;
|
|
3
8
|
preimage: string;
|
|
4
9
|
paymentHash: string;
|
|
@@ -84,6 +84,7 @@ export class CredentialStore {
|
|
|
84
84
|
this.purgeExpired();
|
|
85
85
|
return Object.entries(this.data).map(([origin, cred]) => ({
|
|
86
86
|
origin,
|
|
87
|
+
...(cred.origins ? { origins: cred.origins } : {}),
|
|
87
88
|
paymentHash: cred.paymentHash,
|
|
88
89
|
creditBalance: cred.creditBalance,
|
|
89
90
|
storedAt: cred.storedAt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/store/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/store/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAqB/E,wFAAwF;AACxF,MAAM,OAAO,eAAe;IAOG;IAN7B,wEAAwE;IACxE,MAAM,CAAU,UAAU,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAA;IAE5C,IAAI,GAAqC,EAAE,CAAA;IAC3C,GAAG,GAAkB,IAAI,CAAA;IAEjC,YAA6B,IAAY;QAAZ,SAAI,GAAJ,IAAI,CAAQ;QACvC,mCAAmC;IACrC,CAAC;IAED,iGAAiG;IACjG,KAAK,CAAC,IAAI;QACR,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAA;QACrC,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;QACrB,IAAI,CAAC,IAAI,EAAE,CAAA;QACX,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;IACrC,CAAC;IAEO,SAAS,CAAC,IAAsB;QACtC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,GAAG,eAAe,CAAC,UAAU,CAAA;IACpF,CAAC;IAEO,YAAY;QAClB,IAAI,OAAO,GAAG,KAAK,CAAA;QACnB,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBACxB,OAAO,GAAG,IAAI,CAAA;YAChB,CAAC;QACH,CAAC;QACD,IAAI,OAAO;YAAE,IAAI,CAAC,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED,GAAG,CAAC,MAAc;QAChB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAA;QAC3B,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACnB,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,GAAG,CAAC,MAAc,EAAE,UAA4B;QAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,UAAU,CAAA;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,MAAM,CAAC,MAAc;QACnB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACxB,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,aAAa,CAAC,MAAc,EAAE,OAAe;QAC3C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,IAAI,IAAI;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAC7B,OAAM;QACR,CAAC;QACD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAA;QAC5B,IAAI,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACxC,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,cAAc,CAAC,MAAc;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAC9B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAClC,IAAI,IAAI;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAC7B,OAAM;QACR,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QACxC,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;IAED,IAAI;QACF,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACxD,MAAM;YACN,GAAG,IAAI;SACR,CAAC,CAAC,CAAA;IACL,CAAC;IAED,8EAA8E;IAC9E,QAAQ;QACN,IAAI,CAAC,YAAY,EAAE,CAAA;QACnB,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACxD,MAAM;YACN,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC,CAAA;IACL,CAAC;IAED,KAAK;QACH,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAA;IACtC,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAM;QAClC,IAAI,CAAC;YACH,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;YACjE,IAAI,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,GAAI,CAAC,CAAA;gBACpC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAqC,CAAA;YAClE,CAAC;iBAAM,CAAC;gBACN,4BAA4B;gBAC5B,IAAI,CAAC,IAAI,GAAG,GAAuC,CAAA;gBACnD,IAAI,CAAC,IAAI,EAAE,CAAA,CAAC,uBAAuB;YACrC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YAAC,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA;QAAC,CAAC;IAC5B,CAAC;IAEO,IAAI;QACV,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YAChD,IAAI,CAAC;gBAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG;YACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,CAAC,CAAC,IAAI,CAAA;QAER,6EAA6E;QAC7E,gEAAgE;QAChE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,MAAM,CAAA;QAClC,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;QAChD,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC;YAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,wBAAwB,CAAC,CAAC;IACxE,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A payment whose outcome is unknown: the wallet may have paid, and nothing
|
|
3
|
+
* has yet proved or disproved it. While one is outstanding for a service,
|
|
4
|
+
* auto-pay to that service is refused so the same thing is not bought twice.
|
|
5
|
+
*/
|
|
6
|
+
export interface PendingPayment {
|
|
7
|
+
paymentHash: string;
|
|
8
|
+
/** Origins this payment was made for. Auto-pay to any of them is blocked. */
|
|
9
|
+
origins: string[];
|
|
10
|
+
/** Service pubkey from l402-search, when the request carried one. */
|
|
11
|
+
pubkey?: string;
|
|
12
|
+
invoice: string;
|
|
13
|
+
costSats: number | null;
|
|
14
|
+
protocol: 'l402' | 'ietf-payment';
|
|
15
|
+
/** Wallet method that attempted the payment. */
|
|
16
|
+
method: string;
|
|
17
|
+
/** L402 macaroon, so a settled payment can still become a credential. */
|
|
18
|
+
macaroon?: string;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
}
|
|
21
|
+
/** Encrypted persistent record of unknown-outcome payments, keyed by payment hash. */
|
|
22
|
+
export declare class PendingPaymentStore {
|
|
23
|
+
private readonly path;
|
|
24
|
+
private data;
|
|
25
|
+
private key;
|
|
26
|
+
constructor(path: string);
|
|
27
|
+
init(): Promise<void>;
|
|
28
|
+
add(entry: PendingPayment): void;
|
|
29
|
+
get(paymentHash: string): PendingPayment | undefined;
|
|
30
|
+
remove(paymentHash: string): boolean;
|
|
31
|
+
list(): PendingPayment[];
|
|
32
|
+
/** Unresolved payments made to any of these origins, or to this service pubkey. */
|
|
33
|
+
unresolvedFor(origins: string[], pubkey?: string): PendingPayment[];
|
|
34
|
+
private load;
|
|
35
|
+
private save;
|
|
36
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, renameSync, mkdirSync, existsSync, chmodSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { getOrCreateKey, encrypt, decrypt, isEncrypted } from './encryption.js';
|
|
4
|
+
const PAYMENT_HASH_RE = /^[0-9a-f]{64}$/;
|
|
5
|
+
/** Bound on stored entries; an agent cannot grow the file without limit. */
|
|
6
|
+
const MAX_ENTRIES = 500;
|
|
7
|
+
/** Encrypted persistent record of unknown-outcome payments, keyed by payment hash. */
|
|
8
|
+
export class PendingPaymentStore {
|
|
9
|
+
path;
|
|
10
|
+
data = {};
|
|
11
|
+
key = null;
|
|
12
|
+
constructor(path) {
|
|
13
|
+
this.path = path;
|
|
14
|
+
}
|
|
15
|
+
async init() {
|
|
16
|
+
this.key = (await getOrCreateKey()).key;
|
|
17
|
+
this.load();
|
|
18
|
+
}
|
|
19
|
+
add(entry) {
|
|
20
|
+
if (!PAYMENT_HASH_RE.test(entry.paymentHash))
|
|
21
|
+
return;
|
|
22
|
+
if (!(entry.paymentHash in this.data) && Object.keys(this.data).length >= MAX_ENTRIES) {
|
|
23
|
+
// Refusing to record would let a re-pay through, so the oldest entry
|
|
24
|
+
// goes instead. With this many unresolved payments every origin in the
|
|
25
|
+
// list is blocked anyway.
|
|
26
|
+
const oldest = Object.values(this.data).sort((a, b) => a.createdAt.localeCompare(b.createdAt))[0];
|
|
27
|
+
if (oldest)
|
|
28
|
+
delete this.data[oldest.paymentHash];
|
|
29
|
+
}
|
|
30
|
+
this.data[entry.paymentHash] = entry;
|
|
31
|
+
this.save();
|
|
32
|
+
}
|
|
33
|
+
get(paymentHash) {
|
|
34
|
+
return this.data[paymentHash.toLowerCase()];
|
|
35
|
+
}
|
|
36
|
+
remove(paymentHash) {
|
|
37
|
+
const hash = paymentHash.toLowerCase();
|
|
38
|
+
if (!(hash in this.data))
|
|
39
|
+
return false;
|
|
40
|
+
delete this.data[hash];
|
|
41
|
+
this.save();
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
list() {
|
|
45
|
+
return Object.values(this.data);
|
|
46
|
+
}
|
|
47
|
+
/** Unresolved payments made to any of these origins, or to this service pubkey. */
|
|
48
|
+
unresolvedFor(origins, pubkey) {
|
|
49
|
+
const wanted = new Set(origins);
|
|
50
|
+
return this.list().filter(p => p.origins.some(o => wanted.has(o)) || (pubkey !== undefined && p.pubkey === pubkey));
|
|
51
|
+
}
|
|
52
|
+
load() {
|
|
53
|
+
if (!existsSync(this.path))
|
|
54
|
+
return;
|
|
55
|
+
try {
|
|
56
|
+
const raw = JSON.parse(readFileSync(this.path, 'utf-8'));
|
|
57
|
+
const parsed = isEncrypted(raw) ? JSON.parse(decrypt(raw, this.key)) : raw;
|
|
58
|
+
this.data = typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)
|
|
59
|
+
? parsed
|
|
60
|
+
: {};
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// An unreadable ledger must not silently unblock auto-pay. Keep the
|
|
64
|
+
// file for inspection and refuse to start rather than overwrite it.
|
|
65
|
+
throw new Error(`Cannot read the unresolved-payment ledger at ${this.path}. Move it aside only once every payment in it has been checked in your wallet.`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
save() {
|
|
69
|
+
const dir = dirname(this.path);
|
|
70
|
+
if (!existsSync(dir)) {
|
|
71
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
72
|
+
try {
|
|
73
|
+
chmodSync(dir, 0o700);
|
|
74
|
+
}
|
|
75
|
+
catch { /* Windows safety net */ }
|
|
76
|
+
}
|
|
77
|
+
const json = JSON.stringify(this.data, null, 2);
|
|
78
|
+
const content = this.key ? JSON.stringify(encrypt(json, this.key), null, 2) : json;
|
|
79
|
+
const tmpPath = this.path + '.tmp';
|
|
80
|
+
writeFileSync(tmpPath, content, { mode: 0o600 });
|
|
81
|
+
renameSync(tmpPath, this.path);
|
|
82
|
+
try {
|
|
83
|
+
chmodSync(this.path, 0o600);
|
|
84
|
+
}
|
|
85
|
+
catch { /* Windows safety net */ }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=pending-payments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pending-payments.js","sourceRoot":"","sources":["../../src/store/pending-payments.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,8 @@ import type { WalletMethod } from '../wallet/types.js';
|
|
|
3
3
|
import type { DecodedInvoice } from '../l402/bolt11.js';
|
|
4
4
|
import type { ResilientFetchOptions } from '../fetch/resilient-fetch.js';
|
|
5
5
|
import type { SpendTracker } from '../spend-tracker.js';
|
|
6
|
+
import type { PendingPayment } from '../store/pending-payments.js';
|
|
7
|
+
import type { ChallengeCache } from '../l402/challenge-cache.js';
|
|
6
8
|
export interface BuyCreditsDeps {
|
|
7
9
|
fetchFn: (url: string | URL, init?: RequestInit, options?: ResilientFetchOptions) => Promise<Response>;
|
|
8
10
|
payInvoice: (invoice: string, options?: {
|
|
@@ -25,6 +27,13 @@ export interface BuyCreditsDeps {
|
|
|
25
27
|
text: string;
|
|
26
28
|
}>;
|
|
27
29
|
walletMethod: () => WalletMethod | undefined;
|
|
30
|
+
/** Ledger of unknown-outcome payments; any entry for a service pauses payment to it. */
|
|
31
|
+
pendingPayments: {
|
|
32
|
+
add(entry: PendingPayment): void;
|
|
33
|
+
unresolvedFor(origins: string[], pubkey?: string): PendingPayment[];
|
|
34
|
+
};
|
|
35
|
+
/** Where an unpaid invoice is kept so l402-pay can settle it by paymentHash. */
|
|
36
|
+
challengeCache?: ChallengeCache;
|
|
28
37
|
}
|
|
29
38
|
/** Purchases a volume discount credit tier from a toll-booth server. */
|
|
30
39
|
export declare function handleBuyCredits(args: {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { safeErrorMessage } from './safe-error.js';
|
|
3
|
+
const RECONCILE_HINT = 'Call l402-reconcile with this paymentHash before paying this service again.';
|
|
3
4
|
const CreateInvoiceResponse = z.object({
|
|
4
5
|
bolt11: z.string().min(1).max(20_000),
|
|
5
6
|
macaroon: z.string().min(1).max(10_000),
|
|
@@ -33,6 +34,20 @@ export async function handleBuyCredits(args, deps) {
|
|
|
33
34
|
}],
|
|
34
35
|
};
|
|
35
36
|
}
|
|
37
|
+
// Purchase mode: an earlier payment to this service may have gone through
|
|
38
|
+
const unresolved = deps.pendingPayments.unresolvedFor([origin]);
|
|
39
|
+
if (unresolved.length > 0) {
|
|
40
|
+
return {
|
|
41
|
+
content: [{
|
|
42
|
+
type: 'text',
|
|
43
|
+
text: JSON.stringify({
|
|
44
|
+
error: `Payment to this service is paused: ${unresolved.length} earlier payment(s) to it have an unknown outcome. Call l402-reconcile with each paymentHash first.`,
|
|
45
|
+
unresolvedPayments: unresolved.map(p => p.paymentHash),
|
|
46
|
+
}),
|
|
47
|
+
}],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
36
51
|
// Purchase mode: create invoice and pay
|
|
37
52
|
const response = await deps.fetchFn(`${origin}/create-invoice`, {
|
|
38
53
|
method: 'POST',
|
|
@@ -101,7 +116,7 @@ export async function handleBuyCredits(args, deps) {
|
|
|
101
116
|
return {
|
|
102
117
|
content: [{
|
|
103
118
|
type: 'text',
|
|
104
|
-
text: JSON.stringify({ error: '
|
|
119
|
+
text: JSON.stringify({ error: deps.spendTracker.refusal(spendAmount, deps.maxSpendPerMinuteSats) ?? 'Spend limit reached.' }),
|
|
105
120
|
}],
|
|
106
121
|
isError: true,
|
|
107
122
|
};
|
|
@@ -111,6 +126,18 @@ export async function handleBuyCredits(args, deps) {
|
|
|
111
126
|
if (!payResult.paid && payResult.outcome !== 'unknown') {
|
|
112
127
|
deps.spendTracker.unrecord(spendAmount);
|
|
113
128
|
}
|
|
129
|
+
if ((payResult.outcome === 'unknown' || (payResult.paid && !payResult.preimage)) && decoded.paymentHash) {
|
|
130
|
+
deps.pendingPayments.add({
|
|
131
|
+
paymentHash: decoded.paymentHash,
|
|
132
|
+
origins: [origin],
|
|
133
|
+
invoice,
|
|
134
|
+
costSats: decoded.costSats,
|
|
135
|
+
protocol: 'l402',
|
|
136
|
+
method: payResult.method,
|
|
137
|
+
macaroon,
|
|
138
|
+
createdAt: new Date().toISOString(),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
114
141
|
if (payResult.outcome === 'unknown') {
|
|
115
142
|
return {
|
|
116
143
|
content: [{
|
|
@@ -121,7 +148,7 @@ export async function handleBuyCredits(args, deps) {
|
|
|
121
148
|
amountSats: args.amountSats,
|
|
122
149
|
paymentHash: decoded.paymentHash,
|
|
123
150
|
method: payResult.method,
|
|
124
|
-
message: payResult.reason ??
|
|
151
|
+
message: payResult.reason ?? `Payment may have executed. ${RECONCILE_HINT}`,
|
|
125
152
|
}, null, 2),
|
|
126
153
|
}],
|
|
127
154
|
isError: true,
|
|
@@ -154,7 +181,7 @@ export async function handleBuyCredits(args, deps) {
|
|
|
154
181
|
amountSats: args.amountSats,
|
|
155
182
|
paymentHash: decoded.paymentHash,
|
|
156
183
|
method: payResult.method,
|
|
157
|
-
message:
|
|
184
|
+
message: `The wallet reported payment without a settlement preimage. ${RECONCILE_HINT}`,
|
|
158
185
|
}, null, 2),
|
|
159
186
|
}],
|
|
160
187
|
isError: true,
|
|
@@ -162,6 +189,16 @@ export async function handleBuyCredits(args, deps) {
|
|
|
162
189
|
}
|
|
163
190
|
// Human wallet timed out — return QR so user can pay manually
|
|
164
191
|
if (payResult.method === 'human') {
|
|
192
|
+
if (decoded.paymentHash) {
|
|
193
|
+
deps.challengeCache?.set({
|
|
194
|
+
invoice,
|
|
195
|
+
macaroon,
|
|
196
|
+
paymentHash: decoded.paymentHash,
|
|
197
|
+
costSats: decoded.costSats,
|
|
198
|
+
expiresAt: Date.now() + decoded.expiry * 1000,
|
|
199
|
+
url: args.url,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
165
202
|
let qrText;
|
|
166
203
|
let qrPngBase64;
|
|
167
204
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buy-credits.js","sourceRoot":"","sources":["../../src/tools/buy-credits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"buy-credits.js","sourceRoot":"","sources":["../../src/tools/buy-credits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAQvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAElD,MAAM,cAAc,GAAG,6EAA6E,CAAA;AAEpG,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IACrC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC;IACvC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACnC,CAAC,CAAA;AAqBF,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAiE,EACjE,IAAoB;IAEpB,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAA;IAEvC,IAAI,CAAC;QACH,yEAAyE;QACzE,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;YAClC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAA;YAEhE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,OAAO;oBACL,OAAO,EAAE,CAAC;4BACR,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,wBAAwB,QAAQ,CAAC,MAAM,qCAAqC,EAAE,CAAC;yBAC9G,CAAC;oBACF,OAAO,EAAE,IAAa;iBACvB,CAAA;YACH,CAAC;YAED,IAAI,IAAI,GAA4B,EAAE,CAAA;YACtC,IAAI,CAAC;gBAAC,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA6B,CAAA;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;YAExF,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBAClE,CAAC;aACH,CAAA;QACH,CAAC;QAED,0EAA0E;QAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;QAC/D,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,sCAAsC,UAAU,CAAC,MAAM,qGAAqG;4BACnK,kBAAkB,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;yBACvD,CAAC;qBACH,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QAED,wCAAwC;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,MAAM,iBAAiB,EAAE;YAC9D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC;SACtD,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QAElB,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kCAAkC,QAAQ,CAAC,MAAM,GAAG,EAAE,CAAC;qBACtF,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QAED,MAAM,GAAG,GAAY,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAC1C,MAAM,SAAS,GAAG,qBAAqB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACtD,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACvB,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,+DAA+D,EAAE,CAAC;qBACjG,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QACD,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,SAAS,CAAC,IAAI,CAAA;QAE7E,2EAA2E;QAC3E,4EAA4E;QAC5E,8CAA8C;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,CAAA;QAC1C,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC9B,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,yGAAyG,EAAE,CAAC;qBAC3I,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC;YACzC,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,mBAAmB,OAAO,CAAC,QAAQ,2CAA2C,IAAI,CAAC,UAAU,0BAA0B,EAAE,CAAC;qBACzJ,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QAED,sEAAsE;QACtE,gFAAgF;QAChF,+DAA+D;QAC/D,MAAM,eAAe,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY,EAAE,CAAA;QAC1D,IAAI,eAAe,KAAK,OAAO,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;YAC1E,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,OAAO,CAAC,QAAQ,oCAAoC,IAAI,CAAC,cAAc,uDAAuD,EAAE,CAAC;qBAC1K,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QAED,gFAAgF;QAChF,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAA;QACpC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,CAAC,qBAAqB,CAAC,EAAE,CAAC;YAC1E,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,qBAAqB,CAAC,IAAI,sBAAsB,EAAE,CAAC;qBAC9H,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAA;QAE/F,sDAAsD;QACtD,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACvD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;QACzC,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACxG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC;gBACvB,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,OAAO,EAAE,CAAC,MAAM,CAAC;gBACjB,OAAO;gBACP,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,SAAS,CAAC,MAAM;gBACxB,QAAQ;gBACR,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC,CAAA;QACJ,CAAC;QAED,IAAI,SAAS,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YACpC,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,IAAI,EAAE,KAAK;4BACX,YAAY,EAAE,SAAS;4BACvB,UAAU,EAAE,IAAI,CAAC,UAAU;4BAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;4BAChC,MAAM,EAAE,SAAS,CAAC,MAAM;4BACxB,OAAO,EAAE,SAAS,CAAC,MAAM,IAAI,8BAA8B,cAAc,EAAE;yBAC5E,EAAE,IAAI,EAAE,CAAC,CAAC;qBACZ,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QAED,IAAI,SAAS,CAAC,IAAI,IAAI,SAAS,CAAC,QAAQ,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAA;YAEpG,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,IAAI,EAAE,IAAI;4BACV,UAAU,EAAE,IAAI,CAAC,UAAU;4BAC3B,eAAe,EAAE,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;4BACnE,iBAAiB,EAAE,MAAM;4BACzB,MAAM,EAAE,SAAS,CAAC,MAAM;4BACxB,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,kFAAkF,EAAE,CAAC;yBACnH,EAAE,IAAI,EAAE,CAAC,CAAC;qBACZ,CAAC;gBACF,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAa,EAAE,CAAC;aAC9C,CAAA;QACH,CAAC;QAED,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;YACnB,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,IAAI,EAAE,KAAK;4BACX,YAAY,EAAE,SAAS;4BACvB,UAAU,EAAE,IAAI,CAAC,UAAU;4BAC3B,WAAW,EAAE,OAAO,CAAC,WAAW;4BAChC,MAAM,EAAE,SAAS,CAAC,MAAM;4BACxB,OAAO,EAAE,8DAA8D,cAAc,EAAE;yBACxF,EAAE,IAAI,EAAE,CAAC,CAAC;qBACZ,CAAC;gBACF,OAAO,EAAE,IAAa;aACvB,CAAA;QACH,CAAC;QAED,8DAA8D;QAC9D,IAAI,SAAS,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACxB,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC;oBACvB,OAAO;oBACP,QAAQ;oBACR,WAAW,EAAE,OAAO,CAAC,WAAW;oBAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI;oBAC7C,GAAG,EAAE,IAAI,CAAC,GAAG;iBACd,CAAC,CAAA;YACJ,CAAC;YACD,IAAI,MAA0B,CAAA;YAC9B,IAAI,WAA+B,CAAA;YACnC,IAAI,CAAC;gBACH,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;gBACzC,MAAM,GAAG,EAAE,CAAC,IAAI,CAAA;gBAChB,WAAW,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,0BAA0B,EAAE,EAAE,CAAC,CAAA;YAC9D,CAAC;YAAC,MAAM,CAAC;gBACP,yDAAyD;YAC3D,CAAC;YAED,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC1B,IAAI,EAAE,KAAK;gBACX,OAAO;gBACP,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,QAAQ,EAAE,IAAI,CAAC,UAAU;gBACzB,OAAO,EAAE,kBAAkB,IAAI,CAAC,UAAU,2DAA2D;aACtG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;YAEX,+EAA+E;YAC/E,MAAM,OAAO,GAA8F,CAAC;oBAC1G,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI;iBAC7C,CAAC,CAAA;YAEF,IAAI,WAAW,EAAE,CAAC;gBAChB,OAAO,CAAC,IAAI,CAAC;oBACX,IAAI,EAAE,OAAgB;oBACtB,IAAI,EAAE,WAAW;oBACjB,QAAQ,EAAE,WAAW;iBACtB,CAAC,CAAA;YACJ,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,CAAA;QACpB,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;iBAChE,CAAC;YACF,OAAO,EAAE,IAAa;SACvB,CAAA;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,OAAO,EAAE,CAAC;oBACR,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;iBACvD,CAAC;YACF,OAAO,EAAE,IAAa;SACvB,CAAA;IACH,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,IAAoB;IAC5E,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB;QACE,WAAW,EAAE,8LAA8L;QAC3M,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;QAC3D,WAAW,EAAE;YACX,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;YAClD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;YACxH,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC;SACzF;KACF,EACD,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,CAC7C,CAAA;AACH,CAAC"}
|
package/build/tools/config.d.ts
CHANGED
|
@@ -4,6 +4,11 @@ export interface ConfigState {
|
|
|
4
4
|
cashuConfigured: boolean;
|
|
5
5
|
cashuBalanceSats: number;
|
|
6
6
|
maxAutoPaySats: number;
|
|
7
|
+
/** Rolling 60-second cap; 0 blocks auto-pay. */
|
|
8
|
+
maxSpendPerMinuteSats?: number;
|
|
9
|
+
/** Rolling 24-hour cap, persisted; 0 blocks auto-pay. */
|
|
10
|
+
maxSpendPerDaySats?: number;
|
|
11
|
+
spentLast24HoursSats?: number;
|
|
7
12
|
credentialCount: number;
|
|
8
13
|
}
|
|
9
14
|
/** Returns the agent's current payment capabilities and configuration. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/tools/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/tools/config.ts"],"names":[],"mappings":"AAeA,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAAC,KAAkB;IAC7C,OAAO;QACL,OAAO,EAAE,CAAC;gBACR,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;aACrC,CAAC;KACH,CAAA;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,kBAAkB,CAChC,MAAiB,EACjB,QAA2B;IAE3B,MAAM,CAAC,YAAY,CACjB,aAAa,EACb;QACE,WAAW,EAAE,2LAA2L;QACxM,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE,EAAE;KAChB,EACD,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC,CAC/B,CAAA;AACH,CAAC"}
|