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

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 (113) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/commands/claim.d.ts +32 -0
  3. package/dist/cli/commands/claim.d.ts.map +1 -1
  4. package/dist/cli/commands/claim.js +115 -27
  5. package/dist/cli/commands/claim.js.map +1 -1
  6. package/dist/cli/commands/pay.d.ts +15 -0
  7. package/dist/cli/commands/pay.d.ts.map +1 -1
  8. package/dist/cli/commands/pay.js +131 -7
  9. package/dist/cli/commands/pay.js.map +1 -1
  10. package/dist/cli/commands/reclaim.d.ts.map +1 -1
  11. package/dist/cli/commands/reclaim.js +20 -4
  12. package/dist/cli/commands/reclaim.js.map +1 -1
  13. package/dist/cli/commands/refund.d.ts +19 -1
  14. package/dist/cli/commands/refund.d.ts.map +1 -1
  15. package/dist/cli/commands/refund.js +200 -27
  16. package/dist/cli/commands/refund.js.map +1 -1
  17. package/dist/cli/commands/status.d.ts.map +1 -1
  18. package/dist/cli/commands/status.js +11 -1
  19. package/dist/cli/commands/status.js.map +1 -1
  20. package/dist/cli/commands/watch.d.ts.map +1 -1
  21. package/dist/cli/commands/watch.js +2 -0
  22. package/dist/cli/commands/watch.js.map +1 -1
  23. package/dist/cli/context.d.ts +19 -0
  24. package/dist/cli/context.d.ts.map +1 -1
  25. package/dist/cli/deps.d.ts +20 -0
  26. package/dist/cli/deps.d.ts.map +1 -1
  27. package/dist/cli/deps.js +14 -0
  28. package/dist/cli/deps.js.map +1 -1
  29. package/dist/cli/progress.d.ts +13 -1
  30. package/dist/cli/progress.d.ts.map +1 -1
  31. package/dist/cli/progress.js +7 -1
  32. package/dist/cli/progress.js.map +1 -1
  33. package/dist/cli/run.d.ts.map +1 -1
  34. package/dist/cli/run.js +26 -14
  35. package/dist/cli/run.js.map +1 -1
  36. package/dist/cli/status.d.ts +103 -0
  37. package/dist/cli/status.d.ts.map +1 -1
  38. package/dist/cli/status.js +310 -41
  39. package/dist/cli/status.js.map +1 -1
  40. package/dist/cli/wallet.d.ts +1 -1
  41. package/dist/cli/wallet.d.ts.map +1 -1
  42. package/dist/cli/wallet.js +28 -4
  43. package/dist/cli/wallet.js.map +1 -1
  44. package/dist/gateway/http-server.d.ts +17 -0
  45. package/dist/gateway/http-server.d.ts.map +1 -1
  46. package/dist/gateway/http-server.js +76 -9
  47. package/dist/gateway/http-server.js.map +1 -1
  48. package/dist/gateway/x402-opener-mode.d.ts +39 -2
  49. package/dist/gateway/x402-opener-mode.d.ts.map +1 -1
  50. package/dist/gateway/x402-opener-mode.js +169 -36
  51. package/dist/gateway/x402-opener-mode.js.map +1 -1
  52. package/dist/mcp/server.d.ts +12 -0
  53. package/dist/mcp/server.d.ts.map +1 -1
  54. package/dist/mcp/server.js +28 -9
  55. package/dist/mcp/server.js.map +1 -1
  56. package/dist/mcp/x402-tools.d.ts +8 -3
  57. package/dist/mcp/x402-tools.d.ts.map +1 -1
  58. package/dist/mcp/x402-tools.js +126 -6
  59. package/dist/mcp/x402-tools.js.map +1 -1
  60. package/dist/sdk/client.d.ts +13 -0
  61. package/dist/sdk/client.d.ts.map +1 -1
  62. package/dist/sdk/client.js +15 -0
  63. package/dist/sdk/client.js.map +1 -1
  64. package/dist/x402-buyer/pay.d.ts +22 -0
  65. package/dist/x402-buyer/pay.d.ts.map +1 -1
  66. package/dist/x402-buyer/pay.js +33 -3
  67. package/dist/x402-buyer/pay.js.map +1 -1
  68. package/dist/x402-opener/facilitator-entry.js +4 -1
  69. package/dist/x402-opener/facilitator-entry.js.map +1 -1
  70. package/dist/x402-opener/facilitator-server.d.ts +29 -0
  71. package/dist/x402-opener/facilitator-server.d.ts.map +1 -1
  72. package/dist/x402-opener/facilitator-server.js +67 -1
  73. package/dist/x402-opener/facilitator-server.js.map +1 -1
  74. package/dist/x402-opener/refund-relay.d.ts +30 -4
  75. package/dist/x402-opener/refund-relay.d.ts.map +1 -1
  76. package/dist/x402-opener/refund-relay.js +123 -22
  77. package/dist/x402-opener/refund-relay.js.map +1 -1
  78. package/dist/x402-opener/scheme.d.ts +79 -0
  79. package/dist/x402-opener/scheme.d.ts.map +1 -1
  80. package/dist/x402-opener/scheme.js +326 -40
  81. package/dist/x402-opener/scheme.js.map +1 -1
  82. package/dist/x402-opener/terms.d.ts +61 -1
  83. package/dist/x402-opener/terms.d.ts.map +1 -1
  84. package/dist/x402-opener/terms.js +94 -2
  85. package/dist/x402-opener/terms.js.map +1 -1
  86. package/docs/cli.md +87 -9
  87. package/docs/mcp-reference.md +18 -2
  88. package/docs/quickstart.md +3 -3
  89. package/docs/x402.md +150 -10
  90. package/package.json +3 -3
  91. package/src/cli/commands/claim.ts +167 -32
  92. package/src/cli/commands/pay.ts +150 -8
  93. package/src/cli/commands/reclaim.ts +25 -5
  94. package/src/cli/commands/refund.ts +231 -33
  95. package/src/cli/commands/status.ts +11 -1
  96. package/src/cli/commands/watch.ts +4 -0
  97. package/src/cli/context.ts +16 -0
  98. package/src/cli/deps.ts +37 -0
  99. package/src/cli/progress.ts +21 -2
  100. package/src/cli/run.ts +26 -13
  101. package/src/cli/status.ts +440 -43
  102. package/src/cli/wallet.ts +44 -7
  103. package/src/gateway/http-server.ts +96 -8
  104. package/src/gateway/x402-opener-mode.ts +234 -37
  105. package/src/mcp/server.ts +43 -11
  106. package/src/mcp/x402-tools.ts +171 -7
  107. package/src/sdk/client.ts +25 -0
  108. package/src/x402-buyer/pay.ts +41 -3
  109. package/src/x402-opener/facilitator-entry.ts +4 -1
  110. package/src/x402-opener/facilitator-server.ts +101 -1
  111. package/src/x402-opener/refund-relay.ts +150 -20
  112. package/src/x402-opener/scheme.ts +459 -41
  113. package/src/x402-opener/terms.ts +155 -2
@@ -1,3 +1,7 @@
1
+ import {
2
+ InvalidUpfrontTermsError,
3
+ validateUpfrontTerms,
4
+ } from "@absol-labs/shared";
1
5
  import { getAddress, isAddress, isHex, type Address, type Hex } from "viem";
2
6
 
3
7
  /**
@@ -51,6 +55,96 @@ export interface OpenerTerms {
51
55
  readonly maxDuration: bigint;
52
56
  }
53
57
 
58
+ /**
59
+ * Which opener contract a factory deploys: `"stream"` (`X402StreamOpener`,
60
+ * 4-field terms, the whole payment funds a stream) or `"upfront"`
61
+ * (`X402UpfrontStreamOpener`, 6-field terms: a fixed `price` whose
62
+ * non-refundable `upfrontAmount` is paid to the seller at settlement and whose
63
+ * remainder funds a stream). Decided by WHICH configured factory a quote names,
64
+ * never by the wire fields alone.
65
+ */
66
+ export type OpenerKind = "stream" | "upfront";
67
+
68
+ /** `termsVersion` of each opener kind's `extra.metrikStreamOpener` (as the SDK checks it). */
69
+ export const OPENER_TERMS_VERSION = {
70
+ stream: "stream-1",
71
+ upfront: "upfront-1",
72
+ } as const satisfies Record<OpenerKind, string>;
73
+
74
+ /**
75
+ * The 6-field terms of an `X402UpfrontStreamOpener` (metrik-contracts#54),
76
+ * mirroring the Solidity struct. Every field is committed by the `payTo`.
77
+ */
78
+ export interface UpfrontOpenerTerms extends OpenerTerms {
79
+ /** The exact x402 amount: the opener accepts this value and nothing else. */
80
+ readonly price: bigint;
81
+ /** NON-REFUNDABLE part paid to the seller (net of the protocol fee) at settlement. `<= price`. */
82
+ readonly upfrontAmount: bigint;
83
+ }
84
+
85
+ /** The refundable, metered part of an upfront opener's price (the stream deposit). */
86
+ export function upfrontRefundable(terms: UpfrontOpenerTerms): bigint {
87
+ return terms.price - terms.upfrontAmount;
88
+ }
89
+
90
+ /** True when an upfront opener opens no stream at all (`upfrontAmount == price`). */
91
+ export function isUpfrontOnly(terms: UpfrontOpenerTerms): boolean {
92
+ return terms.price > 0n && terms.upfrontAmount === terms.price;
93
+ }
94
+
95
+ /**
96
+ * The upfront terms a gateway may quote: exactly the factory's
97
+ * `validateTerms` (via `@absol-labs/shared`'s `validateUpfrontTerms`, so a
98
+ * `payTo` no transaction can deploy is never quoted), a fixed non-zero price,
99
+ * and a metered part (`price - upfrontAmount`) the stream can actually earn
100
+ * (`<= ratePerSecond * maxDuration`) — the SDK buyer refuses anything else.
101
+ */
102
+ export function assertValidUpfrontTerms(terms: UpfrontOpenerTerms): void {
103
+ assertValidTerms(terms);
104
+ try {
105
+ validateUpfrontTerms({
106
+ operator: getAddress(terms.operator),
107
+ serviceRef: terms.serviceRef.toLowerCase() as Hex,
108
+ ratePerSecond: terms.ratePerSecond,
109
+ maxDuration: terms.maxDuration,
110
+ price: terms.price,
111
+ upfrontAmount: terms.upfrontAmount,
112
+ });
113
+ } catch (error) {
114
+ throw new InvalidOpenerTermsError(
115
+ error instanceof InvalidUpfrontTermsError || error instanceof Error
116
+ ? error.message
117
+ : String(error),
118
+ );
119
+ }
120
+ if (terms.price <= 0n) {
121
+ throw new InvalidOpenerTermsError(
122
+ "an upfront opener needs a fixed price > 0",
123
+ );
124
+ }
125
+ if (upfrontRefundable(terms) > maxEarnable(terms)) {
126
+ throw new InvalidOpenerTermsError(
127
+ `the metered part ${upfrontRefundable(terms)} (price - upfrontAmount) exceeds ratePerSecond * maxDuration (${maxEarnable(terms)})`,
128
+ );
129
+ }
130
+ }
131
+
132
+ /** Solidity-tuple view of 6-field upfront terms for viem contract calls. */
133
+ export function upfrontTermsTuple(terms: UpfrontOpenerTerms): {
134
+ readonly operator: Address;
135
+ readonly serviceRef: Hex;
136
+ readonly ratePerSecond: bigint;
137
+ readonly maxDuration: bigint;
138
+ readonly price: bigint;
139
+ readonly upfrontAmount: bigint;
140
+ } {
141
+ return {
142
+ ...termsTuple(terms),
143
+ price: terms.price,
144
+ upfrontAmount: terms.upfrontAmount,
145
+ };
146
+ }
147
+
54
148
  /** JSON-safe projection of {@link OpenerTerms} plus the factory that prices them. */
55
149
  export interface OpenerTermsExtra {
56
150
  readonly factory: Address;
@@ -58,6 +152,12 @@ export interface OpenerTermsExtra {
58
152
  readonly serviceRef: Hex;
59
153
  readonly ratePerSecond: string;
60
154
  readonly maxDuration: string;
155
+ /** Upfront openers only: the exact price (base units). */
156
+ readonly price?: string;
157
+ /** Upfront openers only: the non-refundable per-call part (base units). */
158
+ readonly upfrontAmount?: string;
159
+ /** `stream-1` / `upfront-1`; optional, must match the factory's kind when present. */
160
+ readonly termsVersion?: string;
61
161
  /**
62
162
  * Informational only (metrik-agent#119): where the payer gets unearned money
63
163
  * back without ETH, as a template containing `{streamId}`. Never used for
@@ -158,14 +258,38 @@ export function termsToExtra(
158
258
  };
159
259
  }
160
260
 
261
+ /** The 402 `extra.metrikStreamOpener` terms of an upfront opener quote. */
262
+ export function upfrontTermsToExtra(
263
+ factory: Address,
264
+ terms: UpfrontOpenerTerms,
265
+ ): OpenerTermsExtra {
266
+ return {
267
+ factory: getAddress(factory),
268
+ termsVersion: OPENER_TERMS_VERSION.upfront,
269
+ operator: getAddress(terms.operator),
270
+ serviceRef: terms.serviceRef.toLowerCase() as Hex,
271
+ ratePerSecond: terms.ratePerSecond.toString(),
272
+ maxDuration: terms.maxDuration.toString(),
273
+ price: terms.price.toString(),
274
+ upfrontAmount: terms.upfrontAmount.toString(),
275
+ };
276
+ }
277
+
161
278
  /**
162
279
  * Reads opener terms from an untrusted `PaymentRequirements.extra`. Every field
163
280
  * is re-validated; unknown keys under the opener object are rejected so the
164
- * wire shape cannot drift silently.
281
+ * wire shape cannot drift silently. `price` / `upfrontAmount` are returned as
282
+ * `upfront` when present (both or neither); whether they are REQUIRED or
283
+ * FORBIDDEN depends on the factory's kind, which only the caller knows.
165
284
  */
166
285
  export function termsFromExtra(extra: unknown): {
167
286
  readonly factory: Address;
168
287
  readonly terms: OpenerTerms;
288
+ readonly upfront?: {
289
+ readonly price: bigint;
290
+ readonly upfrontAmount: bigint;
291
+ };
292
+ readonly termsVersion?: string;
169
293
  } {
170
294
  if (typeof extra !== "object" || extra === null) {
171
295
  throw new InvalidOpenerTermsError("requirements.extra is missing");
@@ -183,6 +307,9 @@ export function termsFromExtra(extra: unknown): {
183
307
  "serviceRef",
184
308
  "ratePerSecond",
185
309
  "maxDuration",
310
+ "price",
311
+ "upfrontAmount",
312
+ "termsVersion",
186
313
  "refundUrl",
187
314
  "docsUrl",
188
315
  ]);
@@ -217,7 +344,33 @@ export function termsFromExtra(extra: unknown): {
217
344
  maxDuration: parseUintString(record.maxDuration, "maxDuration"),
218
345
  };
219
346
  assertValidTerms(terms);
220
- return { factory: getAddress(factory), terms };
347
+ const termsVersion = record.termsVersion;
348
+ if (
349
+ termsVersion !== undefined &&
350
+ (typeof termsVersion !== "string" || termsVersion.length > 64)
351
+ ) {
352
+ throw new InvalidOpenerTermsError("termsVersion must be a short string");
353
+ }
354
+ if ((record.price === undefined) !== (record.upfrontAmount === undefined)) {
355
+ throw new InvalidOpenerTermsError(
356
+ "price and upfrontAmount must be given together (an upfront opener's terms) or not at all",
357
+ );
358
+ }
359
+ const upfront =
360
+ record.price === undefined
361
+ ? undefined
362
+ : {
363
+ price: parseUintString(record.price, "price"),
364
+ upfrontAmount: parseUintString(record.upfrontAmount, "upfrontAmount"),
365
+ };
366
+ return {
367
+ factory: getAddress(factory),
368
+ terms,
369
+ ...(upfront === undefined ? {} : { upfront }),
370
+ ...(termsVersion === undefined
371
+ ? {}
372
+ : { termsVersion: termsVersion as string }),
373
+ };
221
374
  }
222
375
 
223
376
  /** Chain id encoded in an `eip155:<id>` CAIP-2 identifier. Throws otherwise. */