agentmall 0.1.2 → 0.1.4
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/cli.js +316 -86
- package/dist/index.cjs +35 -19
- package/dist/index.d.cts +11 -8
- package/dist/index.d.ts +11 -8
- package/dist/index.js +35 -19
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/cli/index.ts
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
|
|
3
6
|
// src/constants.ts
|
|
4
7
|
var BASE_URL = "https://api.agentmall.sh";
|
|
5
8
|
var SERVICE_FEE_CENTS = 150;
|
|
@@ -65,7 +68,6 @@ function createIdempotencyKey() {
|
|
|
65
68
|
var AgentMall = class {
|
|
66
69
|
baseUrl;
|
|
67
70
|
apiSecret;
|
|
68
|
-
account;
|
|
69
71
|
_fetch;
|
|
70
72
|
products;
|
|
71
73
|
purchases;
|
|
@@ -74,7 +76,6 @@ var AgentMall = class {
|
|
|
74
76
|
constructor(config = {}) {
|
|
75
77
|
this.baseUrl = (config.baseUrl ?? BASE_URL).replace(/\/$/, "");
|
|
76
78
|
this.apiSecret = config.apiSecret;
|
|
77
|
-
this.account = config.account;
|
|
78
79
|
this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
79
80
|
this.products = new AgentMallProducts(this);
|
|
80
81
|
this.purchases = new AgentMallPurchases(this);
|
|
@@ -82,8 +83,8 @@ var AgentMall = class {
|
|
|
82
83
|
this.refunds = new AgentMallRefunds(this);
|
|
83
84
|
}
|
|
84
85
|
/** @internal */
|
|
85
|
-
|
|
86
|
-
return this.
|
|
86
|
+
hasApiSecret() {
|
|
87
|
+
return Boolean(this.apiSecret);
|
|
87
88
|
}
|
|
88
89
|
/** @internal */
|
|
89
90
|
async request(method, path, options) {
|
|
@@ -165,28 +166,19 @@ var AgentMallPurchases = class {
|
|
|
165
166
|
}
|
|
166
167
|
});
|
|
167
168
|
}
|
|
168
|
-
/** Get a single purchase by ID using either operator auth or
|
|
169
|
+
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
169
170
|
async get(id, options) {
|
|
170
|
-
|
|
171
|
-
if (account) {
|
|
172
|
-
const challenge = await this.client.request(
|
|
173
|
-
"POST",
|
|
174
|
-
"/api/purchases/status/challenge",
|
|
175
|
-
{
|
|
176
|
-
body: { id }
|
|
177
|
-
}
|
|
178
|
-
);
|
|
179
|
-
const signature = await account.signMessage({
|
|
180
|
-
message: challenge.message
|
|
181
|
-
});
|
|
171
|
+
if (options?.buyerToken) {
|
|
182
172
|
return this.client.request("POST", "/api/purchases/status", {
|
|
183
173
|
body: {
|
|
184
174
|
id,
|
|
185
|
-
|
|
186
|
-
signature
|
|
175
|
+
buyer_token: options.buyerToken
|
|
187
176
|
}
|
|
188
177
|
});
|
|
189
178
|
}
|
|
179
|
+
if (!this.client.hasApiSecret()) {
|
|
180
|
+
throw new Error("buyerToken or apiSecret is required for this endpoint");
|
|
181
|
+
}
|
|
190
182
|
return this.client.request("GET", "/api/purchases", {
|
|
191
183
|
auth: true,
|
|
192
184
|
params: { id }
|
|
@@ -234,6 +226,33 @@ var AgentMallRefunds = class {
|
|
|
234
226
|
params: { id }
|
|
235
227
|
});
|
|
236
228
|
}
|
|
229
|
+
/** Get refund status for a purchase using either operator auth or a buyer token. */
|
|
230
|
+
async getByPurchase(purchaseId, options) {
|
|
231
|
+
if (options?.buyerToken) {
|
|
232
|
+
return this.client.request("POST", "/api/refunds/status", {
|
|
233
|
+
body: {
|
|
234
|
+
purchase_id: purchaseId,
|
|
235
|
+
buyer_token: options.buyerToken
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
if (!this.client.hasApiSecret()) {
|
|
240
|
+
throw new Error("buyerToken or apiSecret is required for this endpoint");
|
|
241
|
+
}
|
|
242
|
+
const result = await this.client.request(
|
|
243
|
+
"GET",
|
|
244
|
+
"/api/refunds",
|
|
245
|
+
{
|
|
246
|
+
auth: true,
|
|
247
|
+
params: { purchase_id: purchaseId }
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
const refund2 = result.refunds[0];
|
|
251
|
+
if (!refund2) {
|
|
252
|
+
throw new AgentMallError(404, { error: "Not found" });
|
|
253
|
+
}
|
|
254
|
+
return refund2;
|
|
255
|
+
}
|
|
237
256
|
/** List refunds. Requires apiSecret. */
|
|
238
257
|
async list(filters) {
|
|
239
258
|
const result = await this.client.request(
|
|
@@ -245,31 +264,24 @@ var AgentMallRefunds = class {
|
|
|
245
264
|
}
|
|
246
265
|
};
|
|
247
266
|
|
|
248
|
-
// src/purchase.ts
|
|
249
|
-
async function purchase(config) {
|
|
250
|
-
const { account, baseUrl, ...body } = config;
|
|
251
|
-
let mppxClient;
|
|
252
|
-
try {
|
|
253
|
-
mppxClient = await import("mppx/client");
|
|
254
|
-
} catch {
|
|
255
|
-
throw new Error("mppx is required for purchases. Install it: npm install mppx");
|
|
256
|
-
}
|
|
257
|
-
const Mppx = mppxClient.Mppx;
|
|
258
|
-
const tempo = mppxClient.tempo;
|
|
259
|
-
if (!Mppx || !tempo) {
|
|
260
|
-
throw new Error("mppx is required for purchases. Install it: npm install mppx");
|
|
261
|
-
}
|
|
262
|
-
const mppx = Mppx.create({
|
|
263
|
-
methods: [tempo({ account })]
|
|
264
|
-
});
|
|
265
|
-
const client = new AgentMall({
|
|
266
|
-
baseUrl: baseUrl ?? BASE_URL,
|
|
267
|
-
fetch: mppx.fetch.bind(mppx)
|
|
268
|
-
});
|
|
269
|
-
return client.purchases.create(body);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
267
|
// src/cli/display.ts
|
|
268
|
+
var FAILURE_MESSAGES = {
|
|
269
|
+
budget_exceeded: "Actual total exceeded your maximum budget.",
|
|
270
|
+
out_of_stock: "Item is out of stock.",
|
|
271
|
+
product_not_found: "Product is no longer available.",
|
|
272
|
+
product_unavailable: "Product cannot be purchased right now.",
|
|
273
|
+
variant_required: "A required size, color, or variant must be selected.",
|
|
274
|
+
variant_unavailable: "Selected variant is unavailable.",
|
|
275
|
+
quantity_unavailable: "Requested quantity is unavailable.",
|
|
276
|
+
quantity_limit: "Retailer quantity limit exceeded.",
|
|
277
|
+
invalid_url: "Product URL is invalid.",
|
|
278
|
+
invalid_address: "Shipping address could not be validated.",
|
|
279
|
+
shipping_unavailable: "Item cannot be shipped to this address.",
|
|
280
|
+
retailer_unavailable: "Retailer is temporarily unavailable.",
|
|
281
|
+
unsupported_retailer: "Retailer is not supported.",
|
|
282
|
+
validation_failed: "Order request failed validation.",
|
|
283
|
+
cancelled: "Order was cancelled."
|
|
284
|
+
};
|
|
273
285
|
function formatCents(cents) {
|
|
274
286
|
return `$${(cents / 100).toFixed(2)}`;
|
|
275
287
|
}
|
|
@@ -294,7 +306,7 @@ function displayProduct(product) {
|
|
|
294
306
|
}
|
|
295
307
|
console.log();
|
|
296
308
|
console.log(
|
|
297
|
-
` Suggested budget: \x1B[1m${formatCents(product.suggestedMaxBudget)}\x1B[0m (includes 15% buffer for tax
|
|
309
|
+
` Suggested budget: \x1B[1m${formatCents(product.suggestedMaxBudget)}\x1B[0m (includes 15% buffer for tax and an $8 minimum shipping buffer)`
|
|
298
310
|
);
|
|
299
311
|
console.log(
|
|
300
312
|
` Service fee: ${formatCents(SERVICE_FEE_CENTS)}`
|
|
@@ -340,6 +352,9 @@ function displayOrderResult(order) {
|
|
|
340
352
|
}
|
|
341
353
|
console.log(` ID: \x1B[1m${order.id}\x1B[0m`);
|
|
342
354
|
console.log(` Status: ${order.status}`);
|
|
355
|
+
if (order.buyerToken) {
|
|
356
|
+
console.log(" Saved local access token for status and refund checks.");
|
|
357
|
+
}
|
|
343
358
|
console.log();
|
|
344
359
|
console.log(
|
|
345
360
|
order.status === "failed" ? " Check status for failure details and refund progress:" : " Check status in 5-10 minutes:"
|
|
@@ -347,26 +362,43 @@ function displayOrderResult(order) {
|
|
|
347
362
|
console.log(` npx agentmall status ${order.id}`);
|
|
348
363
|
console.log();
|
|
349
364
|
}
|
|
350
|
-
function displayStatus(
|
|
365
|
+
function displayStatus(purchase) {
|
|
351
366
|
console.log();
|
|
352
|
-
console.log(` \x1B[1mOrder ${
|
|
353
|
-
console.log(` Status: ${
|
|
354
|
-
if (
|
|
355
|
-
for (const item of
|
|
367
|
+
console.log(` \x1B[1mOrder ${purchase.id}\x1B[0m`);
|
|
368
|
+
console.log(` Status: ${purchase.status}`);
|
|
369
|
+
if (purchase.items?.length) {
|
|
370
|
+
for (const item of purchase.items) {
|
|
356
371
|
const price = item.price ? ` \u2014 ${formatCents(item.price)}` : "";
|
|
357
372
|
console.log(` ${item.quantity}x ${item.title ?? item.productRef}${price}`);
|
|
358
373
|
}
|
|
359
374
|
}
|
|
360
|
-
if (
|
|
361
|
-
console.log(` Final total: ${formatCents(
|
|
375
|
+
if (purchase.finalTotal) {
|
|
376
|
+
console.log(` Final total: ${formatCents(purchase.finalTotal)}`);
|
|
362
377
|
}
|
|
363
|
-
if (
|
|
364
|
-
console.log(
|
|
378
|
+
if (purchase.failureReason) {
|
|
379
|
+
console.log(
|
|
380
|
+
` \x1B[31mFailure: ${FAILURE_MESSAGES[purchase.failureReason] ?? purchase.failureReason}\x1B[0m`
|
|
381
|
+
);
|
|
365
382
|
}
|
|
366
|
-
if (
|
|
367
|
-
console.log(` Shipping: ${
|
|
383
|
+
if (purchase.deliveryMethod) {
|
|
384
|
+
console.log(` Shipping: ${purchase.deliveryMethod}`);
|
|
385
|
+
}
|
|
386
|
+
console.log(` Created: ${new Date(purchase.createdAt).toLocaleString()}`);
|
|
387
|
+
console.log();
|
|
388
|
+
}
|
|
389
|
+
function displayRefund(refund2) {
|
|
390
|
+
console.log();
|
|
391
|
+
console.log(` \x1B[1mRefund ${refund2.id}\x1B[0m`);
|
|
392
|
+
console.log(` Status: ${refund2.status}`);
|
|
393
|
+
console.log(` Amount: ${formatCents(refund2.amountCents)}`);
|
|
394
|
+
console.log(` Reason: ${refund2.reason}`);
|
|
395
|
+
if (refund2.txHash) {
|
|
396
|
+
console.log(` TX: ${refund2.txHash}`);
|
|
397
|
+
}
|
|
398
|
+
console.log(` Created: ${new Date(refund2.createdAt).toLocaleString()}`);
|
|
399
|
+
if (refund2.processedAt) {
|
|
400
|
+
console.log(` Processed: ${new Date(refund2.processedAt).toLocaleString()}`);
|
|
368
401
|
}
|
|
369
|
-
console.log(` Created: ${new Date(purchase2.createdAt).toLocaleString()}`);
|
|
370
402
|
console.log();
|
|
371
403
|
}
|
|
372
404
|
|
|
@@ -442,34 +474,181 @@ async function promptAddress() {
|
|
|
442
474
|
async function promptConfirm(message) {
|
|
443
475
|
return confirm({ message });
|
|
444
476
|
}
|
|
445
|
-
|
|
477
|
+
function formatCents2(cents) {
|
|
478
|
+
return `$${(cents / 100).toFixed(2)}`;
|
|
479
|
+
}
|
|
480
|
+
function parseBudgetInput(value) {
|
|
481
|
+
const trimmed = value.trim();
|
|
482
|
+
if (!trimmed) return null;
|
|
483
|
+
if (/^\d+\.\d{1,2}$/.test(trimmed)) {
|
|
484
|
+
return Math.round(Number(trimmed) * 100);
|
|
485
|
+
}
|
|
486
|
+
if (/^\d+$/.test(trimmed)) {
|
|
487
|
+
return parseInt(trimmed, 10);
|
|
488
|
+
}
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
async function promptBudget(suggested, minimumCents) {
|
|
446
492
|
const value = await input({
|
|
447
|
-
message: `Max budget in cents (suggested
|
|
493
|
+
message: `Max budget in cents (e.g. ${suggested} = ${formatCents2(suggested)})`,
|
|
448
494
|
default: String(suggested),
|
|
449
495
|
validate: (v) => {
|
|
450
|
-
const n =
|
|
451
|
-
if (
|
|
496
|
+
const n = parseBudgetInput(v);
|
|
497
|
+
if (n === null || n <= 0) {
|
|
498
|
+
return "Enter cents like 1540 or dollars like 15.40";
|
|
499
|
+
}
|
|
500
|
+
if (n < minimumCents) {
|
|
501
|
+
return `Max budget must be at least the current product price ${formatCents2(minimumCents)}`;
|
|
502
|
+
}
|
|
452
503
|
return true;
|
|
453
504
|
}
|
|
454
505
|
});
|
|
455
|
-
|
|
506
|
+
const parsed = parseBudgetInput(value);
|
|
507
|
+
if (parsed === null) {
|
|
508
|
+
throw new Error("Invalid budget input");
|
|
509
|
+
}
|
|
510
|
+
return parsed;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/cli/tokenStore.ts
|
|
514
|
+
import { chmod, mkdir, readFile, writeFile } from "fs/promises";
|
|
515
|
+
import { homedir } from "os";
|
|
516
|
+
import { dirname, join } from "path";
|
|
517
|
+
var STORE_PATH = join(homedir(), ".agentmall", "tokens.json");
|
|
518
|
+
function emptyStore() {
|
|
519
|
+
return {
|
|
520
|
+
version: 1,
|
|
521
|
+
purchases: {}
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
async function readStore() {
|
|
525
|
+
try {
|
|
526
|
+
const raw = await readFile(STORE_PATH, "utf8");
|
|
527
|
+
const parsed = JSON.parse(raw);
|
|
528
|
+
return {
|
|
529
|
+
version: 1,
|
|
530
|
+
purchases: parsed.purchases ?? {}
|
|
531
|
+
};
|
|
532
|
+
} catch {
|
|
533
|
+
return emptyStore();
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
async function writeStore(store) {
|
|
537
|
+
await mkdir(dirname(STORE_PATH), { recursive: true });
|
|
538
|
+
await writeFile(STORE_PATH, JSON.stringify(store, null, 2), "utf8");
|
|
539
|
+
try {
|
|
540
|
+
await chmod(STORE_PATH, 384);
|
|
541
|
+
} catch {
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
async function saveBuyerToken(purchaseId, buyerToken) {
|
|
545
|
+
const store = await readStore();
|
|
546
|
+
store.purchases[purchaseId] = {
|
|
547
|
+
buyerToken,
|
|
548
|
+
savedAt: Date.now()
|
|
549
|
+
};
|
|
550
|
+
await writeStore(store);
|
|
551
|
+
}
|
|
552
|
+
async function getBuyerToken(purchaseId) {
|
|
553
|
+
const store = await readStore();
|
|
554
|
+
return store.purchases[purchaseId]?.buyerToken ?? null;
|
|
456
555
|
}
|
|
457
556
|
|
|
458
557
|
// src/cli/index.ts
|
|
459
558
|
var EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
460
|
-
async function
|
|
559
|
+
async function runCommandCapture(command2, args2) {
|
|
560
|
+
return await new Promise((resolve, reject) => {
|
|
561
|
+
const child = spawn(command2, args2, {
|
|
562
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
563
|
+
shell: process.platform === "win32"
|
|
564
|
+
});
|
|
565
|
+
let stdout = "";
|
|
566
|
+
let stderr = "";
|
|
567
|
+
child.stdout?.on("data", (chunk) => {
|
|
568
|
+
stdout += chunk.toString();
|
|
569
|
+
});
|
|
570
|
+
child.stderr?.on("data", (chunk) => {
|
|
571
|
+
stderr += chunk.toString();
|
|
572
|
+
});
|
|
573
|
+
child.on("error", reject);
|
|
574
|
+
child.on(
|
|
575
|
+
"exit",
|
|
576
|
+
(code) => resolve({
|
|
577
|
+
code: code ?? 1,
|
|
578
|
+
stdout,
|
|
579
|
+
stderr
|
|
580
|
+
})
|
|
581
|
+
);
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
async function runInteractiveCommand(command2, args2) {
|
|
585
|
+
return await new Promise((resolve, reject) => {
|
|
586
|
+
const child = spawn(command2, args2, {
|
|
587
|
+
stdio: "inherit",
|
|
588
|
+
shell: process.platform === "win32"
|
|
589
|
+
});
|
|
590
|
+
child.on("error", reject);
|
|
591
|
+
child.on("exit", (code) => resolve(code ?? 1));
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
async function readTempoWhoami() {
|
|
461
595
|
try {
|
|
462
|
-
const
|
|
463
|
-
|
|
596
|
+
const result = await runCommandCapture("tempo", ["wallet", "-j", "whoami"]);
|
|
597
|
+
if (result.code !== 0) return null;
|
|
598
|
+
return JSON.parse(result.stdout);
|
|
599
|
+
} catch {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
async function ensureTempoInstalled() {
|
|
604
|
+
try {
|
|
605
|
+
const result = await runCommandCapture("tempo", ["--version"]);
|
|
606
|
+
if (result.code === 0) return;
|
|
464
607
|
} catch {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
608
|
+
}
|
|
609
|
+
console.error("\x1B[31mTempo CLI is required for purchases.\x1B[0m");
|
|
610
|
+
console.error("");
|
|
611
|
+
console.error("Install it first:");
|
|
612
|
+
console.error(" curl -fsSL https://tempo.xyz/install | bash");
|
|
613
|
+
process.exit(1);
|
|
614
|
+
}
|
|
615
|
+
async function ensureTempoReady() {
|
|
616
|
+
await ensureTempoInstalled();
|
|
617
|
+
const whoami = await readTempoWhoami();
|
|
618
|
+
if (whoami?.ready) return whoami;
|
|
619
|
+
console.log(" Tempo wallet login required...");
|
|
620
|
+
const loginCode = await runInteractiveCommand("tempo", ["wallet", "login"]);
|
|
621
|
+
if (loginCode !== 0) {
|
|
622
|
+
throw new Error("Tempo wallet login failed");
|
|
623
|
+
}
|
|
624
|
+
const afterLogin = await readTempoWhoami();
|
|
625
|
+
if (afterLogin?.ready) return afterLogin;
|
|
626
|
+
throw new Error("Tempo wallet is not ready after login");
|
|
627
|
+
}
|
|
628
|
+
function formatUsdAmount(cents) {
|
|
629
|
+
return (cents / 100).toFixed(2);
|
|
630
|
+
}
|
|
631
|
+
async function createPurchaseWithTempo(body) {
|
|
632
|
+
const totalChargeCents = body.max_budget + SERVICE_FEE_CENTS;
|
|
633
|
+
const result = await runCommandCapture("tempo", [
|
|
634
|
+
"request",
|
|
635
|
+
"-s",
|
|
636
|
+
"--max-spend",
|
|
637
|
+
formatUsdAmount(totalChargeCents),
|
|
638
|
+
"-X",
|
|
639
|
+
"POST",
|
|
640
|
+
"--json",
|
|
641
|
+
JSON.stringify(body),
|
|
642
|
+
`${BASE_URL}/api/purchases`
|
|
643
|
+
]);
|
|
644
|
+
if (result.code !== 0) {
|
|
645
|
+
const message = result.stderr.trim() || result.stdout.trim() || "Tempo request failed";
|
|
646
|
+
throw new Error(message);
|
|
647
|
+
}
|
|
648
|
+
try {
|
|
649
|
+
return JSON.parse(result.stdout);
|
|
650
|
+
} catch {
|
|
651
|
+
throw new Error(`Unexpected response from Tempo request: ${result.stdout.trim() || "(empty)"}`);
|
|
473
652
|
}
|
|
474
653
|
}
|
|
475
654
|
async function buy(urlArg) {
|
|
@@ -477,15 +656,14 @@ async function buy(urlArg) {
|
|
|
477
656
|
console.log();
|
|
478
657
|
console.log(" \x1B[1magentmall\x1B[0m \u2014 Buy anything with a URL");
|
|
479
658
|
console.log();
|
|
480
|
-
const account = await resolveAccount();
|
|
481
659
|
const url = urlArg ?? await promptProductUrl();
|
|
482
660
|
const client = new AgentMall();
|
|
483
|
-
console.log("
|
|
661
|
+
console.log(" Looking up product...");
|
|
484
662
|
const product = await client.products.lookup(url);
|
|
485
663
|
displayProduct(product);
|
|
486
664
|
const variantSelections = product.variants?.length ? await promptVariants(product.variants) : void 0;
|
|
487
665
|
const address = await promptAddress();
|
|
488
|
-
const maxBudget = await promptBudget(product.suggestedMaxBudget);
|
|
666
|
+
const maxBudget = await promptBudget(product.suggestedMaxBudget, product.price);
|
|
489
667
|
const { input: input2 } = await import("@inquirer/prompts");
|
|
490
668
|
const buyerEmail = await input2({
|
|
491
669
|
message: "Email for order updates",
|
|
@@ -509,11 +687,16 @@ async function buy(urlArg) {
|
|
|
509
687
|
console.log(" Cancelled.");
|
|
510
688
|
return;
|
|
511
689
|
}
|
|
690
|
+
const wallet = await ensureTempoReady();
|
|
691
|
+
if (wallet.wallet) {
|
|
692
|
+
const balance = wallet.balance?.available ? `, balance ${wallet.balance.available} ${wallet.balance?.symbol ?? "USDC"}` : "";
|
|
693
|
+
console.log(` Paying with Tempo wallet ${wallet.wallet}${balance}`);
|
|
694
|
+
}
|
|
512
695
|
console.log(" Placing order...");
|
|
513
|
-
const order = await
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}
|
|
696
|
+
const order = await createPurchaseWithTempo(body);
|
|
697
|
+
if (order.buyerToken) {
|
|
698
|
+
await saveBuyerToken(order.id, order.buyerToken);
|
|
699
|
+
}
|
|
517
700
|
displayOrderResult(order);
|
|
518
701
|
} catch (error) {
|
|
519
702
|
console.log();
|
|
@@ -542,10 +725,48 @@ async function buy(urlArg) {
|
|
|
542
725
|
}
|
|
543
726
|
async function status(purchaseId) {
|
|
544
727
|
const apiSecret = process.env.AGENTMALL_API_SECRET;
|
|
545
|
-
const
|
|
546
|
-
const
|
|
728
|
+
const buyerToken = apiSecret ? null : await getBuyerToken(purchaseId);
|
|
729
|
+
const client = apiSecret ? new AgentMall({ apiSecret }) : new AgentMall();
|
|
730
|
+
if (!apiSecret && !buyerToken) {
|
|
731
|
+
throw new Error("No saved buyer token found for this order on this machine.");
|
|
732
|
+
}
|
|
733
|
+
const result = await client.purchases.get(
|
|
734
|
+
purchaseId,
|
|
735
|
+
buyerToken ? { buyerToken } : void 0
|
|
736
|
+
);
|
|
547
737
|
displayStatus(result);
|
|
548
738
|
}
|
|
739
|
+
async function refund(purchaseId) {
|
|
740
|
+
const apiSecret = process.env.AGENTMALL_API_SECRET;
|
|
741
|
+
const buyerToken = apiSecret ? null : await getBuyerToken(purchaseId);
|
|
742
|
+
const client = apiSecret ? new AgentMall({ apiSecret }) : new AgentMall();
|
|
743
|
+
if (!apiSecret && !buyerToken) {
|
|
744
|
+
throw new Error("No saved buyer token found for this order on this machine.");
|
|
745
|
+
}
|
|
746
|
+
const result = await client.refunds.getByPurchase(
|
|
747
|
+
purchaseId,
|
|
748
|
+
buyerToken ? { buyerToken } : void 0
|
|
749
|
+
);
|
|
750
|
+
displayRefund(result);
|
|
751
|
+
}
|
|
752
|
+
async function onboard() {
|
|
753
|
+
console.log();
|
|
754
|
+
console.log(" \x1B[1magentmall onboarding\x1B[0m");
|
|
755
|
+
console.log();
|
|
756
|
+
const wallet = await ensureTempoReady();
|
|
757
|
+
console.log();
|
|
758
|
+
if (wallet.wallet) {
|
|
759
|
+
console.log(` Wallet ready: ${wallet.wallet}`);
|
|
760
|
+
}
|
|
761
|
+
if (wallet.balance?.available) {
|
|
762
|
+
console.log(` Available balance: ${wallet.balance.available} ${wallet.balance?.symbol ?? "USDC"}`);
|
|
763
|
+
}
|
|
764
|
+
console.log(" Next steps:");
|
|
765
|
+
console.log(" 1. Run \x1B[1mtempo wallet whoami\x1B[0m to review your wallet");
|
|
766
|
+
console.log(" 2. Add funds to your Tempo wallet if needed");
|
|
767
|
+
console.log(" 3. Retry your purchase with \x1B[1mnpx agentmall buy <url>\x1B[0m");
|
|
768
|
+
console.log();
|
|
769
|
+
}
|
|
549
770
|
|
|
550
771
|
// src/cli.ts
|
|
551
772
|
var args = process.argv.slice(2);
|
|
@@ -563,6 +784,17 @@ async function main() {
|
|
|
563
784
|
}
|
|
564
785
|
await status(args[1]);
|
|
565
786
|
break;
|
|
787
|
+
case "refund":
|
|
788
|
+
if (!args[1]) {
|
|
789
|
+
console.error("Usage: agentmall refund <purchase_id>");
|
|
790
|
+
process.exit(1);
|
|
791
|
+
}
|
|
792
|
+
await refund(args[1]);
|
|
793
|
+
break;
|
|
794
|
+
case "onboard":
|
|
795
|
+
case "setup":
|
|
796
|
+
await onboard();
|
|
797
|
+
break;
|
|
566
798
|
case "help":
|
|
567
799
|
case "--help":
|
|
568
800
|
case "-h":
|
|
@@ -588,14 +820,12 @@ function printHelp() {
|
|
|
588
820
|
\x1B[1magentmall\x1B[0m \u2014 Buy anything with a URL
|
|
589
821
|
|
|
590
822
|
Usage:
|
|
823
|
+
agentmall onboard Log in to Tempo and show wallet funding steps
|
|
591
824
|
agentmall [url] Buy a product (interactive)
|
|
592
825
|
agentmall buy <url> Buy a product
|
|
593
|
-
agentmall status <id> Check order status
|
|
826
|
+
agentmall status <id> Check order status using the saved buyer token
|
|
827
|
+
agentmall refund <id> Check refund status using the saved buyer token
|
|
594
828
|
agentmall help Show this help
|
|
595
|
-
|
|
596
|
-
Environment:
|
|
597
|
-
MPPX_PRIVATE_KEY Wallet private key for payments and buyer status checks
|
|
598
|
-
AGENTMALL_API_SECRET Operator secret for internal admin read endpoints
|
|
599
829
|
`);
|
|
600
830
|
}
|
|
601
831
|
main();
|
package/dist/index.cjs
CHANGED
|
@@ -108,7 +108,6 @@ function createIdempotencyKey() {
|
|
|
108
108
|
var AgentMall = class {
|
|
109
109
|
baseUrl;
|
|
110
110
|
apiSecret;
|
|
111
|
-
account;
|
|
112
111
|
_fetch;
|
|
113
112
|
products;
|
|
114
113
|
purchases;
|
|
@@ -117,7 +116,6 @@ var AgentMall = class {
|
|
|
117
116
|
constructor(config = {}) {
|
|
118
117
|
this.baseUrl = (config.baseUrl ?? BASE_URL).replace(/\/$/, "");
|
|
119
118
|
this.apiSecret = config.apiSecret;
|
|
120
|
-
this.account = config.account;
|
|
121
119
|
this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
122
120
|
this.products = new AgentMallProducts(this);
|
|
123
121
|
this.purchases = new AgentMallPurchases(this);
|
|
@@ -125,8 +123,8 @@ var AgentMall = class {
|
|
|
125
123
|
this.refunds = new AgentMallRefunds(this);
|
|
126
124
|
}
|
|
127
125
|
/** @internal */
|
|
128
|
-
|
|
129
|
-
return this.
|
|
126
|
+
hasApiSecret() {
|
|
127
|
+
return Boolean(this.apiSecret);
|
|
130
128
|
}
|
|
131
129
|
/** @internal */
|
|
132
130
|
async request(method, path, options) {
|
|
@@ -208,28 +206,19 @@ var AgentMallPurchases = class {
|
|
|
208
206
|
}
|
|
209
207
|
});
|
|
210
208
|
}
|
|
211
|
-
/** Get a single purchase by ID using either operator auth or
|
|
209
|
+
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
212
210
|
async get(id, options) {
|
|
213
|
-
|
|
214
|
-
if (account) {
|
|
215
|
-
const challenge = await this.client.request(
|
|
216
|
-
"POST",
|
|
217
|
-
"/api/purchases/status/challenge",
|
|
218
|
-
{
|
|
219
|
-
body: { id }
|
|
220
|
-
}
|
|
221
|
-
);
|
|
222
|
-
const signature = await account.signMessage({
|
|
223
|
-
message: challenge.message
|
|
224
|
-
});
|
|
211
|
+
if (options?.buyerToken) {
|
|
225
212
|
return this.client.request("POST", "/api/purchases/status", {
|
|
226
213
|
body: {
|
|
227
214
|
id,
|
|
228
|
-
|
|
229
|
-
signature
|
|
215
|
+
buyer_token: options.buyerToken
|
|
230
216
|
}
|
|
231
217
|
});
|
|
232
218
|
}
|
|
219
|
+
if (!this.client.hasApiSecret()) {
|
|
220
|
+
throw new Error("buyerToken or apiSecret is required for this endpoint");
|
|
221
|
+
}
|
|
233
222
|
return this.client.request("GET", "/api/purchases", {
|
|
234
223
|
auth: true,
|
|
235
224
|
params: { id }
|
|
@@ -277,6 +266,33 @@ var AgentMallRefunds = class {
|
|
|
277
266
|
params: { id }
|
|
278
267
|
});
|
|
279
268
|
}
|
|
269
|
+
/** Get refund status for a purchase using either operator auth or a buyer token. */
|
|
270
|
+
async getByPurchase(purchaseId, options) {
|
|
271
|
+
if (options?.buyerToken) {
|
|
272
|
+
return this.client.request("POST", "/api/refunds/status", {
|
|
273
|
+
body: {
|
|
274
|
+
purchase_id: purchaseId,
|
|
275
|
+
buyer_token: options.buyerToken
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
if (!this.client.hasApiSecret()) {
|
|
280
|
+
throw new Error("buyerToken or apiSecret is required for this endpoint");
|
|
281
|
+
}
|
|
282
|
+
const result = await this.client.request(
|
|
283
|
+
"GET",
|
|
284
|
+
"/api/refunds",
|
|
285
|
+
{
|
|
286
|
+
auth: true,
|
|
287
|
+
params: { purchase_id: purchaseId }
|
|
288
|
+
}
|
|
289
|
+
);
|
|
290
|
+
const refund = result.refunds[0];
|
|
291
|
+
if (!refund) {
|
|
292
|
+
throw new AgentMallError(404, { error: "Not found" });
|
|
293
|
+
}
|
|
294
|
+
return refund;
|
|
295
|
+
}
|
|
280
296
|
/** List refunds. Requires apiSecret. */
|
|
281
297
|
async list(filters) {
|
|
282
298
|
const result = await this.client.request(
|
package/dist/index.d.cts
CHANGED
|
@@ -3,8 +3,6 @@ type AgentMallConfig = {
|
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
/** Operator API secret for admin read endpoints (Bearer auth). */
|
|
5
5
|
apiSecret?: string;
|
|
6
|
-
/** Wallet account used for buyer-authenticated purchase status reads. */
|
|
7
|
-
account?: WalletAccount;
|
|
8
6
|
/** Custom fetch implementation (e.g. mppx-wrapped fetch for automatic 402 handling). */
|
|
9
7
|
fetch?: typeof globalThis.fetch;
|
|
10
8
|
};
|
|
@@ -33,7 +31,7 @@ type ProductLookup = {
|
|
|
33
31
|
availability: string;
|
|
34
32
|
imageUrl?: string;
|
|
35
33
|
retailer: string;
|
|
36
|
-
/** Suggested max_budget in cents (list price +
|
|
34
|
+
/** Suggested max_budget in cents (list price + a buffer, with a minimum $8 buffer). */
|
|
37
35
|
suggestedMaxBudget: number;
|
|
38
36
|
variants?: ProductVariant[];
|
|
39
37
|
/** True if served from cache. Price may not reflect current listing. */
|
|
@@ -72,12 +70,14 @@ type CreatePurchaseResponse = {
|
|
|
72
70
|
id: string;
|
|
73
71
|
status: PurchaseLifecycleStatus;
|
|
74
72
|
deduplicated?: boolean;
|
|
73
|
+
buyerToken?: string;
|
|
75
74
|
};
|
|
76
75
|
type PurchaseStatusChallenge = {
|
|
77
76
|
challenge: string;
|
|
78
77
|
message: string;
|
|
79
78
|
expiresAt: number;
|
|
80
79
|
};
|
|
80
|
+
type RefundStatusChallenge = PurchaseStatusChallenge;
|
|
81
81
|
type PurchaseItem = {
|
|
82
82
|
productRef: string;
|
|
83
83
|
quantity: number;
|
|
@@ -144,7 +144,6 @@ type RefundFilters = {
|
|
|
144
144
|
declare class AgentMall {
|
|
145
145
|
private baseUrl;
|
|
146
146
|
private apiSecret?;
|
|
147
|
-
private account?;
|
|
148
147
|
private _fetch;
|
|
149
148
|
products: AgentMallProducts;
|
|
150
149
|
purchases: AgentMallPurchases;
|
|
@@ -152,7 +151,7 @@ declare class AgentMall {
|
|
|
152
151
|
refunds: AgentMallRefunds;
|
|
153
152
|
constructor(config?: AgentMallConfig);
|
|
154
153
|
/** @internal */
|
|
155
|
-
|
|
154
|
+
hasApiSecret(): boolean;
|
|
156
155
|
/** @internal */
|
|
157
156
|
request<T>(method: string, path: string, options?: {
|
|
158
157
|
body?: unknown;
|
|
@@ -175,9 +174,9 @@ declare class AgentMallPurchases {
|
|
|
175
174
|
* Use mppx-wrapped fetch to handle payment automatically, or catch PaymentRequiredError.
|
|
176
175
|
*/
|
|
177
176
|
create(body: CreatePurchaseRequest): Promise<CreatePurchaseResponse>;
|
|
178
|
-
/** Get a single purchase by ID using either operator auth or
|
|
177
|
+
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
179
178
|
get(id: string, options?: {
|
|
180
|
-
|
|
179
|
+
buyerToken?: string;
|
|
181
180
|
}): Promise<Purchase>;
|
|
182
181
|
/** List purchases. Requires apiSecret. */
|
|
183
182
|
list(filters?: PurchaseFilters): Promise<Purchase[]>;
|
|
@@ -195,6 +194,10 @@ declare class AgentMallRefunds {
|
|
|
195
194
|
constructor(client: AgentMall);
|
|
196
195
|
/** Get a single refund by public ID. Requires apiSecret. */
|
|
197
196
|
get(id: string): Promise<Refund>;
|
|
197
|
+
/** Get refund status for a purchase using either operator auth or a buyer token. */
|
|
198
|
+
getByPurchase(purchaseId: string, options?: {
|
|
199
|
+
buyerToken?: string;
|
|
200
|
+
}): Promise<Refund>;
|
|
198
201
|
/** List refunds. Requires apiSecret. */
|
|
199
202
|
list(filters?: RefundFilters): Promise<Refund[]>;
|
|
200
203
|
}
|
|
@@ -248,4 +251,4 @@ declare const BASE_URL = "https://api.agentmall.sh";
|
|
|
248
251
|
declare const SERVICE_FEE_CENTS = 150;
|
|
249
252
|
declare const SUPPORTED_RETAILERS: readonly ["amazon.com", "walmart.com", "target.com", "bestbuy.com", "homedepot.com", "ebay.com", "lowes.com", "wayfair.com", "acehardware.com", "1800flowers.com", "pokemoncenter.com"];
|
|
250
253
|
|
|
251
|
-
export { AgentMall, type AgentMallConfig, AgentMallError, BASE_URL, ConflictError, type CreatePurchaseRequest, type CreatePurchaseResponse, type DeliveryAddress, type Payment, type PaymentFilters, PaymentRequiredError, type ProductLookup, type ProductVariant, type Purchase, type PurchaseFilters, type PurchaseItem, type PurchaseItemInput, type PurchaseLifecycleStatus, type PurchaseStatusChallenge, RateLimitError, type Refund, type RefundFilters, SERVICE_FEE_CENTS, SUPPORTED_RETAILERS, ValidationError, type VariantSelection, type WalletAccount, purchase };
|
|
254
|
+
export { AgentMall, type AgentMallConfig, AgentMallError, BASE_URL, ConflictError, type CreatePurchaseRequest, type CreatePurchaseResponse, type DeliveryAddress, type Payment, type PaymentFilters, PaymentRequiredError, type ProductLookup, type ProductVariant, type Purchase, type PurchaseFilters, type PurchaseItem, type PurchaseItemInput, type PurchaseLifecycleStatus, type PurchaseStatusChallenge, RateLimitError, type Refund, type RefundFilters, type RefundStatusChallenge, SERVICE_FEE_CENTS, SUPPORTED_RETAILERS, ValidationError, type VariantSelection, type WalletAccount, purchase };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,6 @@ type AgentMallConfig = {
|
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
/** Operator API secret for admin read endpoints (Bearer auth). */
|
|
5
5
|
apiSecret?: string;
|
|
6
|
-
/** Wallet account used for buyer-authenticated purchase status reads. */
|
|
7
|
-
account?: WalletAccount;
|
|
8
6
|
/** Custom fetch implementation (e.g. mppx-wrapped fetch for automatic 402 handling). */
|
|
9
7
|
fetch?: typeof globalThis.fetch;
|
|
10
8
|
};
|
|
@@ -33,7 +31,7 @@ type ProductLookup = {
|
|
|
33
31
|
availability: string;
|
|
34
32
|
imageUrl?: string;
|
|
35
33
|
retailer: string;
|
|
36
|
-
/** Suggested max_budget in cents (list price +
|
|
34
|
+
/** Suggested max_budget in cents (list price + a buffer, with a minimum $8 buffer). */
|
|
37
35
|
suggestedMaxBudget: number;
|
|
38
36
|
variants?: ProductVariant[];
|
|
39
37
|
/** True if served from cache. Price may not reflect current listing. */
|
|
@@ -72,12 +70,14 @@ type CreatePurchaseResponse = {
|
|
|
72
70
|
id: string;
|
|
73
71
|
status: PurchaseLifecycleStatus;
|
|
74
72
|
deduplicated?: boolean;
|
|
73
|
+
buyerToken?: string;
|
|
75
74
|
};
|
|
76
75
|
type PurchaseStatusChallenge = {
|
|
77
76
|
challenge: string;
|
|
78
77
|
message: string;
|
|
79
78
|
expiresAt: number;
|
|
80
79
|
};
|
|
80
|
+
type RefundStatusChallenge = PurchaseStatusChallenge;
|
|
81
81
|
type PurchaseItem = {
|
|
82
82
|
productRef: string;
|
|
83
83
|
quantity: number;
|
|
@@ -144,7 +144,6 @@ type RefundFilters = {
|
|
|
144
144
|
declare class AgentMall {
|
|
145
145
|
private baseUrl;
|
|
146
146
|
private apiSecret?;
|
|
147
|
-
private account?;
|
|
148
147
|
private _fetch;
|
|
149
148
|
products: AgentMallProducts;
|
|
150
149
|
purchases: AgentMallPurchases;
|
|
@@ -152,7 +151,7 @@ declare class AgentMall {
|
|
|
152
151
|
refunds: AgentMallRefunds;
|
|
153
152
|
constructor(config?: AgentMallConfig);
|
|
154
153
|
/** @internal */
|
|
155
|
-
|
|
154
|
+
hasApiSecret(): boolean;
|
|
156
155
|
/** @internal */
|
|
157
156
|
request<T>(method: string, path: string, options?: {
|
|
158
157
|
body?: unknown;
|
|
@@ -175,9 +174,9 @@ declare class AgentMallPurchases {
|
|
|
175
174
|
* Use mppx-wrapped fetch to handle payment automatically, or catch PaymentRequiredError.
|
|
176
175
|
*/
|
|
177
176
|
create(body: CreatePurchaseRequest): Promise<CreatePurchaseResponse>;
|
|
178
|
-
/** Get a single purchase by ID using either operator auth or
|
|
177
|
+
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
179
178
|
get(id: string, options?: {
|
|
180
|
-
|
|
179
|
+
buyerToken?: string;
|
|
181
180
|
}): Promise<Purchase>;
|
|
182
181
|
/** List purchases. Requires apiSecret. */
|
|
183
182
|
list(filters?: PurchaseFilters): Promise<Purchase[]>;
|
|
@@ -195,6 +194,10 @@ declare class AgentMallRefunds {
|
|
|
195
194
|
constructor(client: AgentMall);
|
|
196
195
|
/** Get a single refund by public ID. Requires apiSecret. */
|
|
197
196
|
get(id: string): Promise<Refund>;
|
|
197
|
+
/** Get refund status for a purchase using either operator auth or a buyer token. */
|
|
198
|
+
getByPurchase(purchaseId: string, options?: {
|
|
199
|
+
buyerToken?: string;
|
|
200
|
+
}): Promise<Refund>;
|
|
198
201
|
/** List refunds. Requires apiSecret. */
|
|
199
202
|
list(filters?: RefundFilters): Promise<Refund[]>;
|
|
200
203
|
}
|
|
@@ -248,4 +251,4 @@ declare const BASE_URL = "https://api.agentmall.sh";
|
|
|
248
251
|
declare const SERVICE_FEE_CENTS = 150;
|
|
249
252
|
declare const SUPPORTED_RETAILERS: readonly ["amazon.com", "walmart.com", "target.com", "bestbuy.com", "homedepot.com", "ebay.com", "lowes.com", "wayfair.com", "acehardware.com", "1800flowers.com", "pokemoncenter.com"];
|
|
250
253
|
|
|
251
|
-
export { AgentMall, type AgentMallConfig, AgentMallError, BASE_URL, ConflictError, type CreatePurchaseRequest, type CreatePurchaseResponse, type DeliveryAddress, type Payment, type PaymentFilters, PaymentRequiredError, type ProductLookup, type ProductVariant, type Purchase, type PurchaseFilters, type PurchaseItem, type PurchaseItemInput, type PurchaseLifecycleStatus, type PurchaseStatusChallenge, RateLimitError, type Refund, type RefundFilters, SERVICE_FEE_CENTS, SUPPORTED_RETAILERS, ValidationError, type VariantSelection, type WalletAccount, purchase };
|
|
254
|
+
export { AgentMall, type AgentMallConfig, AgentMallError, BASE_URL, ConflictError, type CreatePurchaseRequest, type CreatePurchaseResponse, type DeliveryAddress, type Payment, type PaymentFilters, PaymentRequiredError, type ProductLookup, type ProductVariant, type Purchase, type PurchaseFilters, type PurchaseItem, type PurchaseItemInput, type PurchaseLifecycleStatus, type PurchaseStatusChallenge, RateLimitError, type Refund, type RefundFilters, type RefundStatusChallenge, SERVICE_FEE_CENTS, SUPPORTED_RETAILERS, ValidationError, type VariantSelection, type WalletAccount, purchase };
|
package/dist/index.js
CHANGED
|
@@ -63,7 +63,6 @@ function createIdempotencyKey() {
|
|
|
63
63
|
var AgentMall = class {
|
|
64
64
|
baseUrl;
|
|
65
65
|
apiSecret;
|
|
66
|
-
account;
|
|
67
66
|
_fetch;
|
|
68
67
|
products;
|
|
69
68
|
purchases;
|
|
@@ -72,7 +71,6 @@ var AgentMall = class {
|
|
|
72
71
|
constructor(config = {}) {
|
|
73
72
|
this.baseUrl = (config.baseUrl ?? BASE_URL).replace(/\/$/, "");
|
|
74
73
|
this.apiSecret = config.apiSecret;
|
|
75
|
-
this.account = config.account;
|
|
76
74
|
this._fetch = config.fetch ?? globalThis.fetch.bind(globalThis);
|
|
77
75
|
this.products = new AgentMallProducts(this);
|
|
78
76
|
this.purchases = new AgentMallPurchases(this);
|
|
@@ -80,8 +78,8 @@ var AgentMall = class {
|
|
|
80
78
|
this.refunds = new AgentMallRefunds(this);
|
|
81
79
|
}
|
|
82
80
|
/** @internal */
|
|
83
|
-
|
|
84
|
-
return this.
|
|
81
|
+
hasApiSecret() {
|
|
82
|
+
return Boolean(this.apiSecret);
|
|
85
83
|
}
|
|
86
84
|
/** @internal */
|
|
87
85
|
async request(method, path, options) {
|
|
@@ -163,28 +161,19 @@ var AgentMallPurchases = class {
|
|
|
163
161
|
}
|
|
164
162
|
});
|
|
165
163
|
}
|
|
166
|
-
/** Get a single purchase by ID using either operator auth or
|
|
164
|
+
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
167
165
|
async get(id, options) {
|
|
168
|
-
|
|
169
|
-
if (account) {
|
|
170
|
-
const challenge = await this.client.request(
|
|
171
|
-
"POST",
|
|
172
|
-
"/api/purchases/status/challenge",
|
|
173
|
-
{
|
|
174
|
-
body: { id }
|
|
175
|
-
}
|
|
176
|
-
);
|
|
177
|
-
const signature = await account.signMessage({
|
|
178
|
-
message: challenge.message
|
|
179
|
-
});
|
|
166
|
+
if (options?.buyerToken) {
|
|
180
167
|
return this.client.request("POST", "/api/purchases/status", {
|
|
181
168
|
body: {
|
|
182
169
|
id,
|
|
183
|
-
|
|
184
|
-
signature
|
|
170
|
+
buyer_token: options.buyerToken
|
|
185
171
|
}
|
|
186
172
|
});
|
|
187
173
|
}
|
|
174
|
+
if (!this.client.hasApiSecret()) {
|
|
175
|
+
throw new Error("buyerToken or apiSecret is required for this endpoint");
|
|
176
|
+
}
|
|
188
177
|
return this.client.request("GET", "/api/purchases", {
|
|
189
178
|
auth: true,
|
|
190
179
|
params: { id }
|
|
@@ -232,6 +221,33 @@ var AgentMallRefunds = class {
|
|
|
232
221
|
params: { id }
|
|
233
222
|
});
|
|
234
223
|
}
|
|
224
|
+
/** Get refund status for a purchase using either operator auth or a buyer token. */
|
|
225
|
+
async getByPurchase(purchaseId, options) {
|
|
226
|
+
if (options?.buyerToken) {
|
|
227
|
+
return this.client.request("POST", "/api/refunds/status", {
|
|
228
|
+
body: {
|
|
229
|
+
purchase_id: purchaseId,
|
|
230
|
+
buyer_token: options.buyerToken
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (!this.client.hasApiSecret()) {
|
|
235
|
+
throw new Error("buyerToken or apiSecret is required for this endpoint");
|
|
236
|
+
}
|
|
237
|
+
const result = await this.client.request(
|
|
238
|
+
"GET",
|
|
239
|
+
"/api/refunds",
|
|
240
|
+
{
|
|
241
|
+
auth: true,
|
|
242
|
+
params: { purchase_id: purchaseId }
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
const refund = result.refunds[0];
|
|
246
|
+
if (!refund) {
|
|
247
|
+
throw new AgentMallError(404, { error: "Not found" });
|
|
248
|
+
}
|
|
249
|
+
return refund;
|
|
250
|
+
}
|
|
235
251
|
/** List refunds. Requires apiSecret. */
|
|
236
252
|
async list(filters) {
|
|
237
253
|
const result = await this.client.request(
|