@agentspend/sdk 0.3.2 → 0.3.3

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.js CHANGED
@@ -42,6 +42,27 @@ function createAgentSpend(options) {
42
42
  }
43
43
  const platformApiBaseUrl = resolvePlatformApiBaseUrl(options.platformApiBaseUrl);
44
44
  // -------------------------------------------------------------------
45
+ // Lazy service_id fetch + cache
46
+ // -------------------------------------------------------------------
47
+ let cachedServiceId = null;
48
+ async function getServiceId() {
49
+ if (cachedServiceId)
50
+ return cachedServiceId;
51
+ if (!options.serviceApiKey)
52
+ return null;
53
+ try {
54
+ const res = await fetchImpl(joinUrl(platformApiBaseUrl, "/v1/service/me"), {
55
+ headers: { authorization: `Bearer ${options.serviceApiKey}` }
56
+ });
57
+ if (res.ok) {
58
+ const data = (await res.json());
59
+ cachedServiceId = data.id ?? null;
60
+ }
61
+ }
62
+ catch { /* graceful fallback */ }
63
+ return cachedServiceId;
64
+ }
65
+ // -------------------------------------------------------------------
45
66
  // x402 singleton setup (Decision 9)
46
67
  // Server-side: facilitator handles verify + settle over HTTP.
47
68
  // No client-side EVM scheme needed — we delegate to the facilitator.
@@ -167,6 +188,10 @@ function createAgentSpend(options) {
167
188
  }
168
189
  catch (error) {
169
190
  if (error instanceof AgentSpendChargeError) {
191
+ if (error.statusCode === 403) {
192
+ // No binding — return 402 so agent can discover service_id and bind
193
+ return return402Response(c, amountCents, currency);
194
+ }
170
195
  if (error.statusCode === 402) {
171
196
  return c.json({ error: "Payment required", details: error.details }, 402);
172
197
  }
@@ -236,6 +261,7 @@ function createAgentSpend(options) {
236
261
  // return402Response — x402 Payment-Required format (Decision 8)
237
262
  // -------------------------------------------------------------------
238
263
  async function return402Response(c, amountCents, currency) {
264
+ const serviceId = await getServiceId();
239
265
  try {
240
266
  const payTo = await resolvePayToAddress();
241
267
  const paymentRequirements = {
@@ -261,11 +287,31 @@ function createAgentSpend(options) {
261
287
  // Set Payment-Required header (base64 encoded)
262
288
  const headerValue = Buffer.from(JSON.stringify(paymentRequired)).toString("base64");
263
289
  c.header("Payment-Required", headerValue);
264
- return c.json({ error: "Payment required", amount_cents: amountCents, currency }, 402);
290
+ return c.json({
291
+ error: "Payment required",
292
+ amount_cents: amountCents,
293
+ currency,
294
+ ...(serviceId ? {
295
+ agentspend: {
296
+ service_id: serviceId,
297
+ amount_cents: amountCents,
298
+ }
299
+ } : {})
300
+ }, 402);
265
301
  }
266
302
  catch {
267
303
  // If we can't resolve a payTo address, return a plain 402
268
- return c.json({ error: "Payment required", amount_cents: amountCents, currency }, 402);
304
+ return c.json({
305
+ error: "Payment required",
306
+ amount_cents: amountCents,
307
+ currency,
308
+ ...(serviceId ? {
309
+ agentspend: {
310
+ service_id: serviceId,
311
+ amount_cents: amountCents,
312
+ }
313
+ } : {})
314
+ }, 402);
269
315
  }
270
316
  }
271
317
  // -------------------------------------------------------------------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentspend/sdk",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "publishConfig": {
package/src/index.ts CHANGED
@@ -170,6 +170,26 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
170
170
 
171
171
  const platformApiBaseUrl = resolvePlatformApiBaseUrl(options.platformApiBaseUrl);
172
172
 
173
+ // -------------------------------------------------------------------
174
+ // Lazy service_id fetch + cache
175
+ // -------------------------------------------------------------------
176
+ let cachedServiceId: string | null = null;
177
+
178
+ async function getServiceId(): Promise<string | null> {
179
+ if (cachedServiceId) return cachedServiceId;
180
+ if (!options.serviceApiKey) return null;
181
+ try {
182
+ const res = await fetchImpl(joinUrl(platformApiBaseUrl, "/v1/service/me"), {
183
+ headers: { authorization: `Bearer ${options.serviceApiKey}` }
184
+ });
185
+ if (res.ok) {
186
+ const data = (await res.json()) as { id?: string };
187
+ cachedServiceId = data.id ?? null;
188
+ }
189
+ } catch { /* graceful fallback */ }
190
+ return cachedServiceId;
191
+ }
192
+
173
193
  // -------------------------------------------------------------------
174
194
  // x402 singleton setup (Decision 9)
175
195
  // Server-side: facilitator handles verify + settle over HTTP.
@@ -336,6 +356,10 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
336
356
  c.set(PAYMENT_CONTEXT_KEY, paymentContext);
337
357
  } catch (error) {
338
358
  if (error instanceof AgentSpendChargeError) {
359
+ if (error.statusCode === 403) {
360
+ // No binding — return 402 so agent can discover service_id and bind
361
+ return return402Response(c, amountCents, currency);
362
+ }
339
363
  if (error.statusCode === 402) {
340
364
  return c.json({ error: "Payment required", details: error.details }, 402);
341
365
  }
@@ -446,6 +470,8 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
446
470
  amountCents: number,
447
471
  currency: string
448
472
  ): Promise<Response> {
473
+ const serviceId = await getServiceId();
474
+
449
475
  try {
450
476
  const payTo = await resolvePayToAddress();
451
477
 
@@ -477,11 +503,31 @@ export function createAgentSpend(options: AgentSpendOptions): AgentSpend {
477
503
  ).toString("base64");
478
504
  c.header("Payment-Required", headerValue);
479
505
 
480
- return c.json({ error: "Payment required", amount_cents: amountCents, currency }, 402);
506
+ return c.json({
507
+ error: "Payment required",
508
+ amount_cents: amountCents,
509
+ currency,
510
+ ...(serviceId ? {
511
+ agentspend: {
512
+ service_id: serviceId,
513
+ amount_cents: amountCents,
514
+ }
515
+ } : {})
516
+ }, 402);
481
517
  } catch {
482
518
  // If we can't resolve a payTo address, return a plain 402
483
519
  return c.json(
484
- { error: "Payment required", amount_cents: amountCents, currency },
520
+ {
521
+ error: "Payment required",
522
+ amount_cents: amountCents,
523
+ currency,
524
+ ...(serviceId ? {
525
+ agentspend: {
526
+ service_id: serviceId,
527
+ amount_cents: amountCents,
528
+ }
529
+ } : {})
530
+ },
485
531
  402
486
532
  );
487
533
  }