@resvary/sdk 0.5.0-alpha.1

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 (171) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +17 -0
  3. package/dist/billing/index.d.ts +3 -0
  4. package/dist/billing/index.d.ts.map +1 -0
  5. package/dist/billing/index.js +3 -0
  6. package/dist/billing/index.js.map +1 -0
  7. package/dist/billing/meter.d.ts +97 -0
  8. package/dist/billing/meter.d.ts.map +1 -0
  9. package/dist/billing/meter.js +109 -0
  10. package/dist/billing/meter.js.map +1 -0
  11. package/dist/billing/plans.d.ts +77 -0
  12. package/dist/billing/plans.d.ts.map +1 -0
  13. package/dist/billing/plans.js +65 -0
  14. package/dist/billing/plans.js.map +1 -0
  15. package/dist/client/buyer.d.ts +82 -0
  16. package/dist/client/buyer.d.ts.map +1 -0
  17. package/dist/client/buyer.js +168 -0
  18. package/dist/client/buyer.js.map +1 -0
  19. package/dist/client/index.d.ts +2 -0
  20. package/dist/client/index.d.ts.map +1 -0
  21. package/dist/client/index.js +2 -0
  22. package/dist/client/index.js.map +1 -0
  23. package/dist/constants.d.ts +36 -0
  24. package/dist/constants.d.ts.map +1 -0
  25. package/dist/constants.js +42 -0
  26. package/dist/constants.js.map +1 -0
  27. package/dist/credits/amount.d.ts +7 -0
  28. package/dist/credits/amount.d.ts.map +1 -0
  29. package/dist/credits/amount.js +36 -0
  30. package/dist/credits/amount.js.map +1 -0
  31. package/dist/credits/errors.d.ts +20 -0
  32. package/dist/credits/errors.d.ts.map +1 -0
  33. package/dist/credits/errors.js +35 -0
  34. package/dist/credits/errors.js.map +1 -0
  35. package/dist/credits/index.d.ts +7 -0
  36. package/dist/credits/index.d.ts.map +1 -0
  37. package/dist/credits/index.js +6 -0
  38. package/dist/credits/index.js.map +1 -0
  39. package/dist/credits/ledger.d.ts +175 -0
  40. package/dist/credits/ledger.d.ts.map +1 -0
  41. package/dist/credits/ledger.js +705 -0
  42. package/dist/credits/ledger.js.map +1 -0
  43. package/dist/credits/store.d.ts +104 -0
  44. package/dist/credits/store.d.ts.map +1 -0
  45. package/dist/credits/store.js +420 -0
  46. package/dist/credits/store.js.map +1 -0
  47. package/dist/credits/types.d.ts +234 -0
  48. package/dist/credits/types.d.ts.map +1 -0
  49. package/dist/credits/types.js +2 -0
  50. package/dist/credits/types.js.map +1 -0
  51. package/dist/credits/webhooks.d.ts +5 -0
  52. package/dist/credits/webhooks.d.ts.map +1 -0
  53. package/dist/credits/webhooks.js +13 -0
  54. package/dist/credits/webhooks.js.map +1 -0
  55. package/dist/funding/arc-worker.d.ts +55 -0
  56. package/dist/funding/arc-worker.d.ts.map +1 -0
  57. package/dist/funding/arc-worker.js +133 -0
  58. package/dist/funding/arc-worker.js.map +1 -0
  59. package/dist/funding/arc.d.ts +38 -0
  60. package/dist/funding/arc.d.ts.map +1 -0
  61. package/dist/funding/arc.js +83 -0
  62. package/dist/funding/arc.js.map +1 -0
  63. package/dist/funding/index.d.ts +3 -0
  64. package/dist/funding/index.d.ts.map +1 -0
  65. package/dist/funding/index.js +3 -0
  66. package/dist/funding/index.js.map +1 -0
  67. package/dist/gateway/client.d.ts +51 -0
  68. package/dist/gateway/client.d.ts.map +1 -0
  69. package/dist/gateway/client.js +59 -0
  70. package/dist/gateway/client.js.map +1 -0
  71. package/dist/gateway/index.d.ts +2 -0
  72. package/dist/gateway/index.d.ts.map +1 -0
  73. package/dist/gateway/index.js +2 -0
  74. package/dist/gateway/index.js.map +1 -0
  75. package/dist/index.d.ts +21 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +20 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/middleware/express.d.ts +25 -0
  80. package/dist/middleware/express.d.ts.map +1 -0
  81. package/dist/middleware/express.js +61 -0
  82. package/dist/middleware/express.js.map +1 -0
  83. package/dist/middleware/index.d.ts +4 -0
  84. package/dist/middleware/index.d.ts.map +1 -0
  85. package/dist/middleware/index.js +4 -0
  86. package/dist/middleware/index.js.map +1 -0
  87. package/dist/middleware/next.d.ts +27 -0
  88. package/dist/middleware/next.d.ts.map +1 -0
  89. package/dist/middleware/next.js +67 -0
  90. package/dist/middleware/next.js.map +1 -0
  91. package/dist/middleware/paywall.d.ts +54 -0
  92. package/dist/middleware/paywall.d.ts.map +1 -0
  93. package/dist/middleware/paywall.js +102 -0
  94. package/dist/middleware/paywall.js.map +1 -0
  95. package/dist/pricing/index.d.ts +3 -0
  96. package/dist/pricing/index.d.ts.map +1 -0
  97. package/dist/pricing/index.js +2 -0
  98. package/dist/pricing/index.js.map +1 -0
  99. package/dist/pricing/rating.d.ts +21 -0
  100. package/dist/pricing/rating.d.ts.map +1 -0
  101. package/dist/pricing/rating.js +109 -0
  102. package/dist/pricing/rating.js.map +1 -0
  103. package/dist/receipts/amount.d.ts +8 -0
  104. package/dist/receipts/amount.d.ts.map +1 -0
  105. package/dist/receipts/amount.js +27 -0
  106. package/dist/receipts/amount.js.map +1 -0
  107. package/dist/receipts/index.d.ts +16 -0
  108. package/dist/receipts/index.d.ts.map +1 -0
  109. package/dist/receipts/index.js +15 -0
  110. package/dist/receipts/index.js.map +1 -0
  111. package/dist/receipts/invoice.d.ts +18 -0
  112. package/dist/receipts/invoice.d.ts.map +1 -0
  113. package/dist/receipts/invoice.js +112 -0
  114. package/dist/receipts/invoice.js.map +1 -0
  115. package/dist/receipts/ledger.d.ts +30 -0
  116. package/dist/receipts/ledger.d.ts.map +1 -0
  117. package/dist/receipts/ledger.js +109 -0
  118. package/dist/receipts/ledger.js.map +1 -0
  119. package/dist/receipts/memo-payment.d.ts +100 -0
  120. package/dist/receipts/memo-payment.d.ts.map +1 -0
  121. package/dist/receipts/memo-payment.js +91 -0
  122. package/dist/receipts/memo-payment.js.map +1 -0
  123. package/dist/receipts/memo.d.ts +14 -0
  124. package/dist/receipts/memo.d.ts.map +1 -0
  125. package/dist/receipts/memo.js +39 -0
  126. package/dist/receipts/memo.js.map +1 -0
  127. package/dist/receipts/persistent-ledger.d.ts +27 -0
  128. package/dist/receipts/persistent-ledger.d.ts.map +1 -0
  129. package/dist/receipts/persistent-ledger.js +111 -0
  130. package/dist/receipts/persistent-ledger.js.map +1 -0
  131. package/dist/receipts/persistent-webhook-inbox.d.ts +32 -0
  132. package/dist/receipts/persistent-webhook-inbox.d.ts.map +1 -0
  133. package/dist/receipts/persistent-webhook-inbox.js +93 -0
  134. package/dist/receipts/persistent-webhook-inbox.js.map +1 -0
  135. package/dist/receipts/proof.d.ts +80 -0
  136. package/dist/receipts/proof.d.ts.map +1 -0
  137. package/dist/receipts/proof.js +223 -0
  138. package/dist/receipts/proof.js.map +1 -0
  139. package/dist/receipts/serialization.d.ts +3 -0
  140. package/dist/receipts/serialization.d.ts.map +1 -0
  141. package/dist/receipts/serialization.js +24 -0
  142. package/dist/receipts/serialization.js.map +1 -0
  143. package/dist/receipts/store.d.ts +69 -0
  144. package/dist/receipts/store.d.ts.map +1 -0
  145. package/dist/receipts/store.js +85 -0
  146. package/dist/receipts/store.js.map +1 -0
  147. package/dist/receipts/types.d.ts +134 -0
  148. package/dist/receipts/types.d.ts.map +1 -0
  149. package/dist/receipts/types.js +5 -0
  150. package/dist/receipts/types.js.map +1 -0
  151. package/dist/receipts/watcher.d.ts +92 -0
  152. package/dist/receipts/watcher.d.ts.map +1 -0
  153. package/dist/receipts/watcher.js +323 -0
  154. package/dist/receipts/watcher.js.map +1 -0
  155. package/dist/receipts/webhook-inbox.d.ts +34 -0
  156. package/dist/receipts/webhook-inbox.d.ts.map +1 -0
  157. package/dist/receipts/webhook-inbox.js +101 -0
  158. package/dist/receipts/webhook-inbox.js.map +1 -0
  159. package/dist/receipts/webhook-route.d.ts +22 -0
  160. package/dist/receipts/webhook-route.d.ts.map +1 -0
  161. package/dist/receipts/webhook-route.js +37 -0
  162. package/dist/receipts/webhook-route.js.map +1 -0
  163. package/dist/receipts/webhooks.d.ts +20 -0
  164. package/dist/receipts/webhooks.d.ts.map +1 -0
  165. package/dist/receipts/webhooks.js +72 -0
  166. package/dist/receipts/webhooks.js.map +1 -0
  167. package/dist/types.d.ts +101 -0
  168. package/dist/types.d.ts.map +1 -0
  169. package/dist/types.js +5 -0
  170. package/dist/types.js.map +1 -0
  171. package/package.json +116 -0
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2025-2026 horn111
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ https://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # @resvary/sdk
2
+
3
+ Open-source prepaid credits and usage billing for AI products.
4
+
5
+ Primary imports:
6
+
7
+ ```typescript
8
+ import { CreditLedger } from '@resvary/sdk/credits';
9
+ import { createMeterDefinition, createPriceVersion, rateUsage } from '@resvary/sdk/pricing';
10
+ import { ArcCreditFunding } from '@resvary/sdk/funding/arc';
11
+ ```
12
+
13
+ The SDK provides USD credit accounts, manual grants, reserve/commit/release, immutable usage receipts, idempotency, a transactional outbox, and signed credit webhooks. It has no database or AI provider dependency.
14
+
15
+ Legacy stablecoin payment imports under `/receipts`, `/middleware`, `/client`, and `/gateway` remain compatible. `UsageMeter` and `createBillingPlan` are deprecated for new balance systems.
16
+
17
+ See the repository README and `docs/` for the complete quickstart and security model.
@@ -0,0 +1,3 @@
1
+ export { UsageMeter, type UsageRecord, type MeterConfig, type UsageSummary } from './meter.js';
2
+ export { createBillingPlan, type BillingPlan, type PricingModel, type PerRequestPricing, type PerSecondPricing, type PerJobPricing, type UsageInput, } from './plans.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/billing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { UsageMeter } from './meter.js';
2
+ export { createBillingPlan, } from './plans.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/billing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAyD,MAAM,YAAY,CAAC;AAC/F,OAAO,EACL,iBAAiB,GAOlB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Usage metering for tracking API consumption and billing.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { UsageMeter } from '@resvary/sdk/billing';
7
+ *
8
+ * const meter = new UsageMeter({ endpoint: '/api/data' });
9
+ *
10
+ * // Record usage
11
+ * meter.record({ buyer: '0x...', amount: '0.001' });
12
+ *
13
+ * // Get usage summary
14
+ * const summary = meter.getSummary('0x...');
15
+ * console.log(summary.totalSpent); // '0.003'
16
+ * ```
17
+ */
18
+ /** Configuration for the usage meter */
19
+ export interface MeterConfig {
20
+ /** Endpoint being metered */
21
+ endpoint: string;
22
+ /** Maximum records to keep in memory (default: 10000) */
23
+ maxRecords?: number;
24
+ }
25
+ /** A single usage record */
26
+ export interface UsageRecord {
27
+ /** Buyer's wallet address */
28
+ buyer: `0x${string}`;
29
+ /** Amount paid in USDC */
30
+ amount: string;
31
+ /** Endpoint accessed */
32
+ endpoint: string;
33
+ /** Timestamp of the request */
34
+ timestamp: number;
35
+ /** Settlement status */
36
+ status: 'pending' | 'batched' | 'settled';
37
+ /** Optional metadata */
38
+ metadata?: Record<string, unknown>;
39
+ }
40
+ /** Usage summary for a buyer */
41
+ export interface UsageSummary {
42
+ /** Buyer's address */
43
+ buyer: `0x${string}`;
44
+ /** Total amount spent in USDC */
45
+ totalSpent: string;
46
+ /** Total number of requests */
47
+ totalRequests: number;
48
+ /** First usage timestamp */
49
+ firstSeen: number;
50
+ /** Last usage timestamp */
51
+ lastSeen: number;
52
+ /** Average cost per request */
53
+ avgCostPerRequest: string;
54
+ }
55
+ /**
56
+ * In-memory usage meter for tracking API consumption.
57
+ *
58
+ * For production use, extend with a persistent store
59
+ * (Supabase, Postgres, Redis, etc.)
60
+ */
61
+ /** @deprecated Use CreditLedger with meters, price versions, and usage receipts instead. */
62
+ export declare class UsageMeter {
63
+ private readonly records;
64
+ private readonly endpoint;
65
+ private readonly maxRecords;
66
+ constructor(config: MeterConfig);
67
+ /**
68
+ * Record a usage event.
69
+ */
70
+ record(params: {
71
+ buyer: `0x${string}`;
72
+ amount: string;
73
+ metadata?: Record<string, unknown>;
74
+ }): UsageRecord;
75
+ /**
76
+ * Get usage summary for a specific buyer.
77
+ */
78
+ getSummary(buyer: `0x${string}`): UsageSummary;
79
+ /**
80
+ * Get all usage records, optionally filtered.
81
+ */
82
+ getRecords(filter?: {
83
+ buyer?: `0x${string}`;
84
+ since?: number;
85
+ status?: UsageRecord['status'];
86
+ }): UsageRecord[];
87
+ /**
88
+ * Get aggregate stats across all buyers.
89
+ */
90
+ getAggregateStats(): {
91
+ totalRevenue: string;
92
+ totalRequests: number;
93
+ uniqueBuyers: number;
94
+ avgRevenuePerRequest: string;
95
+ };
96
+ }
97
+ //# sourceMappingURL=meter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meter.d.ts","sourceRoot":"","sources":["../../src/billing/meter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,wCAAwC;AACxC,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,4BAA4B;AAC5B,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC1C,wBAAwB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,gCAAgC;AAChC,MAAM,WAAW,YAAY;IAC3B,sBAAsB;IACtB,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;IACrB,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,+BAA+B;IAC/B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,4FAA4F;AAC5F,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAExB,MAAM,EAAE,WAAW;IAK/B;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,WAAW;IAoBzG;;OAEG;IACH,UAAU,CAAC,KAAK,EAAE,KAAK,MAAM,EAAE,GAAG,YAAY;IA+B9C;;OAEG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE;QAClB,KAAK,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;KAChC,GAAG,WAAW,EAAE;IAoBjB;;OAEG;IACH,iBAAiB,IAAI;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,oBAAoB,EAAE,MAAM,CAAC;KAC9B;CAiBF"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Usage metering for tracking API consumption and billing.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { UsageMeter } from '@resvary/sdk/billing';
7
+ *
8
+ * const meter = new UsageMeter({ endpoint: '/api/data' });
9
+ *
10
+ * // Record usage
11
+ * meter.record({ buyer: '0x...', amount: '0.001' });
12
+ *
13
+ * // Get usage summary
14
+ * const summary = meter.getSummary('0x...');
15
+ * console.log(summary.totalSpent); // '0.003'
16
+ * ```
17
+ */
18
+ /**
19
+ * In-memory usage meter for tracking API consumption.
20
+ *
21
+ * For production use, extend with a persistent store
22
+ * (Supabase, Postgres, Redis, etc.)
23
+ */
24
+ /** @deprecated Use CreditLedger with meters, price versions, and usage receipts instead. */
25
+ export class UsageMeter {
26
+ records = [];
27
+ endpoint;
28
+ maxRecords;
29
+ constructor(config) {
30
+ this.endpoint = config.endpoint;
31
+ this.maxRecords = config.maxRecords ?? 10_000;
32
+ }
33
+ /**
34
+ * Record a usage event.
35
+ */
36
+ record(params) {
37
+ const record = {
38
+ buyer: params.buyer,
39
+ amount: params.amount,
40
+ endpoint: this.endpoint,
41
+ timestamp: Date.now(),
42
+ status: 'pending',
43
+ metadata: params.metadata,
44
+ };
45
+ this.records.push(record);
46
+ // Evict oldest records if over limit
47
+ if (this.records.length > this.maxRecords) {
48
+ this.records.splice(0, this.records.length - this.maxRecords);
49
+ }
50
+ return record;
51
+ }
52
+ /**
53
+ * Get usage summary for a specific buyer.
54
+ */
55
+ getSummary(buyer) {
56
+ const buyerRecords = this.records.filter((r) => r.buyer.toLowerCase() === buyer.toLowerCase());
57
+ if (buyerRecords.length === 0) {
58
+ return {
59
+ buyer,
60
+ totalSpent: '0',
61
+ totalRequests: 0,
62
+ firstSeen: 0,
63
+ lastSeen: 0,
64
+ avgCostPerRequest: '0',
65
+ };
66
+ }
67
+ const totalSpent = buyerRecords.reduce((sum, r) => sum + parseFloat(r.amount), 0);
68
+ return {
69
+ buyer,
70
+ totalSpent: totalSpent.toFixed(6),
71
+ totalRequests: buyerRecords.length,
72
+ firstSeen: buyerRecords[0].timestamp,
73
+ lastSeen: buyerRecords[buyerRecords.length - 1].timestamp,
74
+ avgCostPerRequest: (totalSpent / buyerRecords.length).toFixed(6),
75
+ };
76
+ }
77
+ /**
78
+ * Get all usage records, optionally filtered.
79
+ */
80
+ getRecords(filter) {
81
+ let filtered = [...this.records];
82
+ if (filter?.buyer) {
83
+ filtered = filtered.filter((r) => r.buyer.toLowerCase() === filter.buyer.toLowerCase());
84
+ }
85
+ if (filter?.since) {
86
+ filtered = filtered.filter((r) => r.timestamp >= filter.since);
87
+ }
88
+ if (filter?.status) {
89
+ filtered = filtered.filter((r) => r.status === filter.status);
90
+ }
91
+ return filtered;
92
+ }
93
+ /**
94
+ * Get aggregate stats across all buyers.
95
+ */
96
+ getAggregateStats() {
97
+ const totalRevenue = this.records.reduce((sum, r) => sum + parseFloat(r.amount), 0);
98
+ const uniqueBuyers = new Set(this.records.map((r) => r.buyer.toLowerCase())).size;
99
+ return {
100
+ totalRevenue: totalRevenue.toFixed(6),
101
+ totalRequests: this.records.length,
102
+ uniqueBuyers,
103
+ avgRevenuePerRequest: this.records.length > 0
104
+ ? (totalRevenue / this.records.length).toFixed(6)
105
+ : '0',
106
+ };
107
+ }
108
+ }
109
+ //# sourceMappingURL=meter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meter.js","sourceRoot":"","sources":["../../src/billing/meter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AA0CH;;;;;GAKG;AACH,4FAA4F;AAC5F,MAAM,OAAO,UAAU;IACJ,OAAO,GAAkB,EAAE,CAAC;IAC5B,QAAQ,CAAS;IACjB,UAAU,CAAS;IAEpC,YAAY,MAAmB;QAC7B,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QAChC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,MAAoF;QACzF,MAAM,MAAM,GAAgB;YAC1B,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1B,qCAAqC;QACrC,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAC1C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,KAAoB;QAC7B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,CACrD,CAAC;QAEF,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO;gBACL,KAAK;gBACL,UAAU,EAAE,GAAG;gBACf,aAAa,EAAE,CAAC;gBAChB,SAAS,EAAE,CAAC;gBACZ,QAAQ,EAAE,CAAC;gBACX,iBAAiB,EAAE,GAAG;aACvB,CAAC;QACJ,CAAC;QAED,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,CACpC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EACtC,CAAC,CACF,CAAC;QAEF,OAAO;YACL,KAAK;YACL,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;YACjC,aAAa,EAAE,YAAY,CAAC,MAAM;YAClC,SAAS,EAAE,YAAY,CAAC,CAAC,CAAE,CAAC,SAAS;YACrC,QAAQ,EAAE,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,SAAS;YAC1D,iBAAiB,EAAE,CAAC,UAAU,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;SACjE,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,MAIV;QACC,IAAI,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAEjC,IAAI,MAAM,EAAE,KAAK,EAAE,CAAC;YAClB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CACxB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,KAAM,CAAC,WAAW,EAAE,CAC7D,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,EAAE,KAAK,EAAE,CAAC;YAClB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,MAAM,CAAC,KAAM,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,MAAM,EAAE,MAAM,EAAE,CAAC;YACnB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,CAAC;QAChE,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,iBAAiB;QAMf,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CACtC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,EACtC,CAAC,CACF,CAAC;QACF,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAElF,OAAO;YACL,YAAY,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;YACrC,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YAClC,YAAY;YACZ,oBAAoB,EAClB,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;gBACrB,CAAC,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;gBACjD,CAAC,CAAC,GAAG;SACV,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Billing plan definitions for different pricing models.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { createBillingPlan } from '@resvary/sdk/billing';
7
+ *
8
+ * const apiPlan = createBillingPlan({
9
+ * name: 'API Standard',
10
+ * pricing: { model: 'per-request', pricePerRequest: '0.001' },
11
+ * });
12
+ *
13
+ * const cost = apiPlan.calculateCost({ requests: 100 });
14
+ * console.log(cost); // '0.1'
15
+ * ```
16
+ */
17
+ /** Per-request pricing: fixed cost per API call */
18
+ export interface PerRequestPricing {
19
+ model: 'per-request';
20
+ /** Price in USDC per request */
21
+ pricePerRequest: string;
22
+ }
23
+ /** Per-second pricing: time-based billing */
24
+ export interface PerSecondPricing {
25
+ model: 'per-second';
26
+ /** Price in USDC per second */
27
+ pricePerSecond: string;
28
+ /** Minimum billable seconds (default: 1) */
29
+ minimumSeconds?: number;
30
+ }
31
+ /** Per-job pricing: batch operation billing */
32
+ export interface PerJobPricing {
33
+ model: 'per-job';
34
+ /** Base price in USDC per job */
35
+ basePrice: string;
36
+ /** Additional price per unit of work (e.g., per MB, per token) */
37
+ pricePerUnit?: string;
38
+ /** Name of the unit (e.g., 'MB', 'token', 'row') */
39
+ unitName?: string;
40
+ }
41
+ /** Union of all pricing model types */
42
+ export type PricingModel = PerRequestPricing | PerSecondPricing | PerJobPricing;
43
+ /** Billing plan configuration */
44
+ export interface BillingPlan {
45
+ /** Plan name */
46
+ name: string;
47
+ /** Plan description */
48
+ description?: string;
49
+ /** Pricing model */
50
+ pricing: PricingModel;
51
+ /** Calculate cost based on usage */
52
+ calculateCost: (usage: UsageInput) => string;
53
+ /** Get the minimum payment amount for this plan */
54
+ getMinimumPayment: () => string;
55
+ }
56
+ /** Input for cost calculation */
57
+ export interface UsageInput {
58
+ /** Number of requests (for per-request model) */
59
+ requests?: number;
60
+ /** Duration in seconds (for per-second model) */
61
+ seconds?: number;
62
+ /** Number of units processed (for per-job model) */
63
+ units?: number;
64
+ }
65
+ /**
66
+ * Create a billing plan with a specific pricing model.
67
+ *
68
+ * @param config - Plan configuration
69
+ * @returns A billing plan with cost calculation methods
70
+ */
71
+ /** @deprecated Use createMeterDefinition, createPriceVersion, and rateUsage instead. */
72
+ export declare function createBillingPlan(config: {
73
+ name: string;
74
+ description?: string;
75
+ pricing: PricingModel;
76
+ }): BillingPlan;
77
+ //# sourceMappingURL=plans.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans.d.ts","sourceRoot":"","sources":["../../src/billing/plans.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,aAAa,CAAC;IACrB,gCAAgC;IAChC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,YAAY,CAAC;IACpB,+BAA+B;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,+CAA+C;AAC/C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAC;IACjB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,uCAAuC;AACvC,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,gBAAgB,GAAG,aAAa,CAAC;AAEhF,iCAAiC;AACjC,MAAM,WAAW,WAAW;IAC1B,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB;IACpB,OAAO,EAAE,YAAY,CAAC;IACtB,oCAAoC;IACpC,aAAa,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC;IAC7C,mDAAmD;IACnD,iBAAiB,EAAE,MAAM,MAAM,CAAC;CACjC;AAED,iCAAiC;AACjC,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,YAAY,CAAC;CACvB,GAAG,WAAW,CAmDd"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Billing plan definitions for different pricing models.
3
+ *
4
+ * @example
5
+ * ```typescript
6
+ * import { createBillingPlan } from '@resvary/sdk/billing';
7
+ *
8
+ * const apiPlan = createBillingPlan({
9
+ * name: 'API Standard',
10
+ * pricing: { model: 'per-request', pricePerRequest: '0.001' },
11
+ * });
12
+ *
13
+ * const cost = apiPlan.calculateCost({ requests: 100 });
14
+ * console.log(cost); // '0.1'
15
+ * ```
16
+ */
17
+ /**
18
+ * Create a billing plan with a specific pricing model.
19
+ *
20
+ * @param config - Plan configuration
21
+ * @returns A billing plan with cost calculation methods
22
+ */
23
+ /** @deprecated Use createMeterDefinition, createPriceVersion, and rateUsage instead. */
24
+ export function createBillingPlan(config) {
25
+ const { name, description, pricing } = config;
26
+ return {
27
+ name,
28
+ description,
29
+ pricing,
30
+ calculateCost(usage) {
31
+ switch (pricing.model) {
32
+ case 'per-request': {
33
+ const requests = usage.requests ?? 1;
34
+ return (requests * parseFloat(pricing.pricePerRequest)).toFixed(6);
35
+ }
36
+ case 'per-second': {
37
+ const seconds = Math.max(usage.seconds ?? 1, pricing.minimumSeconds ?? 1);
38
+ return (seconds * parseFloat(pricing.pricePerSecond)).toFixed(6);
39
+ }
40
+ case 'per-job': {
41
+ const base = parseFloat(pricing.basePrice);
42
+ const unitCost = pricing.pricePerUnit
43
+ ? (usage.units ?? 0) * parseFloat(pricing.pricePerUnit)
44
+ : 0;
45
+ return (base + unitCost).toFixed(6);
46
+ }
47
+ default:
48
+ throw new Error(`Unknown pricing model: ${pricing.model}`);
49
+ }
50
+ },
51
+ getMinimumPayment() {
52
+ switch (pricing.model) {
53
+ case 'per-request':
54
+ return pricing.pricePerRequest;
55
+ case 'per-second':
56
+ return (parseFloat(pricing.pricePerSecond) * (pricing.minimumSeconds ?? 1)).toFixed(6);
57
+ case 'per-job':
58
+ return pricing.basePrice;
59
+ default:
60
+ return '0.000001';
61
+ }
62
+ },
63
+ };
64
+ }
65
+ //# sourceMappingURL=plans.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plans.js","sourceRoot":"","sources":["../../src/billing/plans.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAwDH;;;;;GAKG;AACH,wFAAwF;AACxF,MAAM,UAAU,iBAAiB,CAAC,MAIjC;IACC,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAE9C,OAAO;QACL,IAAI;QACJ,WAAW;QACX,OAAO;QAEP,aAAa,CAAC,KAAiB;YAC7B,QAAQ,OAAO,CAAC,KAAK,EAAE,CAAC;gBACtB,KAAK,aAAa,CAAC,CAAC,CAAC;oBACnB,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,CAAC,CAAC;oBACrC,OAAO,CAAC,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACrE,CAAC;gBAED,KAAK,YAAY,CAAC,CAAC,CAAC;oBAClB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CACtB,KAAK,CAAC,OAAO,IAAI,CAAC,EAClB,OAAO,CAAC,cAAc,IAAI,CAAC,CAC5B,CAAC;oBACF,OAAO,CAAC,OAAO,GAAG,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACnE,CAAC;gBAED,KAAK,SAAS,CAAC,CAAC,CAAC;oBACf,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;oBAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY;wBACnC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC;wBACvD,CAAC,CAAC,CAAC,CAAC;oBACN,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACtC,CAAC;gBAED;oBACE,MAAM,IAAI,KAAK,CAAC,0BAA2B,OAAwB,CAAC,KAAK,EAAE,CAAC,CAAC;YACjF,CAAC;QACH,CAAC;QAED,iBAAiB;YACf,QAAQ,OAAO,CAAC,KAAK,EAAE,CAAC;gBACtB,KAAK,aAAa;oBAChB,OAAO,OAAO,CAAC,eAAe,CAAC;gBACjC,KAAK,YAAY;oBACf,OAAO,CACL,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,CAAC,CAAC,CACnE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACf,KAAK,SAAS;oBACZ,OAAO,OAAO,CAAC,SAAS,CAAC;gBAC3B;oBACE,OAAO,UAAU,CAAC;YACtB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Buyer SDK for automated x402 payment flow.
3
+ *
4
+ * Handles the complete payment lifecycle:
5
+ * 1. Send request to a paywalled endpoint
6
+ * 2. Receive 402 + payment requirements
7
+ * 3. Sign EIP-3009 transferWithAuthorization
8
+ * 4. Retry request with X-PAYMENT header
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { BuyerClient } from '@resvary/sdk/client';
13
+ *
14
+ * const buyer = new BuyerClient({
15
+ * privateKey: '0x...',
16
+ * rpcUrl: 'https://rpc.testnet.arc.network',
17
+ * });
18
+ *
19
+ * const response = await buyer.request('https://api.example.com/premium/data');
20
+ * console.log(response.data);
21
+ * ```
22
+ */
23
+ /** Configuration for the BuyerClient */
24
+ export interface BuyerClientConfig {
25
+ /** Buyer's private key (hex string with 0x prefix) */
26
+ privateKey: `0x${string}`;
27
+ /** RPC URL for the target network (default: Arc Testnet) */
28
+ rpcUrl?: string;
29
+ /** Chain ID (default: Arc Testnet) */
30
+ chainId?: number;
31
+ /** Maximum number of payment retries */
32
+ maxRetries?: number;
33
+ /** Custom fetch implementation */
34
+ fetch?: typeof globalThis.fetch;
35
+ }
36
+ /** Response from a paid request */
37
+ export interface PaidResponse<T = unknown> {
38
+ /** Response data */
39
+ data: T;
40
+ /** HTTP status code */
41
+ status: number;
42
+ /** Response headers */
43
+ headers: Record<string, string>;
44
+ /** Payment details (if payment was made) */
45
+ payment?: {
46
+ amount: string;
47
+ to: `0x${string}`;
48
+ network: string;
49
+ };
50
+ }
51
+ /**
52
+ * Client for consuming x402-paywalled APIs.
53
+ *
54
+ * Automatically handles the 402 payment flow: detects paywalled endpoints,
55
+ * signs payment authorizations, and retries requests with valid payments.
56
+ */
57
+ export declare class BuyerClient {
58
+ private readonly account;
59
+ private readonly chainId;
60
+ private readonly fetchFn;
61
+ constructor(config: BuyerClientConfig);
62
+ /** Get the buyer's wallet address */
63
+ get address(): `0x${string}`;
64
+ /**
65
+ * Make a request to a potentially paywalled endpoint.
66
+ * Automatically handles 402 → sign → retry flow.
67
+ *
68
+ * @param url - The endpoint URL
69
+ * @param init - Optional fetch init options
70
+ * @returns Response with data and payment info
71
+ */
72
+ request<T = unknown>(url: string, init?: RequestInit): Promise<PaidResponse<T>>;
73
+ /**
74
+ * Parse payment requirements from a 402 response.
75
+ */
76
+ private parsePaymentRequirements;
77
+ /**
78
+ * Sign a payment authorization using EIP-3009.
79
+ */
80
+ private signPayment;
81
+ }
82
+ //# sourceMappingURL=buyer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buyer.d.ts","sourceRoot":"","sources":["../../src/client/buyer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH,wCAAwC;AACxC,MAAM,WAAW,iBAAiB;IAChC,sDAAsD;IACtD,UAAU,EAAE,KAAK,MAAM,EAAE,CAAC;IAC1B,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED,mCAAmC;AACnC,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,oBAAoB;IACpB,IAAI,EAAE,CAAC,CAAC;IACR,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,4CAA4C;IAC5C,OAAO,CAAC,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;;;;GAKG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;gBAEtC,MAAM,EAAE,iBAAiB;IAMrC,qCAAqC;IACrC,IAAI,OAAO,IAAI,KAAK,MAAM,EAAE,CAE3B;IAED;;;;;;;OAOG;IACG,OAAO,CAAC,CAAC,GAAG,OAAO,EACvB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,WAAW,GACjB,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAkD3B;;OAEG;YACW,wBAAwB;IAmBtC;;OAEG;YACW,WAAW;CA2D1B"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * Buyer SDK for automated x402 payment flow.
3
+ *
4
+ * Handles the complete payment lifecycle:
5
+ * 1. Send request to a paywalled endpoint
6
+ * 2. Receive 402 + payment requirements
7
+ * 3. Sign EIP-3009 transferWithAuthorization
8
+ * 4. Retry request with X-PAYMENT header
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { BuyerClient } from '@resvary/sdk/client';
13
+ *
14
+ * const buyer = new BuyerClient({
15
+ * privateKey: '0x...',
16
+ * rpcUrl: 'https://rpc.testnet.arc.network',
17
+ * });
18
+ *
19
+ * const response = await buyer.request('https://api.example.com/premium/data');
20
+ * console.log(response.data);
21
+ * ```
22
+ */
23
+ import { privateKeyToAccount } from 'viem/accounts';
24
+ import { ARC_TESTNET, DEFAULTS, HTTP_402, USDC_DECIMALS, X402_HEADER, PAYMENT_REQUIRED_HEADER } from '../constants.js';
25
+ /**
26
+ * Client for consuming x402-paywalled APIs.
27
+ *
28
+ * Automatically handles the 402 payment flow: detects paywalled endpoints,
29
+ * signs payment authorizations, and retries requests with valid payments.
30
+ */
31
+ export class BuyerClient {
32
+ account;
33
+ chainId;
34
+ fetchFn;
35
+ constructor(config) {
36
+ this.account = privateKeyToAccount(config.privateKey);
37
+ this.chainId = config.chainId ?? ARC_TESTNET.chainId;
38
+ this.fetchFn = config.fetch ?? globalThis.fetch;
39
+ }
40
+ /** Get the buyer's wallet address */
41
+ get address() {
42
+ return this.account.address;
43
+ }
44
+ /**
45
+ * Make a request to a potentially paywalled endpoint.
46
+ * Automatically handles 402 → sign → retry flow.
47
+ *
48
+ * @param url - The endpoint URL
49
+ * @param init - Optional fetch init options
50
+ * @returns Response with data and payment info
51
+ */
52
+ async request(url, init) {
53
+ // Initial request
54
+ const initialResponse = await this.fetchFn(url, init);
55
+ // If not 402, return directly
56
+ if (initialResponse.status !== HTTP_402) {
57
+ const data = await initialResponse.json();
58
+ return {
59
+ data,
60
+ status: initialResponse.status,
61
+ headers: Object.fromEntries(initialResponse.headers.entries()),
62
+ };
63
+ }
64
+ // Parse payment requirements from 402 response
65
+ const requirements = await this.parsePaymentRequirements(initialResponse);
66
+ if (!requirements) {
67
+ throw new Error('Received 402 but could not parse payment requirements');
68
+ }
69
+ // Sign the payment
70
+ const paymentPayload = await this.signPayment(requirements);
71
+ // Encode payment as base64
72
+ const encodedPayment = Buffer.from(JSON.stringify(paymentPayload)).toString('base64');
73
+ // Retry with payment header
74
+ const paidResponse = await this.fetchFn(url, {
75
+ ...init,
76
+ headers: {
77
+ ...init?.headers,
78
+ [X402_HEADER]: encodedPayment,
79
+ },
80
+ });
81
+ const data = await paidResponse.json();
82
+ return {
83
+ data,
84
+ status: paidResponse.status,
85
+ headers: Object.fromEntries(paidResponse.headers.entries()),
86
+ payment: {
87
+ amount: requirements.maxAmountRequired,
88
+ to: requirements.payTo,
89
+ network: requirements.network,
90
+ },
91
+ };
92
+ }
93
+ /**
94
+ * Parse payment requirements from a 402 response.
95
+ */
96
+ async parsePaymentRequirements(response) {
97
+ try {
98
+ // Try to get requirements from header
99
+ const headerValue = response.headers.get(PAYMENT_REQUIRED_HEADER);
100
+ if (headerValue) {
101
+ const decoded = Buffer.from(headerValue, 'base64').toString('utf-8');
102
+ return JSON.parse(decoded);
103
+ }
104
+ // Fallback: try to get from response body
105
+ const body = await response.json();
106
+ return body.requirements ?? null;
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ /**
113
+ * Sign a payment authorization using EIP-3009.
114
+ */
115
+ async signPayment(requirements) {
116
+ const now = Math.floor(Date.now() / 1000);
117
+ const nonce = `0x${Buffer.from(crypto.getRandomValues(new Uint8Array(32))).toString('hex')}`;
118
+ const authorization = {
119
+ from: this.account.address,
120
+ to: requirements.payTo,
121
+ value: String(BigInt(Math.ceil(parseFloat(requirements.maxAmountRequired) * 10 ** USDC_DECIMALS))),
122
+ validAfter: String(now - 60), // Valid from 1 minute ago (clock skew buffer)
123
+ validBefore: String(now + DEFAULTS.paymentValiditySeconds),
124
+ nonce,
125
+ };
126
+ // Sign the authorization using EIP-712 typed data
127
+ if (!this.account.signTypedData) {
128
+ throw new Error('Account does not support signTypedData');
129
+ }
130
+ const signature = await this.account.signTypedData({
131
+ domain: {
132
+ name: 'USD Coin',
133
+ version: '2',
134
+ chainId: BigInt(this.chainId),
135
+ verifyingContract: ARC_TESTNET.usdcAddress,
136
+ },
137
+ types: {
138
+ TransferWithAuthorization: [
139
+ { name: 'from', type: 'address' },
140
+ { name: 'to', type: 'address' },
141
+ { name: 'value', type: 'uint256' },
142
+ { name: 'validAfter', type: 'uint256' },
143
+ { name: 'validBefore', type: 'uint256' },
144
+ { name: 'nonce', type: 'bytes32' },
145
+ ],
146
+ },
147
+ primaryType: 'TransferWithAuthorization',
148
+ message: {
149
+ from: authorization.from,
150
+ to: authorization.to,
151
+ value: BigInt(authorization.value),
152
+ validAfter: BigInt(authorization.validAfter),
153
+ validBefore: BigInt(authorization.validBefore),
154
+ nonce: authorization.nonce,
155
+ },
156
+ });
157
+ return {
158
+ x402Version: DEFAULTS.x402Version,
159
+ scheme: requirements.scheme ?? 'exact',
160
+ network: requirements.network,
161
+ payload: {
162
+ signature,
163
+ authorization,
164
+ },
165
+ };
166
+ }
167
+ }
168
+ //# sourceMappingURL=buyer.js.map