@agentspend/sdk 0.3.8 → 0.3.9
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/core/client.d.ts +6 -0
- package/dist/core/client.js +308 -0
- package/dist/core/error.d.ts +5 -0
- package/dist/core/error.js +9 -0
- package/dist/core/helpers.d.ts +8 -0
- package/dist/core/helpers.js +77 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +4 -0
- package/dist/{index.d.ts → core/types.d.ts} +21 -22
- package/dist/core/types.js +4 -0
- package/dist/express/index.d.ts +22 -0
- package/dist/express/index.js +50 -0
- package/dist/fastify/index.d.ts +27 -0
- package/dist/fastify/index.js +58 -0
- package/dist/hono/index.d.ts +20 -0
- package/dist/hono/index.js +49 -0
- package/dist/next/index.d.ts +15 -0
- package/dist/next/index.js +39 -0
- package/package.json +50 -3
- package/src/core/client.ts +433 -0
- package/src/core/error.ts +10 -0
- package/src/core/helpers.ts +87 -0
- package/src/core/index.ts +5 -0
- package/src/core/types.ts +104 -0
- package/src/express/index.ts +101 -0
- package/src/fastify/index.ts +120 -0
- package/src/hono/index.ts +97 -0
- package/src/next/index.ts +92 -0
- package/dist/index.js +0 -420
- package/src/index.ts +0 -662
package/dist/index.js
DELETED
|
@@ -1,420 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// ---------------------------------------------------------------------------
|
|
3
|
-
// Types (inlined from @agentspend/types to avoid cross-repo publish)
|
|
4
|
-
// ---------------------------------------------------------------------------
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.AgentSpendChargeError = void 0;
|
|
7
|
-
exports.getPaymentContext = getPaymentContext;
|
|
8
|
-
exports.createAgentSpend = createAgentSpend;
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
// x402 imports – server-side only (HTTP calls to facilitator, no crypto deps)
|
|
11
|
-
// ---------------------------------------------------------------------------
|
|
12
|
-
const server_1 = require("@x402/core/server");
|
|
13
|
-
const server_2 = require("@x402/evm/exact/server");
|
|
14
|
-
class AgentSpendChargeError extends Error {
|
|
15
|
-
statusCode;
|
|
16
|
-
details;
|
|
17
|
-
constructor(message, statusCode, details) {
|
|
18
|
-
super(message);
|
|
19
|
-
this.statusCode = statusCode;
|
|
20
|
-
this.details = details;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
exports.AgentSpendChargeError = AgentSpendChargeError;
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
// Payment context helper
|
|
26
|
-
// ---------------------------------------------------------------------------
|
|
27
|
-
const PAYMENT_CONTEXT_KEY = "payment";
|
|
28
|
-
function getPaymentContext(c) {
|
|
29
|
-
const ctx = c.get(PAYMENT_CONTEXT_KEY);
|
|
30
|
-
return ctx ?? null;
|
|
31
|
-
}
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
// Factory
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
function createAgentSpend(options) {
|
|
36
|
-
// Validate: at least one of serviceApiKey or crypto must be provided
|
|
37
|
-
if (!options.serviceApiKey && !options.crypto) {
|
|
38
|
-
throw new AgentSpendChargeError("At least one of serviceApiKey or crypto config must be provided", 500);
|
|
39
|
-
}
|
|
40
|
-
const fetchImpl = options.fetchImpl ?? globalThis.fetch;
|
|
41
|
-
if (!fetchImpl) {
|
|
42
|
-
throw new AgentSpendChargeError("No fetch implementation available", 500);
|
|
43
|
-
}
|
|
44
|
-
const platformApiBaseUrl = resolvePlatformApiBaseUrl(options.platformApiBaseUrl);
|
|
45
|
-
// -------------------------------------------------------------------
|
|
46
|
-
// Lazy service_id fetch + cache
|
|
47
|
-
// -------------------------------------------------------------------
|
|
48
|
-
let cachedServiceId = null;
|
|
49
|
-
async function getServiceId() {
|
|
50
|
-
if (cachedServiceId)
|
|
51
|
-
return cachedServiceId;
|
|
52
|
-
if (!options.serviceApiKey)
|
|
53
|
-
return null;
|
|
54
|
-
try {
|
|
55
|
-
const res = await fetchImpl(joinUrl(platformApiBaseUrl, "/v1/service/me"), {
|
|
56
|
-
headers: { authorization: `Bearer ${options.serviceApiKey}` }
|
|
57
|
-
});
|
|
58
|
-
if (res.ok) {
|
|
59
|
-
const data = (await res.json());
|
|
60
|
-
cachedServiceId = data.id ?? null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
catch { /* graceful fallback */ }
|
|
64
|
-
return cachedServiceId;
|
|
65
|
-
}
|
|
66
|
-
// -------------------------------------------------------------------
|
|
67
|
-
// x402 singleton setup (Decision 9)
|
|
68
|
-
// Server-side: facilitator handles verify + settle over HTTP.
|
|
69
|
-
// No client-side EVM scheme needed — we delegate to the facilitator.
|
|
70
|
-
// -------------------------------------------------------------------
|
|
71
|
-
let facilitator = null;
|
|
72
|
-
let resourceServer = null;
|
|
73
|
-
const cryptoNetwork = (options.crypto?.network ?? "eip155:8453");
|
|
74
|
-
if (options.crypto || options.serviceApiKey) {
|
|
75
|
-
const facilitatorUrl = options.crypto?.facilitatorUrl ?? "https://facilitator.openx402.ai";
|
|
76
|
-
facilitator = new server_1.HTTPFacilitatorClient({ url: facilitatorUrl });
|
|
77
|
-
resourceServer = new server_1.x402ResourceServer(facilitator);
|
|
78
|
-
(0, server_2.registerExactEvmScheme)(resourceServer);
|
|
79
|
-
}
|
|
80
|
-
// -------------------------------------------------------------------
|
|
81
|
-
// charge() — card-only, unchanged
|
|
82
|
-
// -------------------------------------------------------------------
|
|
83
|
-
async function charge(cardIdInput, opts) {
|
|
84
|
-
if (!options.serviceApiKey) {
|
|
85
|
-
throw new AgentSpendChargeError("charge() requires serviceApiKey", 500);
|
|
86
|
-
}
|
|
87
|
-
const cardId = toCardId(cardIdInput);
|
|
88
|
-
if (!cardId) {
|
|
89
|
-
throw new AgentSpendChargeError("card_id must start with card_", 400);
|
|
90
|
-
}
|
|
91
|
-
if (!Number.isInteger(opts.amount_cents) || opts.amount_cents <= 0) {
|
|
92
|
-
throw new AgentSpendChargeError("amount_cents must be a positive integer", 400);
|
|
93
|
-
}
|
|
94
|
-
const payload = {
|
|
95
|
-
card_id: cardId,
|
|
96
|
-
amount_cents: opts.amount_cents,
|
|
97
|
-
currency: opts.currency ?? "usd",
|
|
98
|
-
...(opts.description ? { description: opts.description } : {}),
|
|
99
|
-
...(opts.metadata ? { metadata: opts.metadata } : {}),
|
|
100
|
-
idempotency_key: opts.idempotency_key ?? bestEffortIdempotencyKey()
|
|
101
|
-
};
|
|
102
|
-
const response = await fetchImpl(joinUrl(platformApiBaseUrl, "/v1/charge"), {
|
|
103
|
-
method: "POST",
|
|
104
|
-
headers: {
|
|
105
|
-
authorization: `Bearer ${options.serviceApiKey}`,
|
|
106
|
-
"content-type": "application/json"
|
|
107
|
-
},
|
|
108
|
-
body: JSON.stringify(payload)
|
|
109
|
-
});
|
|
110
|
-
const responseBody = (await response.json().catch(() => ({})));
|
|
111
|
-
if (!response.ok) {
|
|
112
|
-
throw new AgentSpendChargeError(typeof responseBody.error === "string" ? responseBody.error : "AgentSpend charge failed", response.status, responseBody);
|
|
113
|
-
}
|
|
114
|
-
return responseBody;
|
|
115
|
-
}
|
|
116
|
-
// -------------------------------------------------------------------
|
|
117
|
-
// paywall() — unified card + crypto middleware
|
|
118
|
-
// -------------------------------------------------------------------
|
|
119
|
-
function paywall(opts) {
|
|
120
|
-
const { amount } = opts;
|
|
121
|
-
// Validate fixed-price amount at creation time
|
|
122
|
-
if (typeof amount === "number") {
|
|
123
|
-
if (!Number.isInteger(amount) || amount <= 0) {
|
|
124
|
-
throw new AgentSpendChargeError("amount must be a positive integer", 500);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return async function paywallMiddleware(c, next) {
|
|
128
|
-
// Step 1: Parse body once (Decision 11)
|
|
129
|
-
const body = await c.req.json().catch(() => ({}));
|
|
130
|
-
// Step 2: Determine effective amount
|
|
131
|
-
let effectiveAmount;
|
|
132
|
-
if (typeof amount === "number") {
|
|
133
|
-
effectiveAmount = amount;
|
|
134
|
-
}
|
|
135
|
-
else if (typeof amount === "string") {
|
|
136
|
-
const raw = body?.[amount];
|
|
137
|
-
effectiveAmount = typeof raw === "number" ? raw : 0;
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
effectiveAmount = amount(body);
|
|
141
|
-
}
|
|
142
|
-
if (!Number.isInteger(effectiveAmount) || effectiveAmount <= 0) {
|
|
143
|
-
return c.json({ error: "Could not determine payment amount from request" }, 400);
|
|
144
|
-
}
|
|
145
|
-
const currency = opts.currency ?? "usd";
|
|
146
|
-
// Step 3: Check for payment header → crypto payment
|
|
147
|
-
// x402 v2 uses "Payment-Signature", v1 uses "X-Payment"
|
|
148
|
-
const paymentHeader = c.req.header("payment-signature") ?? c.req.header("x-payment");
|
|
149
|
-
if (paymentHeader) {
|
|
150
|
-
return handleCryptoPayment(c, next, paymentHeader, effectiveAmount, currency, body, opts);
|
|
151
|
-
}
|
|
152
|
-
// Step 4: Check for x-card-id header or body.card_id → card payment
|
|
153
|
-
const cardIdFromHeader = c.req.header("x-card-id");
|
|
154
|
-
let cardId = cardIdFromHeader ? toCardId(cardIdFromHeader) : null;
|
|
155
|
-
if (!cardId) {
|
|
156
|
-
const bodyCardId = typeof body?.card_id === "string"
|
|
157
|
-
? body.card_id
|
|
158
|
-
: null;
|
|
159
|
-
cardId = toCardId(bodyCardId);
|
|
160
|
-
}
|
|
161
|
-
if (cardId) {
|
|
162
|
-
return handleCardPayment(c, next, cardId, effectiveAmount, currency, body, opts);
|
|
163
|
-
}
|
|
164
|
-
// Step 5: Neither → return 402 with Payment-Required header (Decision 8)
|
|
165
|
-
return return402Response(c, effectiveAmount, currency);
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
// -------------------------------------------------------------------
|
|
169
|
-
// handleCardPayment — existing charge() flow
|
|
170
|
-
// -------------------------------------------------------------------
|
|
171
|
-
async function handleCardPayment(c, next, cardId, amountCents, currency, body, opts) {
|
|
172
|
-
if (!options.serviceApiKey) {
|
|
173
|
-
return c.json({ error: "Card payments require serviceApiKey" }, 500);
|
|
174
|
-
}
|
|
175
|
-
try {
|
|
176
|
-
const chargeResult = await charge(cardId, {
|
|
177
|
-
amount_cents: amountCents,
|
|
178
|
-
currency,
|
|
179
|
-
description: opts.description,
|
|
180
|
-
metadata: opts.metadata ? toStringMetadata(opts.metadata(body)) : undefined,
|
|
181
|
-
idempotency_key: c.req.header("x-request-id") ?? c.req.header("idempotency-key") ?? undefined
|
|
182
|
-
});
|
|
183
|
-
const paymentContext = {
|
|
184
|
-
method: "card",
|
|
185
|
-
amount_cents: amountCents,
|
|
186
|
-
currency,
|
|
187
|
-
card_id: cardId,
|
|
188
|
-
remaining_limit_cents: chargeResult.remaining_limit_cents
|
|
189
|
-
};
|
|
190
|
-
c.set(PAYMENT_CONTEXT_KEY, paymentContext);
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
if (error instanceof AgentSpendChargeError) {
|
|
194
|
-
if (error.statusCode === 403) {
|
|
195
|
-
// No binding — return 402 so agent can discover service_id and bind
|
|
196
|
-
return return402Response(c, amountCents, currency);
|
|
197
|
-
}
|
|
198
|
-
if (error.statusCode === 402) {
|
|
199
|
-
return c.json({ error: "Payment required", details: error.details }, 402);
|
|
200
|
-
}
|
|
201
|
-
return c.json({ error: error.message, details: error.details }, error.statusCode);
|
|
202
|
-
}
|
|
203
|
-
return c.json({ error: "Unexpected paywall failure" }, 500);
|
|
204
|
-
}
|
|
205
|
-
await next();
|
|
206
|
-
}
|
|
207
|
-
// -------------------------------------------------------------------
|
|
208
|
-
// handleCryptoPayment — x402 verify + settle via facilitator
|
|
209
|
-
// -------------------------------------------------------------------
|
|
210
|
-
async function handleCryptoPayment(c, next, paymentHeader, amountCents, currency, _body, _opts) {
|
|
211
|
-
if (!resourceServer) {
|
|
212
|
-
return c.json({ error: "Crypto payments not configured" }, 500);
|
|
213
|
-
}
|
|
214
|
-
try {
|
|
215
|
-
// Decode the x-payment header (base64 JSON payment payload)
|
|
216
|
-
let paymentPayload;
|
|
217
|
-
try {
|
|
218
|
-
paymentPayload = JSON.parse(Buffer.from(paymentHeader, "base64").toString("utf-8"));
|
|
219
|
-
}
|
|
220
|
-
catch {
|
|
221
|
-
return c.json({ error: "Invalid payment payload encoding" }, 400);
|
|
222
|
-
}
|
|
223
|
-
// Extract payTo from the payment payload's accepted requirements
|
|
224
|
-
// rather than generating a new deposit address.
|
|
225
|
-
// resolvePayToAddress() creates a fresh Stripe PaymentIntent each
|
|
226
|
-
// time, which would return a *different* address than the one in the
|
|
227
|
-
// 402 response the client signed against → facilitator verification
|
|
228
|
-
// would fail.
|
|
229
|
-
const acceptedPayTo = paymentPayload
|
|
230
|
-
.accepted?.payTo;
|
|
231
|
-
const payTo = acceptedPayTo ?? await resolvePayToAddress();
|
|
232
|
-
// Build the payment requirements that the payment should satisfy
|
|
233
|
-
const paymentRequirements = {
|
|
234
|
-
scheme: "exact",
|
|
235
|
-
network: cryptoNetwork,
|
|
236
|
-
amount: String(amountCents),
|
|
237
|
-
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
|
|
238
|
-
payTo,
|
|
239
|
-
maxTimeoutSeconds: 300,
|
|
240
|
-
extra: { name: "USD Coin", version: "2" }
|
|
241
|
-
};
|
|
242
|
-
// Verify payment via resource server (delegates to facilitator)
|
|
243
|
-
const verifyResult = await resourceServer.verifyPayment(paymentPayload, paymentRequirements);
|
|
244
|
-
if (!verifyResult.isValid) {
|
|
245
|
-
return c.json({ error: "Payment verification failed", details: verifyResult.invalidReason }, 402);
|
|
246
|
-
}
|
|
247
|
-
// Settle payment via resource server (delegates to facilitator)
|
|
248
|
-
const settleResult = await resourceServer.settlePayment(paymentPayload, paymentRequirements);
|
|
249
|
-
if (!settleResult.success) {
|
|
250
|
-
return c.json({ error: "Payment settlement failed", details: settleResult.errorReason }, 402);
|
|
251
|
-
}
|
|
252
|
-
const paymentContext = {
|
|
253
|
-
method: "crypto",
|
|
254
|
-
amount_cents: amountCents,
|
|
255
|
-
currency,
|
|
256
|
-
transaction_hash: settleResult.transaction,
|
|
257
|
-
payer_address: verifyResult.payer ?? undefined,
|
|
258
|
-
network: cryptoNetwork
|
|
259
|
-
};
|
|
260
|
-
c.set(PAYMENT_CONTEXT_KEY, paymentContext);
|
|
261
|
-
await next();
|
|
262
|
-
}
|
|
263
|
-
catch (error) {
|
|
264
|
-
if (error instanceof AgentSpendChargeError) {
|
|
265
|
-
return c.json({ error: error.message, details: error.details }, error.statusCode);
|
|
266
|
-
}
|
|
267
|
-
return c.json({ error: "Crypto payment processing failed", details: error.message }, 500);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
// -------------------------------------------------------------------
|
|
271
|
-
// return402Response — x402 Payment-Required format (Decision 8)
|
|
272
|
-
// -------------------------------------------------------------------
|
|
273
|
-
async function return402Response(c, amountCents, currency) {
|
|
274
|
-
const serviceId = await getServiceId();
|
|
275
|
-
try {
|
|
276
|
-
const payTo = await resolvePayToAddress();
|
|
277
|
-
const paymentRequirements = {
|
|
278
|
-
scheme: "exact",
|
|
279
|
-
network: cryptoNetwork,
|
|
280
|
-
amount: String(amountCents),
|
|
281
|
-
asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // USDC on Base
|
|
282
|
-
payTo,
|
|
283
|
-
maxTimeoutSeconds: 300,
|
|
284
|
-
extra: { name: "USD Coin", version: "2" }
|
|
285
|
-
};
|
|
286
|
-
// Build x402 v2 PaymentRequired response
|
|
287
|
-
const paymentRequired = {
|
|
288
|
-
x402Version: 2,
|
|
289
|
-
error: "Payment required",
|
|
290
|
-
resource: {
|
|
291
|
-
url: c.req.url,
|
|
292
|
-
description: `Payment of ${amountCents} cents`,
|
|
293
|
-
mimeType: "application/json"
|
|
294
|
-
},
|
|
295
|
-
accepts: [paymentRequirements]
|
|
296
|
-
};
|
|
297
|
-
// Set Payment-Required header (base64 encoded)
|
|
298
|
-
const headerValue = Buffer.from(JSON.stringify(paymentRequired)).toString("base64");
|
|
299
|
-
c.header("Payment-Required", headerValue);
|
|
300
|
-
return c.json({
|
|
301
|
-
error: "Payment required",
|
|
302
|
-
amount_cents: amountCents,
|
|
303
|
-
currency,
|
|
304
|
-
...(serviceId ? {
|
|
305
|
-
agentspend: {
|
|
306
|
-
service_id: serviceId,
|
|
307
|
-
amount_cents: amountCents,
|
|
308
|
-
}
|
|
309
|
-
} : {})
|
|
310
|
-
}, 402);
|
|
311
|
-
}
|
|
312
|
-
catch (error) {
|
|
313
|
-
// Log clearly so service developers can diagnose why crypto is unavailable
|
|
314
|
-
console.error("[agentspend] Failed to resolve crypto payTo address — returning card-only 402:", error instanceof Error ? error.message : error);
|
|
315
|
-
// Return card-only 402 (no Payment-Required header → crypto clients
|
|
316
|
-
// will see "Invalid payment required response")
|
|
317
|
-
return c.json({
|
|
318
|
-
error: "Payment required",
|
|
319
|
-
amount_cents: amountCents,
|
|
320
|
-
currency,
|
|
321
|
-
...(serviceId ? {
|
|
322
|
-
agentspend: {
|
|
323
|
-
service_id: serviceId,
|
|
324
|
-
amount_cents: amountCents,
|
|
325
|
-
}
|
|
326
|
-
} : {})
|
|
327
|
-
}, 402);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
// -------------------------------------------------------------------
|
|
331
|
-
// resolvePayToAddress — static address or Stripe Machine Payments
|
|
332
|
-
// -------------------------------------------------------------------
|
|
333
|
-
async function resolvePayToAddress() {
|
|
334
|
-
// Static address for crypto-only services
|
|
335
|
-
if (options.crypto?.receiverAddress) {
|
|
336
|
-
return options.crypto.receiverAddress;
|
|
337
|
-
}
|
|
338
|
-
// Stripe Connect service → get deposit address from platform
|
|
339
|
-
if (options.serviceApiKey) {
|
|
340
|
-
const response = await fetchImpl(joinUrl(platformApiBaseUrl, "/v1/crypto/deposit-address"), {
|
|
341
|
-
method: "POST",
|
|
342
|
-
headers: {
|
|
343
|
-
authorization: `Bearer ${options.serviceApiKey}`,
|
|
344
|
-
"content-type": "application/json"
|
|
345
|
-
},
|
|
346
|
-
body: JSON.stringify({ amount_cents: 0, currency: "usd" })
|
|
347
|
-
});
|
|
348
|
-
if (!response.ok) {
|
|
349
|
-
throw new AgentSpendChargeError("Failed to resolve crypto deposit address", 502);
|
|
350
|
-
}
|
|
351
|
-
const data = (await response.json());
|
|
352
|
-
if (!data.deposit_address) {
|
|
353
|
-
throw new AgentSpendChargeError("No deposit address returned", 502);
|
|
354
|
-
}
|
|
355
|
-
return data.deposit_address;
|
|
356
|
-
}
|
|
357
|
-
throw new AgentSpendChargeError("No crypto payTo address available", 500);
|
|
358
|
-
}
|
|
359
|
-
// -------------------------------------------------------------------
|
|
360
|
-
// Return public interface
|
|
361
|
-
// -------------------------------------------------------------------
|
|
362
|
-
return {
|
|
363
|
-
charge,
|
|
364
|
-
paywall
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
// ---------------------------------------------------------------------------
|
|
368
|
-
// Helpers (unchanged from original)
|
|
369
|
-
// ---------------------------------------------------------------------------
|
|
370
|
-
function toCardId(input) {
|
|
371
|
-
if (typeof input !== "string") {
|
|
372
|
-
return null;
|
|
373
|
-
}
|
|
374
|
-
const trimmed = input.trim();
|
|
375
|
-
if (!trimmed.startsWith("card_")) {
|
|
376
|
-
return null;
|
|
377
|
-
}
|
|
378
|
-
return trimmed;
|
|
379
|
-
}
|
|
380
|
-
function joinUrl(base, path) {
|
|
381
|
-
const normalizedBase = base.endsWith("/") ? base.slice(0, -1) : base;
|
|
382
|
-
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
383
|
-
return `${normalizedBase}${normalizedPath}`;
|
|
384
|
-
}
|
|
385
|
-
function bestEffortIdempotencyKey() {
|
|
386
|
-
const uuid = globalThis.crypto?.randomUUID?.();
|
|
387
|
-
if (uuid) {
|
|
388
|
-
return uuid;
|
|
389
|
-
}
|
|
390
|
-
return `auto_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
391
|
-
}
|
|
392
|
-
function toStringMetadata(input) {
|
|
393
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
394
|
-
return {};
|
|
395
|
-
}
|
|
396
|
-
const result = {};
|
|
397
|
-
for (const [key, value] of Object.entries(input)) {
|
|
398
|
-
if (typeof value === "string") {
|
|
399
|
-
result[key] = value;
|
|
400
|
-
}
|
|
401
|
-
else if (typeof value === "number" && Number.isFinite(value)) {
|
|
402
|
-
result[key] = String(value);
|
|
403
|
-
}
|
|
404
|
-
else if (typeof value === "boolean") {
|
|
405
|
-
result[key] = value ? "true" : "false";
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
return result;
|
|
409
|
-
}
|
|
410
|
-
const DEFAULT_PLATFORM_API_BASE_URL = "https://api.agentspend.co";
|
|
411
|
-
function resolvePlatformApiBaseUrl(explicitBaseUrl) {
|
|
412
|
-
if (explicitBaseUrl && explicitBaseUrl.trim().length > 0) {
|
|
413
|
-
return explicitBaseUrl.trim();
|
|
414
|
-
}
|
|
415
|
-
const envValue = typeof process !== "undefined" && process.env ? process.env.AGENTSPEND_API_URL : undefined;
|
|
416
|
-
if (typeof envValue === "string" && envValue.trim().length > 0) {
|
|
417
|
-
return envValue.trim();
|
|
418
|
-
}
|
|
419
|
-
return DEFAULT_PLATFORM_API_BASE_URL;
|
|
420
|
-
}
|