@web42/w42 0.1.18 → 0.1.20
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 +1 -17
- package/dist/commands/pay.js +79 -74
- package/dist/commands/send.js +54 -35
- package/dist/utils/tx-store.d.ts +25 -0
- package/dist/utils/tx-store.js +52 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -95,23 +95,7 @@ web42 register https://my-agent.example.com --visibility private --tags "nlp,sum
|
|
|
95
95
|
|
|
96
96
|
### `web42 pay`
|
|
97
97
|
|
|
98
|
-
AP2 payment commands —
|
|
99
|
-
|
|
100
|
-
#### `web42 pay wallet`
|
|
101
|
-
|
|
102
|
-
View your wallet balance.
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
web42 pay wallet
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
#### `web42 pay wallet topup <amount>`
|
|
109
|
-
|
|
110
|
-
Add funds to your wallet. Amount is in dollars.
|
|
111
|
-
|
|
112
|
-
```bash
|
|
113
|
-
web42 pay wallet topup 50.00
|
|
114
|
-
```
|
|
98
|
+
AP2 payment commands — intents, checkout, and human signing.
|
|
115
99
|
|
|
116
100
|
#### `web42 pay intent propose`
|
|
117
101
|
|
package/dist/commands/pay.js
CHANGED
|
@@ -3,46 +3,7 @@ import { Command } from "commander";
|
|
|
3
3
|
import ora from "ora";
|
|
4
4
|
import { apiGet, apiPost } from "../utils/api.js";
|
|
5
5
|
import { requireAuth, setConfigValue, } from "../utils/config.js";
|
|
6
|
-
|
|
7
|
-
const walletCommand = new Command("wallet")
|
|
8
|
-
.description("View or top up your wallet balance")
|
|
9
|
-
.action(async () => {
|
|
10
|
-
requireAuth();
|
|
11
|
-
const spinner = ora("Fetching wallet...").start();
|
|
12
|
-
try {
|
|
13
|
-
const res = await apiGet("/api/pay/wallet");
|
|
14
|
-
spinner.stop();
|
|
15
|
-
console.log(JSON.stringify(res, null, 2));
|
|
16
|
-
}
|
|
17
|
-
catch (err) {
|
|
18
|
-
spinner.fail("Failed to fetch wallet");
|
|
19
|
-
console.error(chalk.red(String(err)));
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
walletCommand
|
|
24
|
-
.command("topup")
|
|
25
|
-
.description("Add funds to your wallet")
|
|
26
|
-
.argument("<amount>", "Amount in dollars (e.g. 50.00)")
|
|
27
|
-
.action(async (amountStr) => {
|
|
28
|
-
requireAuth();
|
|
29
|
-
const amountCents = Math.round(parseFloat(amountStr) * 100);
|
|
30
|
-
if (isNaN(amountCents) || amountCents <= 0) {
|
|
31
|
-
console.error(chalk.red("Amount must be a positive number"));
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
const spinner = ora("Topping up wallet...").start();
|
|
35
|
-
try {
|
|
36
|
-
const res = await apiPost("/api/pay/wallet/topup", { amount_cents: amountCents });
|
|
37
|
-
spinner.stop();
|
|
38
|
-
console.log(JSON.stringify(res, null, 2));
|
|
39
|
-
}
|
|
40
|
-
catch (err) {
|
|
41
|
-
spinner.fail("Failed to top up wallet");
|
|
42
|
-
console.error(chalk.red(String(err)));
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
6
|
+
import { getTx, listTxs, updateTx } from "../utils/tx-store.js";
|
|
46
7
|
// ─── Intent ───────────────────────────────────────────────
|
|
47
8
|
const intentCommand = new Command("intent").description("Manage payment intents");
|
|
48
9
|
intentCommand
|
|
@@ -149,28 +110,31 @@ intentCommand
|
|
|
149
110
|
// ─── Checkout ─────────────────────────────────────────────
|
|
150
111
|
const checkoutCommand = new Command("checkout")
|
|
151
112
|
.description("Execute a payment against a matching intent (no human needed)")
|
|
152
|
-
.requiredOption("--
|
|
153
|
-
.requiredOption("--agent <slug>", "Merchant agent slug")
|
|
113
|
+
.requiredOption("--tx <id>", "Transaction ID from tx-store")
|
|
154
114
|
.requiredOption("--intent <nick>", "Intent nick to use")
|
|
155
115
|
.action(async (opts) => {
|
|
156
116
|
requireAuth();
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
catch {
|
|
162
|
-
console.error(chalk.red("Invalid cart JSON"));
|
|
117
|
+
const tx = getTx(opts.tx);
|
|
118
|
+
if (!tx) {
|
|
119
|
+
console.error(chalk.red(`Transaction ${opts.tx} not found. Run: w42 pay list`));
|
|
163
120
|
process.exit(1);
|
|
164
121
|
}
|
|
165
122
|
const spinner = ora("Processing checkout...").start();
|
|
166
123
|
try {
|
|
167
124
|
const res = await apiPost("/api/pay/checkout", {
|
|
168
|
-
cart,
|
|
169
|
-
agent_slug:
|
|
125
|
+
cart: tx.cartMandate,
|
|
126
|
+
agent_slug: tx.agentSlug,
|
|
170
127
|
intent_nick: opts.intent,
|
|
171
128
|
});
|
|
172
129
|
spinner.stop();
|
|
173
|
-
|
|
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));
|
|
174
138
|
}
|
|
175
139
|
catch (err) {
|
|
176
140
|
spinner.fail("Checkout failed");
|
|
@@ -182,25 +146,20 @@ const checkoutCommand = new Command("checkout")
|
|
|
182
146
|
const signCommand = new Command("sign").description("Create a payment session for human approval");
|
|
183
147
|
signCommand
|
|
184
148
|
.command("create")
|
|
185
|
-
.description("Create a new payment session")
|
|
186
|
-
.requiredOption("--
|
|
187
|
-
.requiredOption("--agent <slug>", "Merchant agent slug")
|
|
149
|
+
.description("Create a new payment session for human approval")
|
|
150
|
+
.requiredOption("--tx <id>", "Transaction ID from tx-store")
|
|
188
151
|
.action(async (opts) => {
|
|
189
152
|
requireAuth();
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
catch {
|
|
195
|
-
console.error(chalk.red("Invalid cart JSON"));
|
|
153
|
+
const tx = getTx(opts.tx);
|
|
154
|
+
if (!tx) {
|
|
155
|
+
console.error(chalk.red(`Transaction ${opts.tx} not found. Run: w42 pay list`));
|
|
196
156
|
process.exit(1);
|
|
197
157
|
}
|
|
198
|
-
// Extract total from cart
|
|
158
|
+
// Extract total from stored cart
|
|
199
159
|
let totalCents = 0;
|
|
200
160
|
let currency = "usd";
|
|
201
161
|
try {
|
|
202
|
-
const
|
|
203
|
-
const contents = c.contents;
|
|
162
|
+
const contents = tx.cartMandate.contents;
|
|
204
163
|
const pr = contents?.payment_request;
|
|
205
164
|
const details = pr?.details;
|
|
206
165
|
const total = details?.total;
|
|
@@ -208,19 +167,24 @@ signCommand
|
|
|
208
167
|
currency = total.amount.currency.toLowerCase();
|
|
209
168
|
}
|
|
210
169
|
catch {
|
|
211
|
-
console.error(chalk.red("Could not extract total from cart"));
|
|
170
|
+
console.error(chalk.red("Could not extract total from stored cart"));
|
|
212
171
|
process.exit(1);
|
|
213
172
|
}
|
|
214
173
|
const spinner = ora("Creating payment session...").start();
|
|
215
174
|
try {
|
|
216
175
|
const res = await apiPost("/api/pay/session", {
|
|
217
|
-
agent_slug:
|
|
218
|
-
cart,
|
|
176
|
+
agent_slug: tx.agentSlug,
|
|
177
|
+
cart: tx.cartMandate,
|
|
219
178
|
total_cents: totalCents,
|
|
220
179
|
currency,
|
|
221
180
|
});
|
|
222
181
|
spinner.stop();
|
|
223
|
-
|
|
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));
|
|
224
188
|
}
|
|
225
189
|
catch (err) {
|
|
226
190
|
spinner.fail("Failed to create session");
|
|
@@ -231,14 +195,33 @@ signCommand
|
|
|
231
195
|
signCommand
|
|
232
196
|
.command("get")
|
|
233
197
|
.description("Check the status of a payment session")
|
|
234
|
-
.argument("<
|
|
235
|
-
.action(async (
|
|
198
|
+
.argument("<tx_id>", "Transaction ID")
|
|
199
|
+
.action(async (txId) => {
|
|
236
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
|
+
}
|
|
237
210
|
const spinner = ora("Fetching session...").start();
|
|
238
211
|
try {
|
|
239
|
-
const res = await apiGet(`/api/pay/session/${encodeURIComponent(
|
|
212
|
+
const res = await apiGet(`/api/pay/session/${encodeURIComponent(tx.sessionCode)}`);
|
|
240
213
|
spinner.stop();
|
|
241
|
-
|
|
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));
|
|
242
225
|
}
|
|
243
226
|
catch (err) {
|
|
244
227
|
spinner.fail("Failed to fetch session");
|
|
@@ -246,10 +229,32 @@ signCommand
|
|
|
246
229
|
process.exit(1);
|
|
247
230
|
}
|
|
248
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
|
+
});
|
|
249
254
|
// ─── Root pay command ─────────────────────────────────────
|
|
250
255
|
export const payCommand = new Command("pay")
|
|
251
|
-
.description("AP2 payment mandates —
|
|
252
|
-
.addCommand(walletCommand)
|
|
256
|
+
.description("AP2 payment mandates — intents, checkout, signing")
|
|
253
257
|
.addCommand(intentCommand)
|
|
254
258
|
.addCommand(checkoutCommand)
|
|
255
|
-
.addCommand(signCommand)
|
|
259
|
+
.addCommand(signCommand)
|
|
260
|
+
.addCommand(listCommand);
|
package/dist/commands/send.js
CHANGED
|
@@ -3,12 +3,14 @@ import chalk from "chalk";
|
|
|
3
3
|
import { Command } from "commander";
|
|
4
4
|
import ora from "ora";
|
|
5
5
|
import { v4 as uuidv4 } from "uuid";
|
|
6
|
+
import { isCartMandatePart, parseCartMandate } from "@web42/auth";
|
|
6
7
|
import { apiPost } from "../utils/api.js";
|
|
7
8
|
import { getConfig, getConfigValue, isTelemetryEnabled, requireAuth, setConfigValue } from "../utils/config.js";
|
|
9
|
+
import { getTx, saveTx, updateTx } from "../utils/tx-store.js";
|
|
8
10
|
function isUrl(s) {
|
|
9
11
|
return s.startsWith("http://") || s.startsWith("https://");
|
|
10
12
|
}
|
|
11
|
-
function printPart(part) {
|
|
13
|
+
function printPart(part, agentSlug) {
|
|
12
14
|
if (part.kind === "text") {
|
|
13
15
|
if (part.text)
|
|
14
16
|
process.stdout.write(part.text);
|
|
@@ -25,6 +27,24 @@ function printPart(part) {
|
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
else if (part.kind === "data") {
|
|
30
|
+
// Detect AP2 CartMandate parts and auto-store them
|
|
31
|
+
if (isCartMandatePart(part)) {
|
|
32
|
+
const cart = parseCartMandate(part);
|
|
33
|
+
if (cart) {
|
|
34
|
+
const total = cart.contents.payment_request.details.total;
|
|
35
|
+
const txId = saveTx({
|
|
36
|
+
cartMandate: cart,
|
|
37
|
+
agentSlug: agentSlug ?? "unknown",
|
|
38
|
+
});
|
|
39
|
+
console.log(chalk.cyan(`\n[CartMandate] ${txId}`));
|
|
40
|
+
for (const item of cart.contents.payment_request.details.displayItems) {
|
|
41
|
+
console.log(` ${item.label}: ${item.amount.currency} ${item.amount.value.toFixed(2)}`);
|
|
42
|
+
}
|
|
43
|
+
console.log(chalk.bold(` Total: ${total.amount.currency} ${total.amount.value.toFixed(2)}`));
|
|
44
|
+
console.log(chalk.dim(`\nTo pay: w42 pay sign create --tx ${txId}`));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
28
48
|
process.stdout.write("\n" + JSON.stringify(part.data, null, 2) + "\n");
|
|
29
49
|
}
|
|
30
50
|
}
|
|
@@ -83,7 +103,7 @@ export const sendCommand = new Command("send")
|
|
|
83
103
|
.option("--new", "Start a new conversation (clears saved context)")
|
|
84
104
|
.option("--context <id>", "Use a specific context ID")
|
|
85
105
|
.option("--task-id <id>", "Reply to a specific task (e.g. one in input-required state)")
|
|
86
|
-
.option("--pay <
|
|
106
|
+
.option("--pay <tx_id>", "Attach PaymentMandate from a transaction (use tx ID from w42 pay list)")
|
|
87
107
|
.action(async (rawAgent, userMessage, opts) => {
|
|
88
108
|
// Normalize slug: @user/name → @user~name (DB format)
|
|
89
109
|
const agent = rawAgent.includes("/") && !isUrl(rawAgent)
|
|
@@ -193,40 +213,39 @@ export const sendCommand = new Command("send")
|
|
|
193
213
|
const startTime = Date.now();
|
|
194
214
|
let firstTokenMs;
|
|
195
215
|
try {
|
|
216
|
+
// Build payment part from tx-store if --pay is provided
|
|
217
|
+
const paymentParts = [];
|
|
218
|
+
if (opts.pay) {
|
|
219
|
+
const tx = getTx(opts.pay);
|
|
220
|
+
if (!tx) {
|
|
221
|
+
console.error(chalk.red(`Transaction ${opts.pay} not found. Run: w42 pay list`));
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
if (tx.status === "cart_received") {
|
|
225
|
+
console.error(chalk.red(`Session not created yet. Run: w42 pay sign create --tx ${opts.pay}`));
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
if (tx.status === "session_created") {
|
|
229
|
+
console.error(chalk.red(`Payment not yet approved. Run: w42 pay sign get ${opts.pay}`));
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
if (!tx.paymentMandate) {
|
|
233
|
+
console.error(chalk.red(`No payment mandate found on transaction ${opts.pay}`));
|
|
234
|
+
process.exit(1);
|
|
235
|
+
}
|
|
236
|
+
paymentParts.push({
|
|
237
|
+
kind: "data",
|
|
238
|
+
data: { "ap2.mandates.PaymentMandate": tx.paymentMandate },
|
|
239
|
+
});
|
|
240
|
+
updateTx(opts.pay, { status: "sent" });
|
|
241
|
+
}
|
|
196
242
|
const stream = client.sendMessageStream({
|
|
197
243
|
message: {
|
|
198
244
|
messageId: uuidv4(),
|
|
199
245
|
role: "user",
|
|
200
246
|
parts: [
|
|
201
247
|
{ kind: "text", text: userMessage },
|
|
202
|
-
...
|
|
203
|
-
? [
|
|
204
|
-
{
|
|
205
|
-
kind: "data",
|
|
206
|
-
data: {
|
|
207
|
-
"ap2.mandates.PaymentMandate": {
|
|
208
|
-
payment_mandate_contents: {
|
|
209
|
-
payment_mandate_id: "",
|
|
210
|
-
payment_details_id: "",
|
|
211
|
-
payment_details_total: {
|
|
212
|
-
label: "Total",
|
|
213
|
-
amount: { currency: "USD", value: 0 },
|
|
214
|
-
refund_period: 3,
|
|
215
|
-
},
|
|
216
|
-
payment_response: {
|
|
217
|
-
request_id: "",
|
|
218
|
-
method_name: "WEB42_WALLET",
|
|
219
|
-
details: {},
|
|
220
|
-
},
|
|
221
|
-
merchant_agent: agent,
|
|
222
|
-
timestamp: new Date().toISOString(),
|
|
223
|
-
},
|
|
224
|
-
user_authorization: opts.pay,
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
]
|
|
229
|
-
: []),
|
|
248
|
+
...paymentParts,
|
|
230
249
|
],
|
|
231
250
|
kind: "message",
|
|
232
251
|
contextId,
|
|
@@ -238,7 +257,7 @@ export const sendCommand = new Command("send")
|
|
|
238
257
|
if (firstTokenMs === undefined)
|
|
239
258
|
firstTokenMs = Date.now() - startTime;
|
|
240
259
|
for (const part of event.parts)
|
|
241
|
-
printPart(part);
|
|
260
|
+
printPart(part, agentKey);
|
|
242
261
|
}
|
|
243
262
|
else if (event.kind === "artifact-update") {
|
|
244
263
|
if (firstTokenMs === undefined)
|
|
@@ -248,12 +267,12 @@ export const sendCommand = new Command("send")
|
|
|
248
267
|
if (!event.append)
|
|
249
268
|
process.stdout.write("\n");
|
|
250
269
|
for (const part of event.artifact.parts ?? [])
|
|
251
|
-
printPart(part);
|
|
270
|
+
printPart(part, agentKey);
|
|
252
271
|
}
|
|
253
272
|
else if (event.kind === "status-update") {
|
|
254
273
|
if (event.status?.message) {
|
|
255
274
|
for (const part of event.status.message.parts ?? [])
|
|
256
|
-
printPart(part);
|
|
275
|
+
printPart(part, agentKey);
|
|
257
276
|
}
|
|
258
277
|
handleTaskState(event.status?.state, event.taskId);
|
|
259
278
|
}
|
|
@@ -265,11 +284,11 @@ export const sendCommand = new Command("send")
|
|
|
265
284
|
for (const artifact of event.artifacts ?? []) {
|
|
266
285
|
process.stdout.write("\n");
|
|
267
286
|
for (const part of artifact.parts ?? [])
|
|
268
|
-
printPart(part);
|
|
287
|
+
printPart(part, agentKey);
|
|
269
288
|
}
|
|
270
289
|
if (event.status?.message) {
|
|
271
290
|
for (const part of event.status.message.parts ?? [])
|
|
272
|
-
printPart(part);
|
|
291
|
+
printPart(part, agentKey);
|
|
273
292
|
}
|
|
274
293
|
handleTaskState(event.status?.state, event.id);
|
|
275
294
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local transaction store for AP2 payment flows.
|
|
3
|
+
*
|
|
4
|
+
* Tracks the lifecycle of a payment transaction:
|
|
5
|
+
* cart_received → session_created → approved → sent
|
|
6
|
+
*
|
|
7
|
+
* Stored in ~/.config/w42-transactions/config.json via `conf`.
|
|
8
|
+
*/
|
|
9
|
+
export interface StoredTransaction {
|
|
10
|
+
id: string;
|
|
11
|
+
cartMandate: Record<string, unknown>;
|
|
12
|
+
agentSlug: string;
|
|
13
|
+
sessionCode?: string;
|
|
14
|
+
signingUrl?: string;
|
|
15
|
+
paymentMandate?: Record<string, unknown>;
|
|
16
|
+
status: "cart_received" | "session_created" | "approved" | "sent";
|
|
17
|
+
createdAt: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function saveTx(opts: {
|
|
20
|
+
cartMandate: Record<string, unknown>;
|
|
21
|
+
agentSlug: string;
|
|
22
|
+
}): string;
|
|
23
|
+
export declare function getTx(id: string): StoredTransaction | null;
|
|
24
|
+
export declare function updateTx(id: string, updates: Partial<Omit<StoredTransaction, "id">>): void;
|
|
25
|
+
export declare function listTxs(status?: string): StoredTransaction[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local transaction store for AP2 payment flows.
|
|
3
|
+
*
|
|
4
|
+
* Tracks the lifecycle of a payment transaction:
|
|
5
|
+
* cart_received → session_created → approved → sent
|
|
6
|
+
*
|
|
7
|
+
* Stored in ~/.config/w42-transactions/config.json via `conf`.
|
|
8
|
+
*/
|
|
9
|
+
import Conf from "conf";
|
|
10
|
+
import crypto from "crypto";
|
|
11
|
+
// ─── Store ───────────────────────────────────────────────
|
|
12
|
+
const store = new Conf({
|
|
13
|
+
projectName: "w42-transactions",
|
|
14
|
+
defaults: { transactions: {} },
|
|
15
|
+
});
|
|
16
|
+
function generateId() {
|
|
17
|
+
return `tx_${crypto.randomBytes(4).toString("hex")}`;
|
|
18
|
+
}
|
|
19
|
+
// ─── Public API ──────────────────────────────────────────
|
|
20
|
+
export function saveTx(opts) {
|
|
21
|
+
const id = generateId();
|
|
22
|
+
const tx = {
|
|
23
|
+
id,
|
|
24
|
+
cartMandate: opts.cartMandate,
|
|
25
|
+
agentSlug: opts.agentSlug,
|
|
26
|
+
status: "cart_received",
|
|
27
|
+
createdAt: new Date().toISOString(),
|
|
28
|
+
};
|
|
29
|
+
const all = store.get("transactions");
|
|
30
|
+
all[id] = tx;
|
|
31
|
+
store.set("transactions", all);
|
|
32
|
+
return id;
|
|
33
|
+
}
|
|
34
|
+
export function getTx(id) {
|
|
35
|
+
const all = store.get("transactions");
|
|
36
|
+
return all[id] ?? null;
|
|
37
|
+
}
|
|
38
|
+
export function updateTx(id, updates) {
|
|
39
|
+
const all = store.get("transactions");
|
|
40
|
+
const tx = all[id];
|
|
41
|
+
if (!tx)
|
|
42
|
+
return;
|
|
43
|
+
Object.assign(tx, updates);
|
|
44
|
+
all[id] = tx;
|
|
45
|
+
store.set("transactions", all);
|
|
46
|
+
}
|
|
47
|
+
export function listTxs(status) {
|
|
48
|
+
const all = Object.values(store.get("transactions"));
|
|
49
|
+
if (!status)
|
|
50
|
+
return all;
|
|
51
|
+
return all.filter((tx) => tx.status === status);
|
|
52
|
+
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.20";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = "0.1.
|
|
1
|
+
export const CLI_VERSION = "0.1.20";
|