@puga-labs/x402-mantle-sdk 0.1.0 → 0.2.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/dist/index.cjs CHANGED
@@ -58,6 +58,59 @@ function usdCentsToAtomic(cents, decimals) {
58
58
  return BigInt(cents) * base;
59
59
  }
60
60
 
61
+ // src/server/constants.ts
62
+ var DEFAULT_TELEMETRY_ENDPOINT = void 0;
63
+
64
+ // src/server/telemetry.ts
65
+ function createTelemetryEvent(entry, config) {
66
+ const assetConfig = getDefaultAssetForNetwork(entry.network);
67
+ return {
68
+ event: "payment_verified",
69
+ ts: entry.timestamp,
70
+ projectKey: config.projectKey,
71
+ network: entry.network,
72
+ buyer: entry.from,
73
+ payTo: entry.to,
74
+ amountAtomic: entry.valueAtomic,
75
+ asset: entry.asset,
76
+ decimals: assetConfig.decimals,
77
+ nonce: entry.id,
78
+ route: entry.route ?? "unknown",
79
+ // Facilitator metadata
80
+ facilitatorType: "hosted",
81
+ // SDK always uses hosted mode
82
+ facilitatorUrl: entry.facilitatorUrl,
83
+ // From PaymentLogEntry
84
+ // facilitatorAddress is undefined for SDK (not available)
85
+ // Optional metadata
86
+ txHash: entry.txHash,
87
+ priceUsd: entry.paymentRequirements?.price
88
+ };
89
+ }
90
+ async function sendTelemetry(event, endpoint) {
91
+ const targetEndpoint = endpoint ?? DEFAULT_TELEMETRY_ENDPOINT;
92
+ if (!targetEndpoint) {
93
+ return;
94
+ }
95
+ try {
96
+ const response = await fetch(targetEndpoint, {
97
+ method: "POST",
98
+ headers: {
99
+ "Content-Type": "application/json",
100
+ "Authorization": `Bearer ${event.projectKey}`
101
+ },
102
+ body: JSON.stringify(event)
103
+ });
104
+ if (!response.ok) {
105
+ console.warn(
106
+ `[x402-telemetry] Failed to send event: HTTP ${response.status}`
107
+ );
108
+ }
109
+ } catch (err) {
110
+ console.error("[x402-telemetry] Error sending telemetry:", err);
111
+ }
112
+ }
113
+
61
114
  // src/server/paymentMiddleware.ts
62
115
  function getRouteKey(req) {
63
116
  const method = (req.method || "GET").toUpperCase();
@@ -81,7 +134,7 @@ function decodePaymentHeader(paymentHeaderBase64) {
81
134
  }
82
135
  }
83
136
  function createPaymentMiddleware(config) {
84
- const { facilitatorUrl, receiverAddress, routes, onPaymentSettled } = config;
137
+ const { facilitatorUrl, receiverAddress, routes, onPaymentSettled, telemetry } = config;
85
138
  if (!facilitatorUrl) {
86
139
  throw new Error("facilitatorUrl is required");
87
140
  }
@@ -171,9 +224,17 @@ function createPaymentMiddleware(config) {
171
224
  asset: assetConfig.address,
172
225
  route: routeKey,
173
226
  timestamp: Date.now(),
227
+ facilitatorUrl,
228
+ // Pass from config closure
174
229
  paymentRequirements
175
230
  };
176
231
  onPaymentSettled(logEntry);
232
+ if (telemetry) {
233
+ const event = createTelemetryEvent(logEntry, telemetry);
234
+ sendTelemetry(event, telemetry.endpoint).catch(
235
+ (err) => console.error("[x402-telemetry] Async send failed:", err)
236
+ );
237
+ }
177
238
  } catch (err) {
178
239
  console.error(
179
240
  "[x402-mantle-sdk] Error calling onPaymentSettled hook:",
@@ -300,7 +361,8 @@ function createPaymentClient(config) {
300
361
  resourceUrl,
301
362
  facilitatorUrl,
302
363
  provider,
303
- userAddress: userAddressOverride
364
+ userAddress: userAddressOverride,
365
+ projectKey
304
366
  } = config;
305
367
  if (!resourceUrl) {
306
368
  throw new Error("resourceUrl is required");
@@ -387,7 +449,8 @@ function createPaymentClient(config) {
387
449
  const settleRes = await fetch(settleUrl, {
388
450
  method: "POST",
389
451
  headers: {
390
- "Content-Type": "application/json"
452
+ "Content-Type": "application/json",
453
+ ...projectKey ? { "X-Project-Key": projectKey } : {}
391
454
  },
392
455
  body: JSON.stringify({
393
456
  x402Version: 1,
package/dist/index.d.cts CHANGED
@@ -64,8 +64,39 @@ interface PaymentLogEntry {
64
64
  route?: RouteKey;
65
65
  txHash?: string;
66
66
  timestamp: number;
67
+ facilitatorUrl?: string;
67
68
  paymentRequirements?: PaymentRequirements;
68
69
  }
70
+ /** Config for optional telemetry (billing/analytics). */
71
+ interface TelemetryConfig {
72
+ /** Project key from nosubs.ai dashboard. */
73
+ projectKey: string;
74
+ /**
75
+ * Telemetry endpoint URL.
76
+ * If not specified, uses DEFAULT_TELEMETRY_ENDPOINT (see server/constants.ts).
77
+ * If both are undefined, telemetry is not sent.
78
+ */
79
+ endpoint?: string;
80
+ }
81
+ /** Telemetry event payload for payment_verified. */
82
+ interface TelemetryEvent {
83
+ event: "payment_verified";
84
+ ts: number;
85
+ projectKey: string;
86
+ network: string;
87
+ buyer: string;
88
+ payTo: string;
89
+ amountAtomic: string;
90
+ asset: string;
91
+ decimals: number;
92
+ nonce: string;
93
+ route: string;
94
+ facilitatorType: "hosted" | "self-hosted";
95
+ facilitatorUrl?: string;
96
+ facilitatorAddress?: string;
97
+ txHash?: string;
98
+ priceUsd?: string;
99
+ }
69
100
  /** Config for createPaymentMiddleware. */
70
101
  interface PaymentMiddlewareConfig {
71
102
  /** Base URL of facilitator, e.g. https://facilitator.nosubs.ai */
@@ -79,6 +110,8 @@ interface PaymentMiddlewareConfig {
79
110
  * You can use this to push logs into your DB / analytics pipeline.
80
111
  */
81
112
  onPaymentSettled?: (entry: PaymentLogEntry) => void;
113
+ /** Optional: Send usage telemetry for billing/analytics. */
114
+ telemetry?: TelemetryConfig;
82
115
  }
83
116
 
84
117
  declare function createPaymentMiddleware(config: PaymentMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -93,6 +126,8 @@ interface PaymentClientConfig {
93
126
  provider: unknown;
94
127
  /** Optional user address override; otherwise derived from provider. */
95
128
  userAddress?: string;
129
+ /** Optional: Project key for hosted facilitator billing. */
130
+ projectKey?: string;
96
131
  }
97
132
  /** Result of a callWithPayment() client operation. */
98
133
  interface CallWithPaymentResult<TResponseBody = unknown> {
@@ -122,8 +157,8 @@ interface PaymentClient {
122
157
  * - calls facilitator /settle
123
158
  * - retries the original request with X-PAYMENT header
124
159
  *
125
- * This logic is x402-like and tailored for Mantle + USDC.
160
+ * This logic is x402 and tailored for Mantle + USDC.
126
161
  */
127
162
  declare function createPaymentClient(config: PaymentClientConfig): PaymentClient;
128
163
 
129
- export { type AssetConfig, type Authorization, type CallWithPaymentResult, type NetworkId, type PaymentClient, type PaymentClientConfig, type PaymentHeaderBase64, type PaymentHeaderObject, type PaymentHeaderPayload, type PaymentLogEntry, type PaymentMiddlewareConfig, type PaymentRequirements, type RouteKey, type RoutePricingConfig, type RoutesConfig, createPaymentClient, createPaymentMiddleware };
164
+ export { type AssetConfig, type Authorization, type CallWithPaymentResult, type NetworkId, type PaymentClient, type PaymentClientConfig, type PaymentHeaderBase64, type PaymentHeaderObject, type PaymentHeaderPayload, type PaymentLogEntry, type PaymentMiddlewareConfig, type PaymentRequirements, type RouteKey, type RoutePricingConfig, type RoutesConfig, type TelemetryConfig, type TelemetryEvent, createPaymentClient, createPaymentMiddleware };
package/dist/index.d.ts CHANGED
@@ -64,8 +64,39 @@ interface PaymentLogEntry {
64
64
  route?: RouteKey;
65
65
  txHash?: string;
66
66
  timestamp: number;
67
+ facilitatorUrl?: string;
67
68
  paymentRequirements?: PaymentRequirements;
68
69
  }
70
+ /** Config for optional telemetry (billing/analytics). */
71
+ interface TelemetryConfig {
72
+ /** Project key from nosubs.ai dashboard. */
73
+ projectKey: string;
74
+ /**
75
+ * Telemetry endpoint URL.
76
+ * If not specified, uses DEFAULT_TELEMETRY_ENDPOINT (see server/constants.ts).
77
+ * If both are undefined, telemetry is not sent.
78
+ */
79
+ endpoint?: string;
80
+ }
81
+ /** Telemetry event payload for payment_verified. */
82
+ interface TelemetryEvent {
83
+ event: "payment_verified";
84
+ ts: number;
85
+ projectKey: string;
86
+ network: string;
87
+ buyer: string;
88
+ payTo: string;
89
+ amountAtomic: string;
90
+ asset: string;
91
+ decimals: number;
92
+ nonce: string;
93
+ route: string;
94
+ facilitatorType: "hosted" | "self-hosted";
95
+ facilitatorUrl?: string;
96
+ facilitatorAddress?: string;
97
+ txHash?: string;
98
+ priceUsd?: string;
99
+ }
69
100
  /** Config for createPaymentMiddleware. */
70
101
  interface PaymentMiddlewareConfig {
71
102
  /** Base URL of facilitator, e.g. https://facilitator.nosubs.ai */
@@ -79,6 +110,8 @@ interface PaymentMiddlewareConfig {
79
110
  * You can use this to push logs into your DB / analytics pipeline.
80
111
  */
81
112
  onPaymentSettled?: (entry: PaymentLogEntry) => void;
113
+ /** Optional: Send usage telemetry for billing/analytics. */
114
+ telemetry?: TelemetryConfig;
82
115
  }
83
116
 
84
117
  declare function createPaymentMiddleware(config: PaymentMiddlewareConfig): (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -93,6 +126,8 @@ interface PaymentClientConfig {
93
126
  provider: unknown;
94
127
  /** Optional user address override; otherwise derived from provider. */
95
128
  userAddress?: string;
129
+ /** Optional: Project key for hosted facilitator billing. */
130
+ projectKey?: string;
96
131
  }
97
132
  /** Result of a callWithPayment() client operation. */
98
133
  interface CallWithPaymentResult<TResponseBody = unknown> {
@@ -122,8 +157,8 @@ interface PaymentClient {
122
157
  * - calls facilitator /settle
123
158
  * - retries the original request with X-PAYMENT header
124
159
  *
125
- * This logic is x402-like and tailored for Mantle + USDC.
160
+ * This logic is x402 and tailored for Mantle + USDC.
126
161
  */
127
162
  declare function createPaymentClient(config: PaymentClientConfig): PaymentClient;
128
163
 
129
- export { type AssetConfig, type Authorization, type CallWithPaymentResult, type NetworkId, type PaymentClient, type PaymentClientConfig, type PaymentHeaderBase64, type PaymentHeaderObject, type PaymentHeaderPayload, type PaymentLogEntry, type PaymentMiddlewareConfig, type PaymentRequirements, type RouteKey, type RoutePricingConfig, type RoutesConfig, createPaymentClient, createPaymentMiddleware };
164
+ export { type AssetConfig, type Authorization, type CallWithPaymentResult, type NetworkId, type PaymentClient, type PaymentClientConfig, type PaymentHeaderBase64, type PaymentHeaderObject, type PaymentHeaderPayload, type PaymentLogEntry, type PaymentMiddlewareConfig, type PaymentRequirements, type RouteKey, type RoutePricingConfig, type RoutesConfig, type TelemetryConfig, type TelemetryEvent, createPaymentClient, createPaymentMiddleware };
package/dist/index.js CHANGED
@@ -38,6 +38,59 @@ function usdCentsToAtomic(cents, decimals) {
38
38
  return BigInt(cents) * base;
39
39
  }
40
40
 
41
+ // src/server/constants.ts
42
+ var DEFAULT_TELEMETRY_ENDPOINT = void 0;
43
+
44
+ // src/server/telemetry.ts
45
+ function createTelemetryEvent(entry, config) {
46
+ const assetConfig = getDefaultAssetForNetwork(entry.network);
47
+ return {
48
+ event: "payment_verified",
49
+ ts: entry.timestamp,
50
+ projectKey: config.projectKey,
51
+ network: entry.network,
52
+ buyer: entry.from,
53
+ payTo: entry.to,
54
+ amountAtomic: entry.valueAtomic,
55
+ asset: entry.asset,
56
+ decimals: assetConfig.decimals,
57
+ nonce: entry.id,
58
+ route: entry.route ?? "unknown",
59
+ // Facilitator metadata
60
+ facilitatorType: "hosted",
61
+ // SDK always uses hosted mode
62
+ facilitatorUrl: entry.facilitatorUrl,
63
+ // From PaymentLogEntry
64
+ // facilitatorAddress is undefined for SDK (not available)
65
+ // Optional metadata
66
+ txHash: entry.txHash,
67
+ priceUsd: entry.paymentRequirements?.price
68
+ };
69
+ }
70
+ async function sendTelemetry(event, endpoint) {
71
+ const targetEndpoint = endpoint ?? DEFAULT_TELEMETRY_ENDPOINT;
72
+ if (!targetEndpoint) {
73
+ return;
74
+ }
75
+ try {
76
+ const response = await fetch(targetEndpoint, {
77
+ method: "POST",
78
+ headers: {
79
+ "Content-Type": "application/json",
80
+ "Authorization": `Bearer ${event.projectKey}`
81
+ },
82
+ body: JSON.stringify(event)
83
+ });
84
+ if (!response.ok) {
85
+ console.warn(
86
+ `[x402-telemetry] Failed to send event: HTTP ${response.status}`
87
+ );
88
+ }
89
+ } catch (err) {
90
+ console.error("[x402-telemetry] Error sending telemetry:", err);
91
+ }
92
+ }
93
+
41
94
  // src/server/paymentMiddleware.ts
42
95
  function getRouteKey(req) {
43
96
  const method = (req.method || "GET").toUpperCase();
@@ -61,7 +114,7 @@ function decodePaymentHeader(paymentHeaderBase64) {
61
114
  }
62
115
  }
63
116
  function createPaymentMiddleware(config) {
64
- const { facilitatorUrl, receiverAddress, routes, onPaymentSettled } = config;
117
+ const { facilitatorUrl, receiverAddress, routes, onPaymentSettled, telemetry } = config;
65
118
  if (!facilitatorUrl) {
66
119
  throw new Error("facilitatorUrl is required");
67
120
  }
@@ -151,9 +204,17 @@ function createPaymentMiddleware(config) {
151
204
  asset: assetConfig.address,
152
205
  route: routeKey,
153
206
  timestamp: Date.now(),
207
+ facilitatorUrl,
208
+ // Pass from config closure
154
209
  paymentRequirements
155
210
  };
156
211
  onPaymentSettled(logEntry);
212
+ if (telemetry) {
213
+ const event = createTelemetryEvent(logEntry, telemetry);
214
+ sendTelemetry(event, telemetry.endpoint).catch(
215
+ (err) => console.error("[x402-telemetry] Async send failed:", err)
216
+ );
217
+ }
157
218
  } catch (err) {
158
219
  console.error(
159
220
  "[x402-mantle-sdk] Error calling onPaymentSettled hook:",
@@ -280,7 +341,8 @@ function createPaymentClient(config) {
280
341
  resourceUrl,
281
342
  facilitatorUrl,
282
343
  provider,
283
- userAddress: userAddressOverride
344
+ userAddress: userAddressOverride,
345
+ projectKey
284
346
  } = config;
285
347
  if (!resourceUrl) {
286
348
  throw new Error("resourceUrl is required");
@@ -367,7 +429,8 @@ function createPaymentClient(config) {
367
429
  const settleRes = await fetch(settleUrl, {
368
430
  method: "POST",
369
431
  headers: {
370
- "Content-Type": "application/json"
432
+ "Content-Type": "application/json",
433
+ ...projectKey ? { "X-Project-Key": projectKey } : {}
371
434
  },
372
435
  body: JSON.stringify({
373
436
  x402Version: 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@puga-labs/x402-mantle-sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "x402 payments SDK for Mantle (USDC, gasless, facilitator-based)",
5
5
  "license": "MIT",
6
6
  "author": "Evgenii Pugachev <cyprus.pugamuga@gmail.com>",