@absol-labs/agent 0.12.0-rc.2 → 0.12.0-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/cli/commands/claim.d.ts +15 -0
  2. package/dist/cli/commands/claim.d.ts.map +1 -1
  3. package/dist/cli/commands/claim.js +65 -23
  4. package/dist/cli/commands/claim.js.map +1 -1
  5. package/dist/cli/commands/pay.d.ts +10 -0
  6. package/dist/cli/commands/pay.d.ts.map +1 -1
  7. package/dist/cli/commands/pay.js +246 -50
  8. package/dist/cli/commands/pay.js.map +1 -1
  9. package/dist/cli/commands/refund.d.ts +23 -12
  10. package/dist/cli/commands/refund.d.ts.map +1 -1
  11. package/dist/cli/commands/refund.js +104 -131
  12. package/dist/cli/commands/refund.js.map +1 -1
  13. package/dist/cli/deps.d.ts +6 -0
  14. package/dist/cli/deps.d.ts.map +1 -1
  15. package/dist/cli/deps.js +3 -0
  16. package/dist/cli/deps.js.map +1 -1
  17. package/dist/cli/errors.d.ts +8 -1
  18. package/dist/cli/errors.d.ts.map +1 -1
  19. package/dist/cli/errors.js.map +1 -1
  20. package/dist/cli/status.d.ts +6 -0
  21. package/dist/cli/status.d.ts.map +1 -1
  22. package/dist/cli/status.js +25 -6
  23. package/dist/cli/status.js.map +1 -1
  24. package/dist/gateway/x402-opener-mode.d.ts.map +1 -1
  25. package/dist/gateway/x402-opener-mode.js +104 -7
  26. package/dist/gateway/x402-opener-mode.js.map +1 -1
  27. package/dist/mcp/server.d.ts +10 -0
  28. package/dist/mcp/server.d.ts.map +1 -1
  29. package/dist/mcp/server.js +21 -1
  30. package/dist/mcp/server.js.map +1 -1
  31. package/dist/mcp/x402-tools.d.ts +7 -1
  32. package/dist/mcp/x402-tools.d.ts.map +1 -1
  33. package/dist/mcp/x402-tools.js +159 -6
  34. package/dist/mcp/x402-tools.js.map +1 -1
  35. package/dist/x402-buyer/index.d.ts +1 -0
  36. package/dist/x402-buyer/index.d.ts.map +1 -1
  37. package/dist/x402-buyer/index.js +1 -0
  38. package/dist/x402-buyer/index.js.map +1 -1
  39. package/dist/x402-buyer/pay.d.ts +38 -2
  40. package/dist/x402-buyer/pay.d.ts.map +1 -1
  41. package/dist/x402-buyer/pay.js +52 -2
  42. package/dist/x402-buyer/pay.js.map +1 -1
  43. package/dist/x402-buyer/refund-actions.d.ts +168 -0
  44. package/dist/x402-buyer/refund-actions.d.ts.map +1 -0
  45. package/dist/x402-buyer/refund-actions.js +351 -0
  46. package/dist/x402-buyer/refund-actions.js.map +1 -0
  47. package/dist/x402-opener/block-floors.d.ts +35 -0
  48. package/dist/x402-opener/block-floors.d.ts.map +1 -0
  49. package/dist/x402-opener/block-floors.js +72 -0
  50. package/dist/x402-opener/block-floors.js.map +1 -0
  51. package/dist/x402-opener/facilitator-server.d.ts.map +1 -1
  52. package/dist/x402-opener/facilitator-server.js +7 -0
  53. package/dist/x402-opener/facilitator-server.js.map +1 -1
  54. package/dist/x402-opener/index.d.ts +1 -0
  55. package/dist/x402-opener/index.d.ts.map +1 -1
  56. package/dist/x402-opener/index.js +1 -0
  57. package/dist/x402-opener/index.js.map +1 -1
  58. package/dist/x402-opener/refund-relay.d.ts +62 -1
  59. package/dist/x402-opener/refund-relay.d.ts.map +1 -1
  60. package/dist/x402-opener/refund-relay.js +387 -208
  61. package/dist/x402-opener/refund-relay.js.map +1 -1
  62. package/dist/x402-opener/scheme.d.ts +8 -0
  63. package/dist/x402-opener/scheme.d.ts.map +1 -1
  64. package/dist/x402-opener/scheme.js +14 -0
  65. package/dist/x402-opener/scheme.js.map +1 -1
  66. package/docs/cli.md +62 -9
  67. package/docs/mcp-reference.md +23 -0
  68. package/docs/x402.md +126 -29
  69. package/package.json +2 -2
  70. package/src/cli/commands/claim.ts +72 -30
  71. package/src/cli/commands/pay.ts +299 -51
  72. package/src/cli/commands/refund.ts +133 -143
  73. package/src/cli/deps.ts +9 -0
  74. package/src/cli/errors.ts +8 -1
  75. package/src/cli/status.ts +28 -7
  76. package/src/gateway/x402-opener-mode.ts +131 -6
  77. package/src/mcp/server.ts +30 -1
  78. package/src/mcp/x402-tools.ts +222 -7
  79. package/src/x402-buyer/index.ts +1 -0
  80. package/src/x402-buyer/pay.ts +99 -2
  81. package/src/x402-buyer/refund-actions.ts +486 -0
  82. package/src/x402-opener/block-floors.ts +78 -0
  83. package/src/x402-opener/facilitator-server.ts +7 -0
  84. package/src/x402-opener/index.ts +1 -0
  85. package/src/x402-opener/refund-relay.ts +486 -217
  86. package/src/x402-opener/scheme.ts +38 -0
@@ -0,0 +1,351 @@
1
+ /**
2
+ * The buyer's own close + reclaim of an x402 stream, through the seller's
3
+ * gasless refund relay. ONE implementation behind `metrik refund`,
4
+ * `metrik pay --close-after`, the MCP `x402_pay` tool's `closeAfter` and
5
+ * {@link closeAfterPayment} (`@absol-labs/agent/x402-buyer`).
6
+ *
7
+ * Nothing here is an automatic refund: it runs only when the buyer asks for
8
+ * it, and it is the buyer's own client that signs the Close and asks the
9
+ * relay to send the permissionless reclaim. The relay pays the gas; the
10
+ * opener always sends the reclaim to the payer.
11
+ *
12
+ * The waits are bounded and the relay's own: `RefundClient.status()` waits
13
+ * out a `503 chain-lagging` (honouring `Retry-After`), and
14
+ * `RefundClient.reclaim()` retries, bounded by the client's `maxAttempts` /
15
+ * `maxDelayMs`, while the relay says the checkpoint covering the close is not
16
+ * posted yet.
17
+ */
18
+ /**
19
+ * After a close/reclaim, how many times the summary re-reads the relay until
20
+ * it reflects the transaction just mined (a load-balanced RPC behind the relay
21
+ * can answer from a node that has not seen it yet), and how long it waits
22
+ * between reads. Bounded: past it the summary is derived from the verified
23
+ * receipts instead.
24
+ */
25
+ export const POST_ACTION_READS = 6;
26
+ export const POST_ACTION_INTERVAL_MS = 1_500;
27
+ /**
28
+ * A close or reclaim that did not complete. `closed` says whether the stream
29
+ * is known to be closed (by this run or before it), so the caller can name the
30
+ * exact command that finishes the job. `cause` is the SDK's error, unchanged.
31
+ */
32
+ export class RefundActionsError extends Error {
33
+ stage;
34
+ closed;
35
+ closeResult;
36
+ constructor(context) {
37
+ super(`the ${context.stage} did not finish: ${context.cause instanceof Error ? context.cause.message : String(context.cause)}`, { cause: context.cause });
38
+ this.name = "RefundActionsError";
39
+ this.stage = context.stage;
40
+ this.closed = context.closed;
41
+ this.closeResult = context.closeResult;
42
+ }
43
+ }
44
+ /**
45
+ * Close and/or reclaim one x402 stream through its refund relay, then read
46
+ * the state AFTER those actions. Finished states (already closed, already
47
+ * reclaimed, nothing to reclaim) are reported, not thrown. Anything else that
48
+ * fails is a {@link RefundActionsError} carrying the SDK's error as `cause`.
49
+ */
50
+ export async function runRefundActions(input) {
51
+ const { refunds } = input;
52
+ let closeResult = null;
53
+ let closeSkipped = null;
54
+ // Set when the relay itself says there is nothing left: the stream was
55
+ // already reclaimed, or the verified delivery covers the whole deposit.
56
+ // Those are FINISHED recoveries, not failures — a second close + reclaim on
57
+ // a done stream must succeed and never point the payer at a gas-spending
58
+ // on-chain recovery that cannot recover a cent.
59
+ let finishedByRelay = null;
60
+ if (input.close) {
61
+ try {
62
+ // Ask first: a stream that is already closed (or already finished)
63
+ // needs no Close, so there is nothing to sign and no wallet is needed.
64
+ const before = await refunds.status();
65
+ const finishedBefore = finishedReason(before);
66
+ if (finishedBefore !== null || before.status === "closed") {
67
+ closeSkipped = finishedBefore ?? "already-closed";
68
+ finishedByRelay = finishedBefore;
69
+ input.note?.(finishedBefore === null
70
+ ? "stream is already closed — no Close to sign."
71
+ : `stream is already closed and ${finishedBefore === "reclaimed" ? "reclaimed" : "has nothing left to reclaim"} — no Close to sign.`);
72
+ }
73
+ else {
74
+ const signer = await input.closeSigner();
75
+ try {
76
+ closeResult = await refunds.close({ signer });
77
+ input.note?.(`close relayed in ${closeResult.transaction}${closeResult.verified ? " (receipt verified on-chain)" : ""}`);
78
+ }
79
+ catch (error) {
80
+ // The status read above said "active", but the stream closed in the
81
+ // meantime (it reached expiresAt, or another close landed): the
82
+ // state the payer asked for. Anything else is a real failure.
83
+ if (relayCode(error) !== "already-closed")
84
+ throw error;
85
+ closeSkipped = "already-closed";
86
+ input.note?.("stream was already closed — no Close was needed.");
87
+ }
88
+ }
89
+ }
90
+ catch (error) {
91
+ throw new RefundActionsError({
92
+ stage: "close",
93
+ closed: false,
94
+ closeResult: null,
95
+ cause: error,
96
+ });
97
+ }
98
+ }
99
+ let reclaimResult = null;
100
+ let reclaimSkipped = null;
101
+ if (input.reclaim) {
102
+ if (finishedByRelay !== null) {
103
+ reclaimSkipped = finishedByRelay;
104
+ }
105
+ else {
106
+ if (input.reclaimActivity !== undefined) {
107
+ input.setActivity?.(input.reclaimActivity);
108
+ }
109
+ try {
110
+ reclaimResult = await refunds.reclaim();
111
+ }
112
+ catch (error) {
113
+ const finished = finishedFromRelayCode(relayCode(error));
114
+ if (finished === null) {
115
+ throw new RefundActionsError({
116
+ stage: "reclaim",
117
+ closed: closeResult !== null || closeSkipped !== null,
118
+ closeResult,
119
+ cause: error,
120
+ });
121
+ }
122
+ reclaimSkipped = finished;
123
+ finishedByRelay = finished;
124
+ }
125
+ finally {
126
+ input.setActivity?.(null);
127
+ }
128
+ }
129
+ }
130
+ // The summary describes the state AFTER what this run did: re-read until
131
+ // the relay reflects the close/reclaim just mined (bounded), else derive it
132
+ // from the verified receipts. Never the pre-action state.
133
+ const status = await statusAfterActions(refunds, {
134
+ closed: closeResult !== null,
135
+ reclaim: reclaimResult,
136
+ payer: input.payer,
137
+ opener: input.opener,
138
+ streamId: input.streamId,
139
+ sleep: input.sleep,
140
+ });
141
+ // A reclaim THIS run performed is reported as a reclaim, not as "already
142
+ // finished".
143
+ const finished = reclaimResult === null ? (finishedReason(status) ?? finishedByRelay) : null;
144
+ return {
145
+ close: closeResult,
146
+ closeSkipped,
147
+ reclaim: reclaimResult,
148
+ reclaimSkipped,
149
+ status,
150
+ finished,
151
+ };
152
+ }
153
+ /**
154
+ * Right after a paid response, at the BUYER's request: close the stream the
155
+ * payment opened (the payer signs the Close, the relay pays the gas), wait for
156
+ * the checkpoint covering the close, and reclaim the unearned remainder to the
157
+ * payer. Never throws for a close/reclaim failure: the payment already
158
+ * succeeded, so the outcome says what did not finish instead.
159
+ *
160
+ * An upfront-only payment (no stream) has nothing to close: the outcome is
161
+ * `nothing-to-close` and nothing is requested, signed or sent.
162
+ */
163
+ export async function closeAfterPayment(input) {
164
+ const { payment } = input;
165
+ const empty = {
166
+ close: null,
167
+ closeSkipped: null,
168
+ reclaim: null,
169
+ reclaimSkipped: null,
170
+ refundedUsdc: null,
171
+ finished: null,
172
+ status: null,
173
+ };
174
+ if (payment.streamId === null || /^0x0{64}$/i.test(payment.streamId)) {
175
+ return {
176
+ ...empty,
177
+ outcome: "nothing-to-close",
178
+ streamId: null,
179
+ incomplete: null,
180
+ };
181
+ }
182
+ const streamId = payment.streamId;
183
+ if (payment.refundUrl === null) {
184
+ return {
185
+ ...empty,
186
+ outcome: "incomplete",
187
+ streamId,
188
+ incomplete: {
189
+ stage: "no-relay",
190
+ closed: false,
191
+ reason: "the seller advertised no refund relay, so there is no gasless close; the stream accrues only for verified seconds until it expires, and anyone can reclaim the unearned remainder to the payer after that",
192
+ error: null,
193
+ },
194
+ };
195
+ }
196
+ let refunds;
197
+ try {
198
+ refunds = await input.openRefunds();
199
+ }
200
+ catch (error) {
201
+ return {
202
+ ...empty,
203
+ outcome: "incomplete",
204
+ streamId,
205
+ incomplete: {
206
+ stage: "close",
207
+ closed: false,
208
+ reason: errorMessage(error),
209
+ error,
210
+ },
211
+ };
212
+ }
213
+ try {
214
+ const result = await runRefundActions({
215
+ ...input,
216
+ refunds,
217
+ streamId,
218
+ opener: payment.opener,
219
+ close: true,
220
+ reclaim: true,
221
+ });
222
+ return {
223
+ outcome: "completed",
224
+ streamId,
225
+ close: result.close,
226
+ closeSkipped: result.closeSkipped,
227
+ reclaim: result.reclaim,
228
+ reclaimSkipped: result.reclaimSkipped,
229
+ refundedUsdc: result.reclaim !== null && result.reclaim.verified
230
+ ? result.reclaim.amount
231
+ : null,
232
+ finished: result.finished,
233
+ status: result.status,
234
+ incomplete: null,
235
+ };
236
+ }
237
+ catch (error) {
238
+ if (!(error instanceof RefundActionsError))
239
+ throw error;
240
+ return {
241
+ ...empty,
242
+ outcome: "incomplete",
243
+ streamId,
244
+ close: error.closeResult,
245
+ incomplete: {
246
+ stage: error.stage,
247
+ closed: error.closed,
248
+ reason: errorMessage(error.cause),
249
+ error: error.cause,
250
+ },
251
+ };
252
+ }
253
+ }
254
+ function errorMessage(error) {
255
+ return error instanceof Error ? error.message : String(error);
256
+ }
257
+ /**
258
+ * The relay's view of a stream AFTER this run's actions. Reads until it
259
+ * reflects them (closed after a close, reclaimed after a reclaim), bounded;
260
+ * if the relay still lags, the state those verified transactions imply is
261
+ * reported instead, marked as derived. With no action, one plain read.
262
+ */
263
+ export async function statusAfterActions(refunds, done) {
264
+ const reclaimed = done.reclaim !== null;
265
+ if (!done.closed && !reclaimed)
266
+ return await refunds.status();
267
+ const reflects = (status) => (!done.closed || status.status === "closed" || status.reclaimed) &&
268
+ (!reclaimed || status.reclaimed);
269
+ let last = null;
270
+ for (let attempt = 1; attempt <= POST_ACTION_READS; attempt++) {
271
+ try {
272
+ const status = await refunds.status();
273
+ if (reflects(status))
274
+ return status;
275
+ last = status;
276
+ }
277
+ catch {
278
+ // A lagging relay (503 chain-lagging, a stale not-found, a blip): the
279
+ // transactions already happened, so keep going and derive if need be.
280
+ }
281
+ if (attempt < POST_ACTION_READS)
282
+ await done.sleep(POST_ACTION_INTERVAL_MS);
283
+ }
284
+ return derivedStatus(last, done);
285
+ }
286
+ /** The state this run's verified close/reclaim imply, when the relay lags. */
287
+ function derivedStatus(last, done) {
288
+ const reclaimed = done.reclaim !== null;
289
+ const note = "derived from this run's transaction receipts; the refund relay had not caught up with them yet";
290
+ return {
291
+ streamId: done.streamId,
292
+ chainId: last?.chainId ?? 0,
293
+ opener: last?.opener ?? done.opener,
294
+ payer: last?.payer ?? done.payer ?? done.opener,
295
+ status: "closed",
296
+ reclaimed: reclaimed || (last?.reclaimed ?? false),
297
+ chainTime: last?.chainTime ?? null,
298
+ reclaimable: null,
299
+ // Both legs this run verified are on-chain facts: the stream is closed.
300
+ state: "closed",
301
+ onChainStatus: "closed",
302
+ maxRefund: last?.maxRefund ?? null,
303
+ maxRefundMeaning: last?.maxRefundMeaning ?? null,
304
+ reclaimableMeaning: last?.reclaimableMeaning ?? null,
305
+ next: reclaimed
306
+ ? {
307
+ action: "none",
308
+ message: "Reclaimed: the unearned remainder was returned to the payer. Nothing further to do.",
309
+ }
310
+ : {
311
+ action: "reclaim",
312
+ message: "Closed. Reclaim the unearned remainder once a checkpoint covering the close is posted (usually within a minute).",
313
+ },
314
+ raw: { derived: true, note },
315
+ };
316
+ }
317
+ /**
318
+ * Whether the relay's status says nothing is left to recover. `reclaimed` is
319
+ * the chain's one-reclaim-per-stream flag; `next: none` with `reclaimable: 0`
320
+ * is the relay's "the verified delivery covers the whole deposit".
321
+ */
322
+ export function finishedReason(status) {
323
+ if (status.reclaimed)
324
+ return "reclaimed";
325
+ if (status.next.action === "none" && status.reclaimable === 0n) {
326
+ return "nothing-to-reclaim";
327
+ }
328
+ return null;
329
+ }
330
+ /** The relay's 409 codes that mean "finished", not "failed". */
331
+ function finishedFromRelayCode(code) {
332
+ if (code === "already-reclaimed")
333
+ return "reclaimed";
334
+ if (code === "nothing-to-reclaim")
335
+ return "nothing-to-reclaim";
336
+ return null;
337
+ }
338
+ /** The relay's refusal code, looked up through a few `cause` links. */
339
+ export function relayCode(error) {
340
+ for (let current = error, depth = 0; depth < 4; depth++) {
341
+ if (!(current instanceof Error))
342
+ return null;
343
+ const code = current.code;
344
+ if (current.name === "RefundRelayError" && typeof code === "string") {
345
+ return code;
346
+ }
347
+ current = current.cause;
348
+ }
349
+ return null;
350
+ }
351
+ //# sourceMappingURL=refund-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refund-actions.js","sourceRoot":"","sources":["../../src/x402-buyer/refund-actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The lowest block a read about a stream must be served from, per stream.
3
+ *
4
+ * A public RPC endpoint is usually a load balancer over several nodes that are
5
+ * not all at the same height: the node that returned a transaction's receipt
6
+ * can be a block or two ahead of the node that answers the next `eth_call` at
7
+ * `latest`. Right after the facilitator settles a payment (or the refund relay
8
+ * mines a close or reclaim), a read at `latest` can therefore still see the
9
+ * stream as it was BEFORE that transaction — not opened yet, still active,
10
+ * not reclaimed (live finding 2026-10-03: the relay answered `not-found` for a
11
+ * stream it had settled half a second earlier).
12
+ *
13
+ * Whoever observes a mined receipt for a stream records its block here; the
14
+ * refund relay then refuses to answer from any block below it (it waits,
15
+ * bounded, for the RPC to catch up and pins every read of one answer to one
16
+ * block). In-memory, per process, bounded; an entry only ever raises.
17
+ */
18
+ export declare class StreamBlockFloors {
19
+ private readonly options;
20
+ private readonly floors;
21
+ constructor(options?: {
22
+ /** How long an entry is kept, ms. Default 1 h. */
23
+ readonly ttlMs?: number;
24
+ /** Hard cap on entries (oldest dropped first). Default 10 000. */
25
+ readonly maxEntries?: number;
26
+ readonly nowMs?: () => number;
27
+ });
28
+ private now;
29
+ /** Records that `streamId` changed in `block` (a mined receipt's block). */
30
+ note(streamId: string, block: bigint | number | null | undefined): void;
31
+ /** The floor for `streamId`, or `undefined` when none is known. */
32
+ get(streamId: string): bigint | undefined;
33
+ private prune;
34
+ }
35
+ //# sourceMappingURL=block-floors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-floors.d.ts","sourceRoot":"","sources":["../../src/x402-opener/block-floors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,iBAAiB;IAO1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAN1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGnB;gBAGe,OAAO,GAAE;QACxB,kDAAkD;QAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QACxB,kEAAkE;QAClE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;KAC1B;IAGR,OAAO,CAAC,GAAG;IAIX,4EAA4E;IAC5E,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI;IAoBvE,mEAAmE;IACnE,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAWzC,OAAO,CAAC,KAAK;CAOd"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * The lowest block a read about a stream must be served from, per stream.
3
+ *
4
+ * A public RPC endpoint is usually a load balancer over several nodes that are
5
+ * not all at the same height: the node that returned a transaction's receipt
6
+ * can be a block or two ahead of the node that answers the next `eth_call` at
7
+ * `latest`. Right after the facilitator settles a payment (or the refund relay
8
+ * mines a close or reclaim), a read at `latest` can therefore still see the
9
+ * stream as it was BEFORE that transaction — not opened yet, still active,
10
+ * not reclaimed (live finding 2026-10-03: the relay answered `not-found` for a
11
+ * stream it had settled half a second earlier).
12
+ *
13
+ * Whoever observes a mined receipt for a stream records its block here; the
14
+ * refund relay then refuses to answer from any block below it (it waits,
15
+ * bounded, for the RPC to catch up and pins every read of one answer to one
16
+ * block). In-memory, per process, bounded; an entry only ever raises.
17
+ */
18
+ export class StreamBlockFloors {
19
+ options;
20
+ floors = new Map();
21
+ constructor(options = {}) {
22
+ this.options = options;
23
+ }
24
+ now() {
25
+ return (this.options.nowMs ?? Date.now)();
26
+ }
27
+ /** Records that `streamId` changed in `block` (a mined receipt's block). */
28
+ note(streamId, block) {
29
+ if (block === null || block === undefined)
30
+ return;
31
+ const value = BigInt(block);
32
+ if (value <= 0n)
33
+ return;
34
+ const key = streamId.toLowerCase();
35
+ const current = this.get(key);
36
+ if (current !== undefined && current >= value)
37
+ return;
38
+ const max = this.options.maxEntries ?? 10_000;
39
+ if (!this.floors.has(key) && this.floors.size >= max) {
40
+ this.prune();
41
+ while (this.floors.size >= max) {
42
+ const oldest = this.floors.keys().next().value;
43
+ if (oldest === undefined)
44
+ break;
45
+ this.floors.delete(oldest);
46
+ }
47
+ }
48
+ this.floors.delete(key);
49
+ this.floors.set(key, { block: value, at: this.now() });
50
+ }
51
+ /** The floor for `streamId`, or `undefined` when none is known. */
52
+ get(streamId) {
53
+ const key = streamId.toLowerCase();
54
+ const entry = this.floors.get(key);
55
+ if (entry === undefined)
56
+ return undefined;
57
+ if (this.now() - entry.at >= (this.options.ttlMs ?? 3_600_000)) {
58
+ this.floors.delete(key);
59
+ return undefined;
60
+ }
61
+ return entry.block;
62
+ }
63
+ prune() {
64
+ const ttl = this.options.ttlMs ?? 3_600_000;
65
+ const now = this.now();
66
+ for (const [key, entry] of this.floors) {
67
+ if (now - entry.at >= ttl)
68
+ this.floors.delete(key);
69
+ }
70
+ }
71
+ }
72
+ //# sourceMappingURL=block-floors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-floors.js","sourceRoot":"","sources":["../../src/x402-opener/block-floors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,iBAAiB;IAOT;IANF,MAAM,GAAG,IAAI,GAAG,EAG9B,CAAC;IAEJ,YACmB,UAMb,EAAE;QANW,YAAO,GAAP,OAAO,CAMlB;IACL,CAAC;IAEI,GAAG;QACT,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC5C,CAAC;IAED,4EAA4E;IAC5E,IAAI,CAAC,QAAgB,EAAE,KAAyC;QAC9D,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,KAAK,IAAI,EAAE;YAAE,OAAO;QACxB,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,IAAI,KAAK;YAAE,OAAO;QACtD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC;QAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;YACrD,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;gBAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;gBAC/C,IAAI,MAAM,KAAK,SAAS;oBAAE,MAAM;gBAChC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,mEAAmE;IACnE,GAAG,CAAC,QAAgB;QAClB,MAAM,GAAG,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QAC1C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACxB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAEO,KAAK;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC;QAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACvC,IAAI,GAAG,GAAG,KAAK,CAAC,EAAE,IAAI,GAAG;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"facilitator-server.d.ts","sourceRoot":"","sources":["../../src/x402-opener/facilitator-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"facilitator-server.d.ts","sourceRoot":"","sources":["../../src/x402-opener/facilitator-server.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { privateKeyToAccount } from "viem/accounts";
7
7
  import { DEFAULT_METRIK_PUBLIC_REGISTRY_URL } from "../discovery/registry.js";
8
8
  import { DEFAULT_LISTING_CACHE_SECONDS, RegistryListingResolver, } from "./listing-resolver.js";
9
9
  import { DEFAULT_REFUND_READ_CACHE_SECONDS, DEFAULT_REFUND_SUBMISSIONS_PER_MINUTE, DEFAULT_REFUND_SUBMISSIONS_PER_STREAM_PER_MINUTE, OpenerRefundRelay, } from "./refund-relay.js";
10
+ import { StreamBlockFloors } from "./block-floors.js";
10
11
  import { RelayerQueue } from "./relayer-queue.js";
11
12
  import { MetrikOpenerExactScheme, } from "./scheme.js";
12
13
  import { chainIdFromNetwork } from "./terms.js";
@@ -342,9 +343,14 @@ export async function buildOpenerFacilitator(options) {
342
343
  const walletClient = createWalletClient({ account, chain, transport });
343
344
  // ONE queue for every transaction this relayer key sends.
344
345
  const relayerQueue = new RelayerQueue();
346
+ // ONE set of per-stream block floors: the scheme records each settlement's
347
+ // block, and the refund relay never answers below it (a lagging RPC node
348
+ // would otherwise call a stream settled a second ago "not found").
349
+ const streamFloors = new StreamBlockFloors();
345
350
  const receiptTimeoutMs = options.receiptTimeoutMs;
346
351
  const scheme = new MetrikOpenerExactScheme({
347
352
  relayerQueue,
353
+ streamFloors,
348
354
  advertiseRefundRelay: options.refundRelay !== undefined,
349
355
  network: options.network,
350
356
  factoryAddress: options.factoryAddress,
@@ -385,6 +391,7 @@ export async function buildOpenerFacilitator(options) {
385
391
  publicClient,
386
392
  walletClient,
387
393
  relayerQueue,
394
+ streamFloors,
388
395
  ...(receiptTimeoutMs === undefined ? {} : { receiptTimeoutMs }),
389
396
  ...(relay.publicBaseUrl === undefined
390
397
  ? {}