@web42/w42 0.1.20 → 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/README.md +167 -67
- package/dist/commands/auth.js +2 -1
- package/dist/commands/cart.d.ts +2 -0
- package/dist/commands/cart.js +219 -0
- package/dist/commands/intent.d.ts +2 -0
- package/dist/commands/intent.js +105 -0
- package/dist/commands/register.js +13 -20
- package/dist/commands/search.js +4 -2
- package/dist/commands/send.js +38 -12
- package/dist/commands/serve.js +1 -0
- package/dist/index.js +4 -2
- package/dist/utils/api.d.ts +7 -0
- package/dist/utils/api.js +24 -2
- package/dist/utils/config.d.ts +12 -0
- package/dist/utils/config.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/commands/pay.d.ts +0 -2
- package/dist/commands/pay.js +0 -260
package/dist/commands/pay.js
DELETED
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { Command } from "commander";
|
|
3
|
-
import ora from "ora";
|
|
4
|
-
import { apiGet, apiPost } from "../utils/api.js";
|
|
5
|
-
import { requireAuth, setConfigValue, } from "../utils/config.js";
|
|
6
|
-
import { getTx, listTxs, updateTx } from "../utils/tx-store.js";
|
|
7
|
-
// ─── Intent ───────────────────────────────────────────────
|
|
8
|
-
const intentCommand = new Command("intent").description("Manage payment intents");
|
|
9
|
-
intentCommand
|
|
10
|
-
.command("get")
|
|
11
|
-
.description("Fetch an intent by nick")
|
|
12
|
-
.requiredOption("--nick <nick>", "Intent nick")
|
|
13
|
-
.action(async (opts) => {
|
|
14
|
-
requireAuth();
|
|
15
|
-
const spinner = ora(`Fetching intent ${opts.nick}...`).start();
|
|
16
|
-
try {
|
|
17
|
-
const res = await apiGet(`/api/pay/intent/${encodeURIComponent(opts.nick)}`);
|
|
18
|
-
spinner.stop();
|
|
19
|
-
// Cache if active
|
|
20
|
-
if (res.status === "active") {
|
|
21
|
-
setConfigValue(`intents.${opts.nick}`, JSON.stringify(res));
|
|
22
|
-
}
|
|
23
|
-
console.log(JSON.stringify(res, null, 2));
|
|
24
|
-
}
|
|
25
|
-
catch (err) {
|
|
26
|
-
spinner.fail("Failed to fetch intent");
|
|
27
|
-
console.error(chalk.red(String(err)));
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
intentCommand
|
|
32
|
-
.command("list")
|
|
33
|
-
.description("List all your intents")
|
|
34
|
-
.action(async () => {
|
|
35
|
-
requireAuth();
|
|
36
|
-
const spinner = ora("Fetching intents...").start();
|
|
37
|
-
try {
|
|
38
|
-
const intents = await apiGet("/api/pay/intent");
|
|
39
|
-
spinner.stop();
|
|
40
|
-
// Sync active intents to cache, remove stale ones
|
|
41
|
-
const activeNicks = new Set();
|
|
42
|
-
for (const intent of intents) {
|
|
43
|
-
if (intent.status === "active" && typeof intent.nick === "string") {
|
|
44
|
-
activeNicks.add(intent.nick);
|
|
45
|
-
setConfigValue(`intents.${intent.nick}`, JSON.stringify(intent));
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
console.log(JSON.stringify(intents, null, 2));
|
|
49
|
-
}
|
|
50
|
-
catch (err) {
|
|
51
|
-
spinner.fail("Failed to list intents");
|
|
52
|
-
console.error(chalk.red(String(err)));
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
intentCommand
|
|
57
|
-
.command("revoke")
|
|
58
|
-
.description("Revoke an active intent")
|
|
59
|
-
.requiredOption("--nick <nick>", "Intent nick")
|
|
60
|
-
.action(async (opts) => {
|
|
61
|
-
requireAuth();
|
|
62
|
-
const spinner = ora(`Revoking intent ${opts.nick}...`).start();
|
|
63
|
-
try {
|
|
64
|
-
const res = await apiPost(`/api/pay/intent/${encodeURIComponent(opts.nick)}/revoke`, {});
|
|
65
|
-
spinner.stop();
|
|
66
|
-
// Remove from cache
|
|
67
|
-
setConfigValue(`intents.${opts.nick}`, "");
|
|
68
|
-
console.log(JSON.stringify(res, null, 2));
|
|
69
|
-
}
|
|
70
|
-
catch (err) {
|
|
71
|
-
spinner.fail("Failed to revoke intent");
|
|
72
|
-
console.error(chalk.red(String(err)));
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
intentCommand
|
|
77
|
-
.command("propose")
|
|
78
|
-
.description("Generate an intent creation URL for the user to authorize in the browser")
|
|
79
|
-
.requiredOption("--nick <nick>", "Short identifier for the intent")
|
|
80
|
-
.requiredOption("--agents <slugs>", "Comma-separated merchant agent slugs (e.g. @x~starbucks)")
|
|
81
|
-
.requiredOption("--max-amount <dollars>", "Max amount per transaction in dollars")
|
|
82
|
-
.requiredOption("--prompt-playback <text>", "Human-readable description of the intent")
|
|
83
|
-
.option("--currency <code>", "Currency code", "USD")
|
|
84
|
-
.option("--recurring <type>", "Recurring type: once, daily, weekly, monthly", "once")
|
|
85
|
-
.option("--budget <dollars>", "Lifetime budget in dollars")
|
|
86
|
-
.option("--expires <date>", "Expiry date (ISO 8601)")
|
|
87
|
-
.action(async (opts) => {
|
|
88
|
-
const cfg = requireAuth();
|
|
89
|
-
const username = cfg.username;
|
|
90
|
-
if (!username) {
|
|
91
|
-
console.error(chalk.red("No username found. Please log in again."));
|
|
92
|
-
process.exit(1);
|
|
93
|
-
}
|
|
94
|
-
const baseUrl = cfg.apiUrl ?? "https://web42-network.vercel.app";
|
|
95
|
-
const params = new URLSearchParams({
|
|
96
|
-
nick: opts.nick,
|
|
97
|
-
agents: opts.agents,
|
|
98
|
-
max_amount: opts.maxAmount,
|
|
99
|
-
currency: opts.currency,
|
|
100
|
-
recurring: opts.recurring,
|
|
101
|
-
prompt_playback: opts.promptPlayback,
|
|
102
|
-
});
|
|
103
|
-
if (opts.budget)
|
|
104
|
-
params.set("budget", opts.budget);
|
|
105
|
-
if (opts.expires)
|
|
106
|
-
params.set("expires_at", opts.expires);
|
|
107
|
-
const url = `${baseUrl}/@${username}/intents/create?${params.toString()}`;
|
|
108
|
-
console.log(JSON.stringify({ url }, null, 2));
|
|
109
|
-
});
|
|
110
|
-
// ─── Checkout ─────────────────────────────────────────────
|
|
111
|
-
const checkoutCommand = new Command("checkout")
|
|
112
|
-
.description("Execute a payment against a matching intent (no human needed)")
|
|
113
|
-
.requiredOption("--tx <id>", "Transaction ID from tx-store")
|
|
114
|
-
.requiredOption("--intent <nick>", "Intent nick to use")
|
|
115
|
-
.action(async (opts) => {
|
|
116
|
-
requireAuth();
|
|
117
|
-
const tx = getTx(opts.tx);
|
|
118
|
-
if (!tx) {
|
|
119
|
-
console.error(chalk.red(`Transaction ${opts.tx} not found. Run: w42 pay list`));
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
const spinner = ora("Processing checkout...").start();
|
|
123
|
-
try {
|
|
124
|
-
const res = await apiPost("/api/pay/checkout", {
|
|
125
|
-
cart: tx.cartMandate,
|
|
126
|
-
agent_slug: tx.agentSlug,
|
|
127
|
-
intent_nick: opts.intent,
|
|
128
|
-
});
|
|
129
|
-
spinner.stop();
|
|
130
|
-
// Store the payment mandate on the tx
|
|
131
|
-
if (res.payment_mandate) {
|
|
132
|
-
updateTx(opts.tx, {
|
|
133
|
-
paymentMandate: res.payment_mandate,
|
|
134
|
-
status: "approved",
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
console.log(JSON.stringify({ tx: opts.tx, ...res }, null, 2));
|
|
138
|
-
}
|
|
139
|
-
catch (err) {
|
|
140
|
-
spinner.fail("Checkout failed");
|
|
141
|
-
console.error(chalk.red(String(err)));
|
|
142
|
-
process.exit(1);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
// ─── Sign (payment session for human approval) ───────────
|
|
146
|
-
const signCommand = new Command("sign").description("Create a payment session for human approval");
|
|
147
|
-
signCommand
|
|
148
|
-
.command("create")
|
|
149
|
-
.description("Create a new payment session for human approval")
|
|
150
|
-
.requiredOption("--tx <id>", "Transaction ID from tx-store")
|
|
151
|
-
.action(async (opts) => {
|
|
152
|
-
requireAuth();
|
|
153
|
-
const tx = getTx(opts.tx);
|
|
154
|
-
if (!tx) {
|
|
155
|
-
console.error(chalk.red(`Transaction ${opts.tx} not found. Run: w42 pay list`));
|
|
156
|
-
process.exit(1);
|
|
157
|
-
}
|
|
158
|
-
// Extract total from stored cart
|
|
159
|
-
let totalCents = 0;
|
|
160
|
-
let currency = "usd";
|
|
161
|
-
try {
|
|
162
|
-
const contents = tx.cartMandate.contents;
|
|
163
|
-
const pr = contents?.payment_request;
|
|
164
|
-
const details = pr?.details;
|
|
165
|
-
const total = details?.total;
|
|
166
|
-
totalCents = Math.round(total.amount.value * 100);
|
|
167
|
-
currency = total.amount.currency.toLowerCase();
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
console.error(chalk.red("Could not extract total from stored cart"));
|
|
171
|
-
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
const spinner = ora("Creating payment session...").start();
|
|
174
|
-
try {
|
|
175
|
-
const res = await apiPost("/api/pay/session", {
|
|
176
|
-
agent_slug: tx.agentSlug,
|
|
177
|
-
cart: tx.cartMandate,
|
|
178
|
-
total_cents: totalCents,
|
|
179
|
-
currency,
|
|
180
|
-
});
|
|
181
|
-
spinner.stop();
|
|
182
|
-
updateTx(opts.tx, {
|
|
183
|
-
sessionCode: res.code,
|
|
184
|
-
signingUrl: res.signing_url,
|
|
185
|
-
status: "session_created",
|
|
186
|
-
});
|
|
187
|
-
console.log(JSON.stringify({ tx: opts.tx, signing_url: res.signing_url }, null, 2));
|
|
188
|
-
}
|
|
189
|
-
catch (err) {
|
|
190
|
-
spinner.fail("Failed to create session");
|
|
191
|
-
console.error(chalk.red(String(err)));
|
|
192
|
-
process.exit(1);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
signCommand
|
|
196
|
-
.command("get")
|
|
197
|
-
.description("Check the status of a payment session")
|
|
198
|
-
.argument("<tx_id>", "Transaction ID")
|
|
199
|
-
.action(async (txId) => {
|
|
200
|
-
requireAuth();
|
|
201
|
-
const tx = getTx(txId);
|
|
202
|
-
if (!tx) {
|
|
203
|
-
console.error(chalk.red(`Transaction ${txId} not found. Run: w42 pay list`));
|
|
204
|
-
process.exit(1);
|
|
205
|
-
}
|
|
206
|
-
if (!tx.sessionCode) {
|
|
207
|
-
console.error(chalk.red(`No session created yet. Run: w42 pay sign create --tx ${txId}`));
|
|
208
|
-
process.exit(1);
|
|
209
|
-
}
|
|
210
|
-
const spinner = ora("Fetching session...").start();
|
|
211
|
-
try {
|
|
212
|
-
const res = await apiGet(`/api/pay/session/${encodeURIComponent(tx.sessionCode)}`);
|
|
213
|
-
spinner.stop();
|
|
214
|
-
// If session is completed, store the payment mandate
|
|
215
|
-
if (res.status === "completed" && res.payment_token) {
|
|
216
|
-
updateTx(txId, {
|
|
217
|
-
paymentMandate: res.payment_mandate ?? {
|
|
218
|
-
payment_mandate_contents: {},
|
|
219
|
-
user_authorization: res.payment_token,
|
|
220
|
-
},
|
|
221
|
-
status: "approved",
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
console.log(JSON.stringify({ tx: txId, ...res }, null, 2));
|
|
225
|
-
}
|
|
226
|
-
catch (err) {
|
|
227
|
-
spinner.fail("Failed to fetch session");
|
|
228
|
-
console.error(chalk.red(String(err)));
|
|
229
|
-
process.exit(1);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
// ─── List (transactions) ──────────────────────────────────
|
|
233
|
-
const listCommand = new Command("list")
|
|
234
|
-
.description("List local payment transactions")
|
|
235
|
-
.option("--status <status>", "Filter by status (cart_received, session_created, approved, sent)")
|
|
236
|
-
.action((opts) => {
|
|
237
|
-
const txs = listTxs(opts.status);
|
|
238
|
-
if (txs.length === 0) {
|
|
239
|
-
console.log(chalk.dim("No transactions found."));
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
for (const tx of txs) {
|
|
243
|
-
const cart = tx.cartMandate;
|
|
244
|
-
const contents = cart?.contents;
|
|
245
|
-
const pr = contents?.payment_request;
|
|
246
|
-
const details = pr?.details;
|
|
247
|
-
const total = details?.total;
|
|
248
|
-
const amount = total?.amount
|
|
249
|
-
? `${total.amount.currency} ${total.amount.value?.toFixed(2)}`
|
|
250
|
-
: "?";
|
|
251
|
-
console.log(`${chalk.cyan(tx.id)} ${chalk.dim(tx.status.padEnd(16))} ${amount} ${chalk.dim(tx.agentSlug)}`);
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
// ─── Root pay command ─────────────────────────────────────
|
|
255
|
-
export const payCommand = new Command("pay")
|
|
256
|
-
.description("AP2 payment mandates — intents, checkout, signing")
|
|
257
|
-
.addCommand(intentCommand)
|
|
258
|
-
.addCommand(checkoutCommand)
|
|
259
|
-
.addCommand(signCommand)
|
|
260
|
-
.addCommand(listCommand);
|