agentmall 0.1.21 → 0.1.22
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 +403 -51
- package/dist/index.cjs +27 -22
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +27 -22
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
4
|
import { spawn } from "child_process";
|
|
5
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
5
6
|
|
|
6
7
|
// src/constants.ts
|
|
7
8
|
var BASE_URL = "https://api.agentmall.sh";
|
|
@@ -142,6 +143,25 @@ var AgentMall = class {
|
|
|
142
143
|
return await response.json();
|
|
143
144
|
}
|
|
144
145
|
};
|
|
146
|
+
async function createStoreAccountHeaders(client, account) {
|
|
147
|
+
const challenge = await client.request(
|
|
148
|
+
"POST",
|
|
149
|
+
"/api/managed-accounts/challenge",
|
|
150
|
+
{
|
|
151
|
+
body: {
|
|
152
|
+
address: account.address
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
const signature = await account.signMessage({
|
|
157
|
+
message: challenge.message
|
|
158
|
+
});
|
|
159
|
+
return {
|
|
160
|
+
"X-AgentMall-Wallet-Address": account.address,
|
|
161
|
+
"X-AgentMall-Auth-Challenge": challenge.challenge,
|
|
162
|
+
"X-AgentMall-Auth-Signature": signature
|
|
163
|
+
};
|
|
164
|
+
}
|
|
145
165
|
var AgentMallProducts = class {
|
|
146
166
|
constructor(client) {
|
|
147
167
|
this.client = client;
|
|
@@ -161,18 +181,20 @@ var AgentMallPurchases = class {
|
|
|
161
181
|
* Create a purchase. The first call returns a 402 MPP payment challenge.
|
|
162
182
|
* Use mppx-wrapped fetch to handle payment automatically, or catch PaymentRequiredError.
|
|
163
183
|
*/
|
|
164
|
-
async create(body) {
|
|
184
|
+
async create(body, options) {
|
|
165
185
|
const idempotencyKey = body.idempotency_key ?? createIdempotencyKey();
|
|
166
186
|
const storeAccountId = body.store_account_id ?? body.retailer_credentials_id;
|
|
187
|
+
const headers = {
|
|
188
|
+
...storeAccountId && options?.account ? await createStoreAccountHeaders(this.client, options.account) : {},
|
|
189
|
+
"X-Idempotency-Key": idempotencyKey
|
|
190
|
+
};
|
|
167
191
|
return this.client.request("POST", "/api/purchases", {
|
|
168
192
|
body: {
|
|
169
193
|
...body,
|
|
170
194
|
...storeAccountId ? { retailer_credentials_id: storeAccountId } : {},
|
|
171
195
|
idempotency_key: idempotencyKey
|
|
172
196
|
},
|
|
173
|
-
headers
|
|
174
|
-
"X-Idempotency-Key": idempotencyKey
|
|
175
|
-
}
|
|
197
|
+
headers
|
|
176
198
|
});
|
|
177
199
|
}
|
|
178
200
|
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
@@ -285,23 +307,7 @@ var AgentMallStoreAccounts = class {
|
|
|
285
307
|
this.client = client;
|
|
286
308
|
}
|
|
287
309
|
async walletHeaders(account) {
|
|
288
|
-
|
|
289
|
-
"POST",
|
|
290
|
-
"/api/managed-accounts/challenge",
|
|
291
|
-
{
|
|
292
|
-
body: {
|
|
293
|
-
address: account.address
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
);
|
|
297
|
-
const signature = await account.signMessage({
|
|
298
|
-
message: challenge.message
|
|
299
|
-
});
|
|
300
|
-
return {
|
|
301
|
-
"X-AgentMall-Wallet-Address": account.address,
|
|
302
|
-
"X-AgentMall-Auth-Challenge": challenge.challenge,
|
|
303
|
-
"X-AgentMall-Auth-Signature": signature
|
|
304
|
-
};
|
|
310
|
+
return createStoreAccountHeaders(this.client, account);
|
|
305
311
|
}
|
|
306
312
|
/** List your store accounts. Requires either apiSecret or a wallet signer. */
|
|
307
313
|
async list(options) {
|
|
@@ -702,6 +708,13 @@ function displayOrderSummary(body) {
|
|
|
702
708
|
line(
|
|
703
709
|
`${addr.city}, ${addr.state ?? ""} ${addr.postal_code} ${addr.country}`
|
|
704
710
|
);
|
|
711
|
+
if (body.store_account_id || body.retailer_credentials_id) {
|
|
712
|
+
gap();
|
|
713
|
+
kv(
|
|
714
|
+
"Store account",
|
|
715
|
+
`${c.bold}${body.store_account_id ?? body.retailer_credentials_id}${c.reset}`
|
|
716
|
+
);
|
|
717
|
+
}
|
|
705
718
|
}
|
|
706
719
|
function displayOrderResult(order) {
|
|
707
720
|
gap();
|
|
@@ -784,6 +797,35 @@ function displayRefund(refund2) {
|
|
|
784
797
|
}
|
|
785
798
|
gap();
|
|
786
799
|
}
|
|
800
|
+
function formatTimestamp(value) {
|
|
801
|
+
return new Date(value).toLocaleString();
|
|
802
|
+
}
|
|
803
|
+
function displayStoreAccount(account, opts) {
|
|
804
|
+
section(opts?.title ?? `Store Account ${account.short_id}`);
|
|
805
|
+
kv("Short ID", account.short_id);
|
|
806
|
+
kv("Retailer", account.retailer ?? "default");
|
|
807
|
+
kv("Email", account.email);
|
|
808
|
+
kv("2FA", account.has_totp ? "configured" : "not set", {
|
|
809
|
+
color: account.has_totp ? c.green : c.yellow
|
|
810
|
+
});
|
|
811
|
+
kv("Forwarding", account.has_forwarding ? "ready" : "pending", {
|
|
812
|
+
color: account.has_forwarding ? c.green : c.yellow
|
|
813
|
+
});
|
|
814
|
+
kv("Forward Email", account.forwarding_email, { dim: true });
|
|
815
|
+
kv("Created", formatTimestamp(account.created_at), { dim: true });
|
|
816
|
+
kv("Updated", formatTimestamp(account.updated_at), { dim: true });
|
|
817
|
+
}
|
|
818
|
+
function displayStoreAccounts(accounts) {
|
|
819
|
+
section("Store Accounts");
|
|
820
|
+
if (accounts.length === 0) {
|
|
821
|
+
line("No store accounts found.");
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
kv("Total", String(accounts.length));
|
|
825
|
+
for (const account of accounts) {
|
|
826
|
+
displayStoreAccount(account);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
787
829
|
|
|
788
830
|
// src/cli/prompts.ts
|
|
789
831
|
import { input, confirm, select } from "@inquirer/prompts";
|
|
@@ -977,6 +1019,17 @@ function parseTempoBalance(balance) {
|
|
|
977
1019
|
function formatUsdcNumber(amount) {
|
|
978
1020
|
return amount.toFixed(6).replace(/\.?0+$/, "");
|
|
979
1021
|
}
|
|
1022
|
+
function createIdempotencyKey2() {
|
|
1023
|
+
return globalThis.crypto?.randomUUID?.() ?? `agentmall_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
1024
|
+
}
|
|
1025
|
+
function normalizeAddress(value) {
|
|
1026
|
+
const trimmed = value?.trim();
|
|
1027
|
+
return trimmed ? trimmed.toLowerCase() : void 0;
|
|
1028
|
+
}
|
|
1029
|
+
function formatAddress(address) {
|
|
1030
|
+
if (!address) return null;
|
|
1031
|
+
return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
|
|
1032
|
+
}
|
|
980
1033
|
async function runCommandCapture(command2, args2, envOverrides) {
|
|
981
1034
|
return await new Promise((resolve, reject) => {
|
|
982
1035
|
const child = spawn(command2, args2, {
|
|
@@ -1029,6 +1082,15 @@ async function readTempoWhoami() {
|
|
|
1029
1082
|
return null;
|
|
1030
1083
|
}
|
|
1031
1084
|
}
|
|
1085
|
+
async function readTempoKeys() {
|
|
1086
|
+
try {
|
|
1087
|
+
const result = await runCommandCapture("tempo", ["wallet", "keys", "-j"]);
|
|
1088
|
+
if (result.code !== 0) return null;
|
|
1089
|
+
return JSON.parse(result.stdout);
|
|
1090
|
+
} catch {
|
|
1091
|
+
return null;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1032
1094
|
async function ensureTempoInstalled() {
|
|
1033
1095
|
try {
|
|
1034
1096
|
const result = await runCommandCapture("tempo", ["--version"]);
|
|
@@ -1061,6 +1123,94 @@ function formatUsdAmount(cents) {
|
|
|
1061
1123
|
function sleep(ms) {
|
|
1062
1124
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1063
1125
|
}
|
|
1126
|
+
async function getTempoSignerContext(wallet) {
|
|
1127
|
+
const readyWallet = wallet ?? await ensureTempoReady();
|
|
1128
|
+
const fallbackKey = (await readTempoKeys())?.keys?.[0];
|
|
1129
|
+
const tempoKey = readyWallet.key ?? fallbackKey;
|
|
1130
|
+
const privateKey = tempoKey?.key?.trim();
|
|
1131
|
+
const signerAddress = normalizeAddress(tempoKey?.address);
|
|
1132
|
+
if (!privateKey || !signerAddress) {
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
"Tempo wallet does not expose a signing key. Run `tempo wallet login` again."
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
const account = privateKeyToAccount(privateKey);
|
|
1138
|
+
if (normalizeAddress(account.address) !== signerAddress) {
|
|
1139
|
+
throw new Error("Tempo signing key does not match the signer address.");
|
|
1140
|
+
}
|
|
1141
|
+
return {
|
|
1142
|
+
account,
|
|
1143
|
+
signerAddress,
|
|
1144
|
+
walletAddress: normalizeAddress(readyWallet.wallet) ?? normalizeAddress(tempoKey?.wallet_address)
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
async function createStoreAccountAuthHeaders(account) {
|
|
1148
|
+
const response = await fetch(`${BASE_URL}/api/managed-accounts/challenge`, {
|
|
1149
|
+
method: "POST",
|
|
1150
|
+
headers: {
|
|
1151
|
+
"Content-Type": "application/json"
|
|
1152
|
+
},
|
|
1153
|
+
body: JSON.stringify({
|
|
1154
|
+
address: account.address
|
|
1155
|
+
})
|
|
1156
|
+
});
|
|
1157
|
+
const text = await response.text();
|
|
1158
|
+
let payload = null;
|
|
1159
|
+
try {
|
|
1160
|
+
payload = text ? JSON.parse(text) : null;
|
|
1161
|
+
} catch {
|
|
1162
|
+
payload = text || null;
|
|
1163
|
+
}
|
|
1164
|
+
if (!response.ok) {
|
|
1165
|
+
const message = typeof payload === "string" ? payload : payload?.error ?? "Unable to authorize store account";
|
|
1166
|
+
throw new Error(message);
|
|
1167
|
+
}
|
|
1168
|
+
const challenge = payload;
|
|
1169
|
+
if (!challenge?.challenge || !challenge.message) {
|
|
1170
|
+
throw new Error("Store account authorization challenge was invalid.");
|
|
1171
|
+
}
|
|
1172
|
+
const signature = await account.signMessage({
|
|
1173
|
+
message: challenge.message
|
|
1174
|
+
});
|
|
1175
|
+
return {
|
|
1176
|
+
"X-AgentMall-Wallet-Address": account.address,
|
|
1177
|
+
"X-AgentMall-Auth-Challenge": challenge.challenge,
|
|
1178
|
+
"X-AgentMall-Auth-Signature": signature
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
function normalizeOptional(value) {
|
|
1182
|
+
const trimmed = value?.trim();
|
|
1183
|
+
return trimmed ? trimmed : void 0;
|
|
1184
|
+
}
|
|
1185
|
+
async function promptStoreAccountFields(mode) {
|
|
1186
|
+
const { input: input2 } = await import("@inquirer/prompts");
|
|
1187
|
+
const email = mode === "create" ? await input2({
|
|
1188
|
+
message: "Store account email",
|
|
1189
|
+
validate: (value) => EMAIL_PATTERN.test(value.trim()) ? true : "A valid email is required"
|
|
1190
|
+
}) : await input2({
|
|
1191
|
+
message: "Email (leave blank to keep current)",
|
|
1192
|
+
default: "",
|
|
1193
|
+
validate: (value) => !value.trim() || EMAIL_PATTERN.test(value.trim()) ? true : "Enter a valid email or leave blank"
|
|
1194
|
+
});
|
|
1195
|
+
const retailer = await input2({
|
|
1196
|
+
message: mode === "create" ? "Retailer" : "Retailer (leave blank to keep current)",
|
|
1197
|
+
default: mode === "create" ? "amazon" : ""
|
|
1198
|
+
});
|
|
1199
|
+
const password = await input2({
|
|
1200
|
+
message: mode === "create" ? "Password (optional)" : "Password (leave blank to keep current)",
|
|
1201
|
+
default: ""
|
|
1202
|
+
});
|
|
1203
|
+
const totpSecret = await input2({
|
|
1204
|
+
message: mode === "create" ? "TOTP secret (optional)" : "TOTP secret (leave blank to keep current)",
|
|
1205
|
+
default: ""
|
|
1206
|
+
});
|
|
1207
|
+
return {
|
|
1208
|
+
...normalizeOptional(email) ? { email: normalizeOptional(email) } : {},
|
|
1209
|
+
...normalizeOptional(retailer) ? { retailer: normalizeOptional(retailer) } : {},
|
|
1210
|
+
...normalizeOptional(password) ? { password: normalizeOptional(password) } : {},
|
|
1211
|
+
...normalizeOptional(totpSecret) ? { totpSecret: normalizeOptional(totpSecret) } : {}
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1064
1214
|
function getSelectedVariantUnitPriceCents(selectedVariants) {
|
|
1065
1215
|
const highestVariantPrice = selectedVariants?.reduce((highest, variant) => {
|
|
1066
1216
|
const variantPriceCents = typeof variant.price === "number" ? Math.round(variant.price * 100) : 0;
|
|
@@ -1110,23 +1260,25 @@ async function ensureSufficientBalance(requiredCents, wallet) {
|
|
|
1110
1260
|
`Still not enough USDC after funding: have ${formatUsdcNumber(available)}, need ${formatUsdAmount(requiredCents)}.`
|
|
1111
1261
|
);
|
|
1112
1262
|
}
|
|
1113
|
-
async function createPurchaseWithTempo(body) {
|
|
1114
|
-
const
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
{
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1263
|
+
async function createPurchaseWithTempo(body, options) {
|
|
1264
|
+
const idempotencyKey = body.idempotency_key?.trim() || createIdempotencyKey2();
|
|
1265
|
+
const requestBody = {
|
|
1266
|
+
...body,
|
|
1267
|
+
idempotency_key: idempotencyKey
|
|
1268
|
+
};
|
|
1269
|
+
const totalChargeCents = requestBody.max_budget + SERVICE_FEE_CENTS;
|
|
1270
|
+
const headers = {
|
|
1271
|
+
"X-Idempotency-Key": idempotencyKey,
|
|
1272
|
+
...options?.headers ?? {}
|
|
1273
|
+
};
|
|
1274
|
+
const args2 = ["request", "-s", "-X", "POST"];
|
|
1275
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
1276
|
+
args2.push("-H", `${key}: ${value}`);
|
|
1277
|
+
}
|
|
1278
|
+
args2.push("--json", JSON.stringify(requestBody), `${BASE_URL}/api/purchases`);
|
|
1279
|
+
const result = await runCommandCapture("tempo", args2, {
|
|
1280
|
+
TEMPO_MAX_SPEND: formatUsdAmount(totalChargeCents)
|
|
1281
|
+
});
|
|
1130
1282
|
if (result.code !== 0) {
|
|
1131
1283
|
const raw = result.stderr.trim() || result.stdout.trim();
|
|
1132
1284
|
const payload = raw ? (() => {
|
|
@@ -1147,7 +1299,7 @@ async function createPurchaseWithTempo(body) {
|
|
|
1147
1299
|
);
|
|
1148
1300
|
}
|
|
1149
1301
|
}
|
|
1150
|
-
async function buy(urlArg) {
|
|
1302
|
+
async function buy(urlArg, options) {
|
|
1151
1303
|
try {
|
|
1152
1304
|
banner();
|
|
1153
1305
|
gap();
|
|
@@ -1193,6 +1345,7 @@ async function buy(urlArg) {
|
|
|
1193
1345
|
message: "Email for order updates",
|
|
1194
1346
|
validate: (value) => EMAIL_PATTERN.test(value.trim()) ? true : "A valid email is required"
|
|
1195
1347
|
});
|
|
1348
|
+
const storeAccountId = normalizeOptional(options?.storeAccountId);
|
|
1196
1349
|
const body = {
|
|
1197
1350
|
items: [
|
|
1198
1351
|
{
|
|
@@ -1203,7 +1356,9 @@ async function buy(urlArg) {
|
|
|
1203
1356
|
],
|
|
1204
1357
|
delivery_address: address,
|
|
1205
1358
|
max_budget: maxBudget,
|
|
1206
|
-
buyer_email: buyerEmail
|
|
1359
|
+
buyer_email: buyerEmail,
|
|
1360
|
+
...storeAccountId ? { store_account_id: storeAccountId } : {},
|
|
1361
|
+
idempotency_key: createIdempotencyKey2()
|
|
1207
1362
|
};
|
|
1208
1363
|
displayOrderSummary(body);
|
|
1209
1364
|
gap();
|
|
@@ -1227,17 +1382,32 @@ async function buy(urlArg) {
|
|
|
1227
1382
|
return;
|
|
1228
1383
|
}
|
|
1229
1384
|
const totalChargeCents = maxBudget + SERVICE_FEE_CENTS;
|
|
1230
|
-
const
|
|
1231
|
-
await ensureSufficientBalance(totalChargeCents,
|
|
1385
|
+
const initialWallet = await spin("Connecting wallet", () => ensureTempoReady());
|
|
1386
|
+
const wallet = await ensureSufficientBalance(totalChargeCents, initialWallet);
|
|
1232
1387
|
if (wallet.wallet) {
|
|
1233
1388
|
const addr = wallet.wallet;
|
|
1234
1389
|
const short = `${addr.slice(0, 6)}\u2026${addr.slice(-4)}`;
|
|
1235
1390
|
const bal = wallet.balance?.available ? ` \xB7 ${wallet.balance.available} ${wallet.balance?.symbol ?? "USDC"}` : "";
|
|
1236
1391
|
muted(`Wallet ${short}${bal}`);
|
|
1237
1392
|
}
|
|
1393
|
+
let purchaseHeaders;
|
|
1394
|
+
if (storeAccountId) {
|
|
1395
|
+
const signer = await spin("Authorizing store account", async () => {
|
|
1396
|
+
const context = await getTempoSignerContext(wallet);
|
|
1397
|
+
const headers = await createStoreAccountAuthHeaders(context.account);
|
|
1398
|
+
return { headers, context };
|
|
1399
|
+
});
|
|
1400
|
+
purchaseHeaders = signer.headers;
|
|
1401
|
+
const signerLine = formatAddress(signer.context.signerAddress);
|
|
1402
|
+
muted(
|
|
1403
|
+
signerLine ? `Store account ${storeAccountId} authorized by signer ${signerLine}` : `Store account ${storeAccountId} authorized`
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1238
1406
|
const order = await spin(
|
|
1239
1407
|
"Placing order",
|
|
1240
|
-
() => createPurchaseWithTempo(body
|
|
1408
|
+
() => createPurchaseWithTempo(body, {
|
|
1409
|
+
...purchaseHeaders ? { headers: purchaseHeaders } : {}
|
|
1410
|
+
})
|
|
1241
1411
|
);
|
|
1242
1412
|
if (order.buyerToken) {
|
|
1243
1413
|
await saveBuyerToken(order.id, order.buyerToken);
|
|
@@ -1347,6 +1517,120 @@ async function onboard() {
|
|
|
1347
1517
|
);
|
|
1348
1518
|
gap();
|
|
1349
1519
|
}
|
|
1520
|
+
async function storeAccountsList() {
|
|
1521
|
+
banner();
|
|
1522
|
+
gap();
|
|
1523
|
+
const wallet = await spin("Connecting wallet", () => ensureTempoReady());
|
|
1524
|
+
const signer = await getTempoSignerContext(wallet);
|
|
1525
|
+
const client = new AgentMall();
|
|
1526
|
+
const walletLabel = formatAddress(signer.walletAddress);
|
|
1527
|
+
const signerLabel = formatAddress(signer.signerAddress);
|
|
1528
|
+
if (walletLabel || signerLabel) {
|
|
1529
|
+
muted(
|
|
1530
|
+
`Using ${walletLabel ? `wallet ${walletLabel}` : "Tempo wallet"}${walletLabel && signerLabel ? " \xB7 " : ""}${signerLabel ? `signer ${signerLabel}` : ""}`
|
|
1531
|
+
);
|
|
1532
|
+
gap();
|
|
1533
|
+
}
|
|
1534
|
+
const accounts = await spin(
|
|
1535
|
+
"Loading store accounts",
|
|
1536
|
+
() => client.storeAccounts.list({ account: signer.account })
|
|
1537
|
+
);
|
|
1538
|
+
displayStoreAccounts(accounts);
|
|
1539
|
+
gap();
|
|
1540
|
+
}
|
|
1541
|
+
async function storeAccountsCreate(options) {
|
|
1542
|
+
banner();
|
|
1543
|
+
gap();
|
|
1544
|
+
const fields = {
|
|
1545
|
+
...normalizeOptional(options?.email) ? { email: normalizeOptional(options?.email) } : {},
|
|
1546
|
+
...normalizeOptional(options?.retailer) ? { retailer: normalizeOptional(options?.retailer) } : {},
|
|
1547
|
+
...normalizeOptional(options?.password) ? { password: normalizeOptional(options?.password) } : {},
|
|
1548
|
+
...normalizeOptional(options?.totpSecret) ? { totpSecret: normalizeOptional(options?.totpSecret) } : {}
|
|
1549
|
+
};
|
|
1550
|
+
const prompted = fields.email && fields.retailer !== void 0 ? fields : {
|
|
1551
|
+
...fields,
|
|
1552
|
+
...await promptStoreAccountFields("create")
|
|
1553
|
+
};
|
|
1554
|
+
if (!prompted.email) {
|
|
1555
|
+
throw new Error("Email is required.");
|
|
1556
|
+
}
|
|
1557
|
+
const body = {
|
|
1558
|
+
email: prompted.email,
|
|
1559
|
+
...prompted.retailer ? { retailer: prompted.retailer } : {},
|
|
1560
|
+
...prompted.password ? { password: prompted.password } : {},
|
|
1561
|
+
...prompted.totpSecret ? { totp_secret: prompted.totpSecret } : {}
|
|
1562
|
+
};
|
|
1563
|
+
const wallet = await spin("Connecting wallet", () => ensureTempoReady());
|
|
1564
|
+
const signer = await getTempoSignerContext(wallet);
|
|
1565
|
+
const client = new AgentMall();
|
|
1566
|
+
const account = await spin(
|
|
1567
|
+
"Creating store account",
|
|
1568
|
+
() => client.storeAccounts.create(body, { account: signer.account })
|
|
1569
|
+
);
|
|
1570
|
+
displayStoreAccount(account, { title: "Store Account Created" });
|
|
1571
|
+
gap();
|
|
1572
|
+
line(
|
|
1573
|
+
`Use ${c.bold}store_account_id: "${account.short_id}"${c.reset} on purchases.`
|
|
1574
|
+
);
|
|
1575
|
+
gap();
|
|
1576
|
+
}
|
|
1577
|
+
async function storeAccountsUpdate(shortId, options) {
|
|
1578
|
+
banner();
|
|
1579
|
+
gap();
|
|
1580
|
+
if (!shortId.trim()) {
|
|
1581
|
+
throw new Error("short_id is required.");
|
|
1582
|
+
}
|
|
1583
|
+
let fields = {
|
|
1584
|
+
...normalizeOptional(options?.email) ? { email: normalizeOptional(options?.email) } : {},
|
|
1585
|
+
...normalizeOptional(options?.retailer) ? { retailer: normalizeOptional(options?.retailer) } : {},
|
|
1586
|
+
...normalizeOptional(options?.password) ? { password: normalizeOptional(options?.password) } : {},
|
|
1587
|
+
...normalizeOptional(options?.totpSecret) ? { totpSecret: normalizeOptional(options?.totpSecret) } : {}
|
|
1588
|
+
};
|
|
1589
|
+
if (Object.keys(fields).length === 0) {
|
|
1590
|
+
fields = await promptStoreAccountFields("update");
|
|
1591
|
+
}
|
|
1592
|
+
if (Object.keys(fields).length === 0) {
|
|
1593
|
+
throw new Error("No updates provided.");
|
|
1594
|
+
}
|
|
1595
|
+
const body = {
|
|
1596
|
+
short_id: shortId.trim(),
|
|
1597
|
+
...fields.email ? { email: fields.email } : {},
|
|
1598
|
+
...fields.retailer ? { retailer: fields.retailer } : {},
|
|
1599
|
+
...fields.password ? { password: fields.password } : {},
|
|
1600
|
+
...fields.totpSecret ? { totp_secret: fields.totpSecret } : {}
|
|
1601
|
+
};
|
|
1602
|
+
const wallet = await spin("Connecting wallet", () => ensureTempoReady());
|
|
1603
|
+
const signer = await getTempoSignerContext(wallet);
|
|
1604
|
+
const client = new AgentMall();
|
|
1605
|
+
const account = await spin(
|
|
1606
|
+
"Updating store account",
|
|
1607
|
+
() => client.storeAccounts.update(body, { account: signer.account })
|
|
1608
|
+
);
|
|
1609
|
+
displayStoreAccount(account, { title: "Store Account Updated" });
|
|
1610
|
+
gap();
|
|
1611
|
+
}
|
|
1612
|
+
async function storeAccountsDelete(shortId, options) {
|
|
1613
|
+
banner();
|
|
1614
|
+
gap();
|
|
1615
|
+
if (!shortId.trim()) {
|
|
1616
|
+
throw new Error("short_id is required.");
|
|
1617
|
+
}
|
|
1618
|
+
const confirmed = options?.yes ?? await promptConfirm(`Delete store account ${shortId.trim()}?`);
|
|
1619
|
+
if (!confirmed) {
|
|
1620
|
+
muted("Cancelled.");
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
const wallet = await spin("Connecting wallet", () => ensureTempoReady());
|
|
1624
|
+
const signer = await getTempoSignerContext(wallet);
|
|
1625
|
+
const client = new AgentMall();
|
|
1626
|
+
await spin(
|
|
1627
|
+
"Deleting store account",
|
|
1628
|
+
() => client.storeAccounts.delete(shortId.trim(), { account: signer.account })
|
|
1629
|
+
);
|
|
1630
|
+
section("Store Account Deleted");
|
|
1631
|
+
line(`${c.bold}${shortId.trim()}${c.reset} was removed.`);
|
|
1632
|
+
gap();
|
|
1633
|
+
}
|
|
1350
1634
|
|
|
1351
1635
|
// src/cli.ts
|
|
1352
1636
|
var c2 = {
|
|
@@ -1358,22 +1642,78 @@ var c2 = {
|
|
|
1358
1642
|
};
|
|
1359
1643
|
var args = process.argv.slice(2);
|
|
1360
1644
|
var command = args[0];
|
|
1361
|
-
function
|
|
1362
|
-
const inline = values.find((
|
|
1645
|
+
function readFlagValue(values, flag) {
|
|
1646
|
+
const inline = values.find((value2) => value2.startsWith(`${flag}=`));
|
|
1363
1647
|
if (inline) {
|
|
1364
|
-
const
|
|
1365
|
-
return
|
|
1648
|
+
const value2 = inline.slice(`${flag}=`.length).trim();
|
|
1649
|
+
return value2 || void 0;
|
|
1366
1650
|
}
|
|
1367
|
-
const index = values.indexOf(
|
|
1651
|
+
const index = values.indexOf(flag);
|
|
1368
1652
|
if (index === -1) return void 0;
|
|
1369
|
-
const
|
|
1370
|
-
return
|
|
1653
|
+
const value = values[index + 1]?.trim();
|
|
1654
|
+
return value || void 0;
|
|
1655
|
+
}
|
|
1656
|
+
function hasFlag(values, flag) {
|
|
1657
|
+
return values.includes(flag);
|
|
1658
|
+
}
|
|
1659
|
+
function readBuyerTokenFlag(values) {
|
|
1660
|
+
return readFlagValue(values, "--buyer-token");
|
|
1661
|
+
}
|
|
1662
|
+
function readStoreAccountFlag(values) {
|
|
1663
|
+
return readFlagValue(values, "--store-account");
|
|
1664
|
+
}
|
|
1665
|
+
async function handleStoreAccounts(values) {
|
|
1666
|
+
const subcommand = values[0];
|
|
1667
|
+
const rest = values.slice(1);
|
|
1668
|
+
switch (subcommand) {
|
|
1669
|
+
case "list":
|
|
1670
|
+
await storeAccountsList();
|
|
1671
|
+
break;
|
|
1672
|
+
case "create":
|
|
1673
|
+
await storeAccountsCreate({
|
|
1674
|
+
email: readFlagValue(rest, "--email"),
|
|
1675
|
+
retailer: readFlagValue(rest, "--retailer"),
|
|
1676
|
+
password: readFlagValue(rest, "--password"),
|
|
1677
|
+
totpSecret: readFlagValue(rest, "--totp-secret")
|
|
1678
|
+
});
|
|
1679
|
+
break;
|
|
1680
|
+
case "update":
|
|
1681
|
+
if (!rest[0]) {
|
|
1682
|
+
console.error(
|
|
1683
|
+
"Usage: agentmall store-accounts update <short_id> [--email <email>] [--retailer <name>] [--password <password>] [--totp-secret <secret>]"
|
|
1684
|
+
);
|
|
1685
|
+
process.exit(1);
|
|
1686
|
+
}
|
|
1687
|
+
await storeAccountsUpdate(rest[0], {
|
|
1688
|
+
email: readFlagValue(rest.slice(1), "--email"),
|
|
1689
|
+
retailer: readFlagValue(rest.slice(1), "--retailer"),
|
|
1690
|
+
password: readFlagValue(rest.slice(1), "--password"),
|
|
1691
|
+
totpSecret: readFlagValue(rest.slice(1), "--totp-secret")
|
|
1692
|
+
});
|
|
1693
|
+
break;
|
|
1694
|
+
case "delete":
|
|
1695
|
+
if (!rest[0]) {
|
|
1696
|
+
console.error("Usage: agentmall store-accounts delete <short_id> [--yes]");
|
|
1697
|
+
process.exit(1);
|
|
1698
|
+
}
|
|
1699
|
+
await storeAccountsDelete(rest[0], {
|
|
1700
|
+
yes: hasFlag(rest.slice(1), "--yes")
|
|
1701
|
+
});
|
|
1702
|
+
break;
|
|
1703
|
+
default:
|
|
1704
|
+
console.error(
|
|
1705
|
+
"Usage: agentmall store-accounts <list|create|update|delete> ..."
|
|
1706
|
+
);
|
|
1707
|
+
process.exit(1);
|
|
1708
|
+
}
|
|
1371
1709
|
}
|
|
1372
1710
|
async function main() {
|
|
1373
1711
|
try {
|
|
1374
1712
|
switch (command) {
|
|
1375
1713
|
case "buy":
|
|
1376
|
-
await buy(args[1]
|
|
1714
|
+
await buy(args[1], {
|
|
1715
|
+
storeAccountId: readStoreAccountFlag(args.slice(2))
|
|
1716
|
+
});
|
|
1377
1717
|
break;
|
|
1378
1718
|
case "status":
|
|
1379
1719
|
if (!args[1]) {
|
|
@@ -1393,6 +1733,9 @@ async function main() {
|
|
|
1393
1733
|
case "setup":
|
|
1394
1734
|
await onboard();
|
|
1395
1735
|
break;
|
|
1736
|
+
case "store-accounts":
|
|
1737
|
+
await handleStoreAccounts(args.slice(1));
|
|
1738
|
+
break;
|
|
1396
1739
|
case "help":
|
|
1397
1740
|
case "--help":
|
|
1398
1741
|
case "-h":
|
|
@@ -1431,6 +1774,9 @@ function printHelp() {
|
|
|
1431
1774
|
console.log(
|
|
1432
1775
|
` ${c2.cyan}agentmall buy${c2.reset} <url> ${c2.dim}Buy a product${c2.reset}`
|
|
1433
1776
|
);
|
|
1777
|
+
console.log(
|
|
1778
|
+
` ${c2.cyan}agentmall store-accounts${c2.reset} ${c2.dim}Manage your store accounts${c2.reset}`
|
|
1779
|
+
);
|
|
1434
1780
|
console.log(
|
|
1435
1781
|
` ${c2.cyan}agentmall status${c2.reset} <id> ${c2.dim}Check order status${c2.reset}`
|
|
1436
1782
|
);
|
|
@@ -1448,6 +1794,12 @@ function printHelp() {
|
|
|
1448
1794
|
console.log(
|
|
1449
1795
|
` ${c2.dim}$${c2.reset} npx agentmall https://amazon.com/dp/B0DWTMJHCG`
|
|
1450
1796
|
);
|
|
1797
|
+
console.log(
|
|
1798
|
+
` ${c2.dim}$${c2.reset} npx agentmall buy <url> --store-account zn_acct_abc123`
|
|
1799
|
+
);
|
|
1800
|
+
console.log(
|
|
1801
|
+
` ${c2.dim}$${c2.reset} npx agentmall store-accounts create`
|
|
1802
|
+
);
|
|
1451
1803
|
console.log(` ${c2.dim}$${c2.reset} npx agentmall status pur_abc123`);
|
|
1452
1804
|
console.log(
|
|
1453
1805
|
` ${c2.dim}$${c2.reset} npx agentmall status pur_abc123 --buyer-token amtk_...`
|
package/dist/index.cjs
CHANGED
|
@@ -182,6 +182,25 @@ var AgentMall = class {
|
|
|
182
182
|
return await response.json();
|
|
183
183
|
}
|
|
184
184
|
};
|
|
185
|
+
async function createStoreAccountHeaders(client, account) {
|
|
186
|
+
const challenge = await client.request(
|
|
187
|
+
"POST",
|
|
188
|
+
"/api/managed-accounts/challenge",
|
|
189
|
+
{
|
|
190
|
+
body: {
|
|
191
|
+
address: account.address
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
const signature = await account.signMessage({
|
|
196
|
+
message: challenge.message
|
|
197
|
+
});
|
|
198
|
+
return {
|
|
199
|
+
"X-AgentMall-Wallet-Address": account.address,
|
|
200
|
+
"X-AgentMall-Auth-Challenge": challenge.challenge,
|
|
201
|
+
"X-AgentMall-Auth-Signature": signature
|
|
202
|
+
};
|
|
203
|
+
}
|
|
185
204
|
var AgentMallProducts = class {
|
|
186
205
|
constructor(client) {
|
|
187
206
|
this.client = client;
|
|
@@ -201,18 +220,20 @@ var AgentMallPurchases = class {
|
|
|
201
220
|
* Create a purchase. The first call returns a 402 MPP payment challenge.
|
|
202
221
|
* Use mppx-wrapped fetch to handle payment automatically, or catch PaymentRequiredError.
|
|
203
222
|
*/
|
|
204
|
-
async create(body) {
|
|
223
|
+
async create(body, options) {
|
|
205
224
|
const idempotencyKey = body.idempotency_key ?? createIdempotencyKey();
|
|
206
225
|
const storeAccountId = body.store_account_id ?? body.retailer_credentials_id;
|
|
226
|
+
const headers = {
|
|
227
|
+
...storeAccountId && options?.account ? await createStoreAccountHeaders(this.client, options.account) : {},
|
|
228
|
+
"X-Idempotency-Key": idempotencyKey
|
|
229
|
+
};
|
|
207
230
|
return this.client.request("POST", "/api/purchases", {
|
|
208
231
|
body: {
|
|
209
232
|
...body,
|
|
210
233
|
...storeAccountId ? { retailer_credentials_id: storeAccountId } : {},
|
|
211
234
|
idempotency_key: idempotencyKey
|
|
212
235
|
},
|
|
213
|
-
headers
|
|
214
|
-
"X-Idempotency-Key": idempotencyKey
|
|
215
|
-
}
|
|
236
|
+
headers
|
|
216
237
|
});
|
|
217
238
|
}
|
|
218
239
|
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
@@ -325,23 +346,7 @@ var AgentMallStoreAccounts = class {
|
|
|
325
346
|
this.client = client;
|
|
326
347
|
}
|
|
327
348
|
async walletHeaders(account) {
|
|
328
|
-
|
|
329
|
-
"POST",
|
|
330
|
-
"/api/managed-accounts/challenge",
|
|
331
|
-
{
|
|
332
|
-
body: {
|
|
333
|
-
address: account.address
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
);
|
|
337
|
-
const signature = await account.signMessage({
|
|
338
|
-
message: challenge.message
|
|
339
|
-
});
|
|
340
|
-
return {
|
|
341
|
-
"X-AgentMall-Wallet-Address": account.address,
|
|
342
|
-
"X-AgentMall-Auth-Challenge": challenge.challenge,
|
|
343
|
-
"X-AgentMall-Auth-Signature": signature
|
|
344
|
-
};
|
|
349
|
+
return createStoreAccountHeaders(this.client, account);
|
|
345
350
|
}
|
|
346
351
|
/** List your store accounts. Requires either apiSecret or a wallet signer. */
|
|
347
352
|
async list(options) {
|
|
@@ -394,7 +399,7 @@ async function purchase(config) {
|
|
|
394
399
|
baseUrl: baseUrl ?? BASE_URL,
|
|
395
400
|
fetch: mppx.fetch.bind(mppx)
|
|
396
401
|
});
|
|
397
|
-
return client.purchases.create(body);
|
|
402
|
+
return client.purchases.create(body, { account });
|
|
398
403
|
}
|
|
399
404
|
// Annotate the CommonJS export names for ESM import in node:
|
|
400
405
|
0 && (module.exports = {
|
package/dist/index.d.cts
CHANGED
|
@@ -220,7 +220,9 @@ declare class AgentMallPurchases {
|
|
|
220
220
|
* Create a purchase. The first call returns a 402 MPP payment challenge.
|
|
221
221
|
* Use mppx-wrapped fetch to handle payment automatically, or catch PaymentRequiredError.
|
|
222
222
|
*/
|
|
223
|
-
create(body: CreatePurchaseRequest
|
|
223
|
+
create(body: CreatePurchaseRequest, options?: {
|
|
224
|
+
account?: WalletAccount;
|
|
225
|
+
}): Promise<CreatePurchaseResponse>;
|
|
224
226
|
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
225
227
|
get(id: string, options?: {
|
|
226
228
|
buyerToken?: string;
|
|
@@ -273,7 +275,7 @@ type AgentMallManagedAccounts = AgentMallStoreAccounts;
|
|
|
273
275
|
|
|
274
276
|
type PurchaseConfig = CreatePurchaseRequest & {
|
|
275
277
|
/** viem Account for MPP payment (from privateKeyToAccount or mppx resolveAccount). */
|
|
276
|
-
account:
|
|
278
|
+
account: WalletAccount;
|
|
277
279
|
/** API base URL. Defaults to https://api.agentmall.sh */
|
|
278
280
|
baseUrl?: string;
|
|
279
281
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -220,7 +220,9 @@ declare class AgentMallPurchases {
|
|
|
220
220
|
* Create a purchase. The first call returns a 402 MPP payment challenge.
|
|
221
221
|
* Use mppx-wrapped fetch to handle payment automatically, or catch PaymentRequiredError.
|
|
222
222
|
*/
|
|
223
|
-
create(body: CreatePurchaseRequest
|
|
223
|
+
create(body: CreatePurchaseRequest, options?: {
|
|
224
|
+
account?: WalletAccount;
|
|
225
|
+
}): Promise<CreatePurchaseResponse>;
|
|
224
226
|
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
225
227
|
get(id: string, options?: {
|
|
226
228
|
buyerToken?: string;
|
|
@@ -273,7 +275,7 @@ type AgentMallManagedAccounts = AgentMallStoreAccounts;
|
|
|
273
275
|
|
|
274
276
|
type PurchaseConfig = CreatePurchaseRequest & {
|
|
275
277
|
/** viem Account for MPP payment (from privateKeyToAccount or mppx resolveAccount). */
|
|
276
|
-
account:
|
|
278
|
+
account: WalletAccount;
|
|
277
279
|
/** API base URL. Defaults to https://api.agentmall.sh */
|
|
278
280
|
baseUrl?: string;
|
|
279
281
|
};
|
package/dist/index.js
CHANGED
|
@@ -137,6 +137,25 @@ var AgentMall = class {
|
|
|
137
137
|
return await response.json();
|
|
138
138
|
}
|
|
139
139
|
};
|
|
140
|
+
async function createStoreAccountHeaders(client, account) {
|
|
141
|
+
const challenge = await client.request(
|
|
142
|
+
"POST",
|
|
143
|
+
"/api/managed-accounts/challenge",
|
|
144
|
+
{
|
|
145
|
+
body: {
|
|
146
|
+
address: account.address
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
const signature = await account.signMessage({
|
|
151
|
+
message: challenge.message
|
|
152
|
+
});
|
|
153
|
+
return {
|
|
154
|
+
"X-AgentMall-Wallet-Address": account.address,
|
|
155
|
+
"X-AgentMall-Auth-Challenge": challenge.challenge,
|
|
156
|
+
"X-AgentMall-Auth-Signature": signature
|
|
157
|
+
};
|
|
158
|
+
}
|
|
140
159
|
var AgentMallProducts = class {
|
|
141
160
|
constructor(client) {
|
|
142
161
|
this.client = client;
|
|
@@ -156,18 +175,20 @@ var AgentMallPurchases = class {
|
|
|
156
175
|
* Create a purchase. The first call returns a 402 MPP payment challenge.
|
|
157
176
|
* Use mppx-wrapped fetch to handle payment automatically, or catch PaymentRequiredError.
|
|
158
177
|
*/
|
|
159
|
-
async create(body) {
|
|
178
|
+
async create(body, options) {
|
|
160
179
|
const idempotencyKey = body.idempotency_key ?? createIdempotencyKey();
|
|
161
180
|
const storeAccountId = body.store_account_id ?? body.retailer_credentials_id;
|
|
181
|
+
const headers = {
|
|
182
|
+
...storeAccountId && options?.account ? await createStoreAccountHeaders(this.client, options.account) : {},
|
|
183
|
+
"X-Idempotency-Key": idempotencyKey
|
|
184
|
+
};
|
|
162
185
|
return this.client.request("POST", "/api/purchases", {
|
|
163
186
|
body: {
|
|
164
187
|
...body,
|
|
165
188
|
...storeAccountId ? { retailer_credentials_id: storeAccountId } : {},
|
|
166
189
|
idempotency_key: idempotencyKey
|
|
167
190
|
},
|
|
168
|
-
headers
|
|
169
|
-
"X-Idempotency-Key": idempotencyKey
|
|
170
|
-
}
|
|
191
|
+
headers
|
|
171
192
|
});
|
|
172
193
|
}
|
|
173
194
|
/** Get a single purchase by ID using either operator auth or a buyer token. */
|
|
@@ -280,23 +301,7 @@ var AgentMallStoreAccounts = class {
|
|
|
280
301
|
this.client = client;
|
|
281
302
|
}
|
|
282
303
|
async walletHeaders(account) {
|
|
283
|
-
|
|
284
|
-
"POST",
|
|
285
|
-
"/api/managed-accounts/challenge",
|
|
286
|
-
{
|
|
287
|
-
body: {
|
|
288
|
-
address: account.address
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
);
|
|
292
|
-
const signature = await account.signMessage({
|
|
293
|
-
message: challenge.message
|
|
294
|
-
});
|
|
295
|
-
return {
|
|
296
|
-
"X-AgentMall-Wallet-Address": account.address,
|
|
297
|
-
"X-AgentMall-Auth-Challenge": challenge.challenge,
|
|
298
|
-
"X-AgentMall-Auth-Signature": signature
|
|
299
|
-
};
|
|
304
|
+
return createStoreAccountHeaders(this.client, account);
|
|
300
305
|
}
|
|
301
306
|
/** List your store accounts. Requires either apiSecret or a wallet signer. */
|
|
302
307
|
async list(options) {
|
|
@@ -349,7 +354,7 @@ async function purchase(config) {
|
|
|
349
354
|
baseUrl: baseUrl ?? BASE_URL,
|
|
350
355
|
fetch: mppx.fetch.bind(mppx)
|
|
351
356
|
});
|
|
352
|
-
return client.purchases.create(body);
|
|
357
|
+
return client.purchases.create(body, { account });
|
|
353
358
|
}
|
|
354
359
|
export {
|
|
355
360
|
AgentMall,
|