run402 1.38.0 → 1.40.0
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/lib/agent.mjs +16 -15
- package/lib/ai.mjs +21 -33
- package/lib/allowance.mjs +41 -16
- package/lib/apps.mjs +71 -79
- package/lib/auth.mjs +27 -66
- package/lib/billing.mjs +37 -47
- package/lib/blob.mjs +37 -35
- package/lib/contracts.mjs +82 -193
- package/lib/domains.mjs +30 -34
- package/lib/email.mjs +94 -344
- package/lib/functions.mjs +77 -79
- package/lib/image.mjs +13 -14
- package/lib/message.mjs +11 -10
- package/lib/projects.mjs +121 -90
- package/lib/sdk-errors.mjs +45 -0
- package/lib/sdk.mjs +14 -0
- package/lib/secrets.mjs +18 -26
- package/lib/sender-domain.mjs +28 -45
- package/lib/service.mjs +16 -19
- package/lib/sites.mjs +24 -20
- package/lib/subdomains.mjs +22 -29
- package/lib/tier.mjs +10 -24
- package/lib/webhooks.mjs +32 -129
- package/package.json +1 -1
- package/lib/paid-fetch.mjs +0 -107
package/lib/webhooks.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveProjectId } from "./config.mjs";
|
|
2
|
+
import { getSdk } from "./sdk.mjs";
|
|
3
|
+
import { reportSdkError } from "./sdk-errors.mjs";
|
|
2
4
|
|
|
3
5
|
const HELP = `run402 email webhooks — Manage mailbox webhooks
|
|
4
6
|
|
|
@@ -26,39 +28,11 @@ const SUB_HELP = {
|
|
|
26
28
|
|
|
27
29
|
Usage:
|
|
28
30
|
run402 email webhooks update <webhook_id> [--url <url>] [--events <e1,e2>] [--project <id>]
|
|
29
|
-
|
|
30
|
-
Arguments:
|
|
31
|
-
<webhook_id> Webhook ID to update
|
|
32
|
-
|
|
33
|
-
Options:
|
|
34
|
-
--url <url> New delivery URL for the webhook
|
|
35
|
-
--events <e1,e2> Comma-separated event list to replace the current events
|
|
36
|
-
Valid: delivery, bounced, complained, reply_received
|
|
37
|
-
--project <id> Project ID (defaults to the active project)
|
|
38
|
-
|
|
39
|
-
Notes:
|
|
40
|
-
- Provide at least one of --url or --events
|
|
41
|
-
|
|
42
|
-
Examples:
|
|
43
|
-
run402 email webhooks update whk_123 --url https://new.example.com/hook
|
|
44
|
-
run402 email webhooks update whk_123 --events delivery,bounced
|
|
45
31
|
`,
|
|
46
32
|
register: `run402 email webhooks register — Register a new webhook
|
|
47
33
|
|
|
48
34
|
Usage:
|
|
49
35
|
run402 email webhooks register --url <url> --events <e1,e2> [--project <id>]
|
|
50
|
-
|
|
51
|
-
Options:
|
|
52
|
-
--url <url> Delivery URL for the webhook (required)
|
|
53
|
-
--events <e1,e2> Comma-separated event list (required)
|
|
54
|
-
Valid: delivery, bounced, complained, reply_received
|
|
55
|
-
--project <id> Project ID (defaults to the active project)
|
|
56
|
-
|
|
57
|
-
Examples:
|
|
58
|
-
run402 email webhooks register --url https://example.com/hook \\
|
|
59
|
-
--events delivery,bounced
|
|
60
|
-
run402 email webhooks register --url https://example.com/hook \\
|
|
61
|
-
--events reply_received --project proj123
|
|
62
36
|
`,
|
|
63
37
|
};
|
|
64
38
|
|
|
@@ -69,53 +43,14 @@ function parseFlag(args, flag) {
|
|
|
69
43
|
return null;
|
|
70
44
|
}
|
|
71
45
|
|
|
72
|
-
async function resolveMailboxId(projectId, serviceKey) {
|
|
73
|
-
const store = loadKeyStore();
|
|
74
|
-
const proj = store.projects[projectId];
|
|
75
|
-
if (proj && proj.mailbox_id) return proj.mailbox_id;
|
|
76
|
-
|
|
77
|
-
const res = await fetch(`${API}/mailboxes/v1`, {
|
|
78
|
-
headers: { "Authorization": `Bearer ${serviceKey}` },
|
|
79
|
-
});
|
|
80
|
-
if (!res.ok) {
|
|
81
|
-
const data = await res.json().catch(() => ({}));
|
|
82
|
-
throw Object.assign(new Error("Failed to resolve mailbox"), { http: res.status, ...data });
|
|
83
|
-
}
|
|
84
|
-
const body = await res.json();
|
|
85
|
-
const mailboxes = body.mailboxes || body;
|
|
86
|
-
if (!Array.isArray(mailboxes) || mailboxes.length === 0) {
|
|
87
|
-
throw new Error("No mailbox found. Run: run402 email create <slug>");
|
|
88
|
-
}
|
|
89
|
-
const mb = mailboxes[0];
|
|
90
|
-
updateProject(projectId, { mailbox_id: mb.mailbox_id, mailbox_address: mb.address });
|
|
91
|
-
return mb.mailbox_id;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function requireMailboxId(projectId, serviceKey) {
|
|
95
|
-
try {
|
|
96
|
-
return await resolveMailboxId(projectId, serviceKey);
|
|
97
|
-
} catch (err) {
|
|
98
|
-
const out = { status: "error", message: err.message };
|
|
99
|
-
if (err.http) out.http = err.http;
|
|
100
|
-
console.error(JSON.stringify(out));
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
46
|
async function list(args) {
|
|
106
47
|
const projectId = resolveProjectId(parseFlag(args, "--project"));
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
});
|
|
113
|
-
const data = await res.json();
|
|
114
|
-
if (!res.ok) {
|
|
115
|
-
console.error(JSON.stringify({ status: "error", http: res.status, ...data }));
|
|
116
|
-
process.exit(1);
|
|
48
|
+
try {
|
|
49
|
+
const data = await getSdk().email.webhooks.list(projectId);
|
|
50
|
+
console.log(JSON.stringify(data, null, 2));
|
|
51
|
+
} catch (err) {
|
|
52
|
+
reportSdkError(err);
|
|
117
53
|
}
|
|
118
|
-
console.log(JSON.stringify(data, null, 2));
|
|
119
54
|
}
|
|
120
55
|
|
|
121
56
|
async function get(args) {
|
|
@@ -126,23 +61,16 @@ async function get(args) {
|
|
|
126
61
|
else if (!args[i].startsWith("--") && !webhookId) { webhookId = args[i]; }
|
|
127
62
|
}
|
|
128
63
|
const projectId = resolveProjectId(projectOpt);
|
|
129
|
-
const p = findProject(projectId);
|
|
130
|
-
|
|
131
64
|
if (!webhookId) {
|
|
132
65
|
console.error(JSON.stringify({ status: "error", message: "Missing webhook_id. Usage: run402 email webhooks get <webhook_id>" }));
|
|
133
66
|
process.exit(1);
|
|
134
67
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const data = await res.json();
|
|
141
|
-
if (!res.ok) {
|
|
142
|
-
console.error(JSON.stringify({ status: "error", http: res.status, ...data }));
|
|
143
|
-
process.exit(1);
|
|
68
|
+
try {
|
|
69
|
+
const data = await getSdk().email.webhooks.get(projectId, webhookId);
|
|
70
|
+
console.log(JSON.stringify(data, null, 2));
|
|
71
|
+
} catch (err) {
|
|
72
|
+
reportSdkError(err);
|
|
144
73
|
}
|
|
145
|
-
console.log(JSON.stringify(data, null, 2));
|
|
146
74
|
}
|
|
147
75
|
|
|
148
76
|
async function del(args) {
|
|
@@ -153,25 +81,16 @@ async function del(args) {
|
|
|
153
81
|
else if (!args[i].startsWith("--") && !webhookId) { webhookId = args[i]; }
|
|
154
82
|
}
|
|
155
83
|
const projectId = resolveProjectId(projectOpt);
|
|
156
|
-
const p = findProject(projectId);
|
|
157
|
-
|
|
158
84
|
if (!webhookId) {
|
|
159
85
|
console.error(JSON.stringify({ status: "error", message: "Missing webhook_id. Usage: run402 email webhooks delete <webhook_id>" }));
|
|
160
86
|
process.exit(1);
|
|
161
87
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
});
|
|
168
|
-
if (!res.ok) {
|
|
169
|
-
let errBody;
|
|
170
|
-
try { errBody = await res.json(); } catch { errBody = {}; }
|
|
171
|
-
console.error(JSON.stringify({ status: "error", http: res.status, ...errBody }));
|
|
172
|
-
process.exit(1);
|
|
88
|
+
try {
|
|
89
|
+
await getSdk().email.webhooks.delete(projectId, webhookId);
|
|
90
|
+
console.log(JSON.stringify({ status: "ok", webhook_id: webhookId, deleted: true }));
|
|
91
|
+
} catch (err) {
|
|
92
|
+
reportSdkError(err);
|
|
173
93
|
}
|
|
174
|
-
console.log(JSON.stringify({ status: "ok", webhook_id: webhookId, deleted: true }));
|
|
175
94
|
}
|
|
176
95
|
|
|
177
96
|
async function update(args) {
|
|
@@ -186,8 +105,6 @@ async function update(args) {
|
|
|
186
105
|
else if (!args[i].startsWith("--") && !webhookId) { webhookId = args[i]; }
|
|
187
106
|
}
|
|
188
107
|
const projectId = resolveProjectId(projectOpt);
|
|
189
|
-
const p = findProject(projectId);
|
|
190
|
-
|
|
191
108
|
if (!webhookId) {
|
|
192
109
|
console.error(JSON.stringify({ status: "error", message: "Missing webhook_id. Usage: run402 email webhooks update <webhook_id> [--url <url>] [--events <e1,e2>]" }));
|
|
193
110
|
process.exit(1);
|
|
@@ -197,22 +114,15 @@ async function update(args) {
|
|
|
197
114
|
process.exit(1);
|
|
198
115
|
}
|
|
199
116
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
body: JSON.stringify(body),
|
|
209
|
-
});
|
|
210
|
-
const data = await res.json();
|
|
211
|
-
if (!res.ok) {
|
|
212
|
-
console.error(JSON.stringify({ status: "error", http: res.status, ...data }));
|
|
213
|
-
process.exit(1);
|
|
117
|
+
try {
|
|
118
|
+
const data = await getSdk().email.webhooks.update(projectId, webhookId, {
|
|
119
|
+
url: url ?? undefined,
|
|
120
|
+
events: eventsRaw ? eventsRaw.split(",").map((e) => e.trim()) : undefined,
|
|
121
|
+
});
|
|
122
|
+
console.log(JSON.stringify({ status: "ok", ...data }));
|
|
123
|
+
} catch (err) {
|
|
124
|
+
reportSdkError(err);
|
|
214
125
|
}
|
|
215
|
-
console.log(JSON.stringify({ status: "ok", ...data }));
|
|
216
126
|
}
|
|
217
127
|
|
|
218
128
|
async function register(args) {
|
|
@@ -220,7 +130,6 @@ async function register(args) {
|
|
|
220
130
|
const eventsRaw = parseFlag(args, "--events");
|
|
221
131
|
const projectOpt = parseFlag(args, "--project");
|
|
222
132
|
const projectId = resolveProjectId(projectOpt);
|
|
223
|
-
const p = findProject(projectId);
|
|
224
133
|
|
|
225
134
|
if (!url) {
|
|
226
135
|
console.error(JSON.stringify({ status: "error", message: "Missing --url. Usage: run402 email webhooks register --url <url> --events <e1,e2>" }));
|
|
@@ -231,19 +140,13 @@ async function register(args) {
|
|
|
231
140
|
process.exit(1);
|
|
232
141
|
}
|
|
233
142
|
|
|
234
|
-
const events = eventsRaw.split(",").map(e => e.trim());
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
});
|
|
241
|
-
const data = await res.json();
|
|
242
|
-
if (!res.ok) {
|
|
243
|
-
console.error(JSON.stringify({ status: "error", http: res.status, ...data }));
|
|
244
|
-
process.exit(1);
|
|
143
|
+
const events = eventsRaw.split(",").map((e) => e.trim());
|
|
144
|
+
try {
|
|
145
|
+
const data = await getSdk().email.webhooks.register(projectId, { url, events });
|
|
146
|
+
console.log(JSON.stringify({ status: "ok", ...data }));
|
|
147
|
+
} catch (err) {
|
|
148
|
+
reportSdkError(err);
|
|
245
149
|
}
|
|
246
|
-
console.log(JSON.stringify({ status: "ok", ...data }));
|
|
247
150
|
}
|
|
248
151
|
|
|
249
152
|
export async function run(sub, args) {
|
package/package.json
CHANGED
package/lib/paid-fetch.mjs
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared payment wrapper for CLI commands that need paid fetch.
|
|
3
|
-
* Branches on allowance rail:
|
|
4
|
-
* - "mpp": uses mppx.fetch (Tempo pathUSD)
|
|
5
|
-
* - "x402" (default): uses @x402/fetch (Base USDC)
|
|
6
|
-
*
|
|
7
|
-
* Checks on-chain balances at setup time and selects funded networks.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { readAllowance, ALLOWANCE_FILE } from "./config.mjs";
|
|
11
|
-
import { existsSync } from "fs";
|
|
12
|
-
|
|
13
|
-
const USDC_ABI = [{ name: "balanceOf", type: "function", stateMutability: "view", inputs: [{ name: "account", type: "address" }], outputs: [{ name: "", type: "uint256" }] }];
|
|
14
|
-
const USDC_MAINNET = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
15
|
-
const USDC_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
|
|
16
|
-
const PATH_USD = "0x20c0000000000000000000000000000000000000";
|
|
17
|
-
const TEMPO_RPC = "https://rpc.moderato.tempo.xyz/";
|
|
18
|
-
|
|
19
|
-
async function checkBalance(publicClient, tokenAddress, walletAddress) {
|
|
20
|
-
try {
|
|
21
|
-
const raw = await publicClient.readContract({
|
|
22
|
-
address: tokenAddress,
|
|
23
|
-
abi: USDC_ABI,
|
|
24
|
-
functionName: "balanceOf",
|
|
25
|
-
args: [walletAddress],
|
|
26
|
-
});
|
|
27
|
-
return Number(raw);
|
|
28
|
-
} catch {
|
|
29
|
-
return 0;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export async function setupPaidFetch() {
|
|
34
|
-
if (!existsSync(ALLOWANCE_FILE)) {
|
|
35
|
-
console.error(JSON.stringify({ status: "error", message: "No agent allowance found. Run: run402 allowance create && run402 allowance fund" }));
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
const allowance = readAllowance();
|
|
39
|
-
const { privateKeyToAccount } = await import("viem/accounts");
|
|
40
|
-
const account = privateKeyToAccount(allowance.privateKey);
|
|
41
|
-
|
|
42
|
-
if (allowance.rail === "mpp") {
|
|
43
|
-
const { createPublicClient, http, defineChain } = await import("viem");
|
|
44
|
-
const tempoModerato = defineChain({
|
|
45
|
-
id: 42431,
|
|
46
|
-
name: "Tempo Moderato",
|
|
47
|
-
nativeCurrency: { name: "pathUSD", symbol: "pathUSD", decimals: 6 },
|
|
48
|
-
rpcUrls: { default: { http: [TEMPO_RPC] } },
|
|
49
|
-
});
|
|
50
|
-
const tempoClient = createPublicClient({ chain: tempoModerato, transport: http() });
|
|
51
|
-
const balance = await checkBalance(tempoClient, PATH_USD, allowance.address);
|
|
52
|
-
if (balance === 0) {
|
|
53
|
-
console.error(JSON.stringify({
|
|
54
|
-
status: "error",
|
|
55
|
-
message: `No pathUSD balance on Tempo Moderato (0). Fund your wallet: run402 allowance fund`,
|
|
56
|
-
}));
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const { Mppx, tempo } = await import("mppx/client");
|
|
61
|
-
const mppx = Mppx.create({
|
|
62
|
-
polyfill: false,
|
|
63
|
-
methods: [tempo({ account })],
|
|
64
|
-
});
|
|
65
|
-
return mppx.fetch;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Default: x402
|
|
69
|
-
const { createPublicClient, http } = await import("viem");
|
|
70
|
-
const { base, baseSepolia } = await import("viem/chains");
|
|
71
|
-
const { x402Client, wrapFetchWithPayment } = await import("@x402/fetch");
|
|
72
|
-
const { ExactEvmScheme } = await import("@x402/evm/exact/client");
|
|
73
|
-
const { toClientEvmSigner } = await import("@x402/evm");
|
|
74
|
-
|
|
75
|
-
const mainnetClient = createPublicClient({ chain: base, transport: http() });
|
|
76
|
-
const sepoliaClient = createPublicClient({ chain: baseSepolia, transport: http() });
|
|
77
|
-
|
|
78
|
-
// Check balances in parallel
|
|
79
|
-
const [mainnetBalance, sepoliaBalance] = await Promise.all([
|
|
80
|
-
checkBalance(mainnetClient, USDC_MAINNET, allowance.address),
|
|
81
|
-
checkBalance(sepoliaClient, USDC_SEPOLIA, allowance.address),
|
|
82
|
-
]);
|
|
83
|
-
|
|
84
|
-
if (mainnetBalance === 0 && sepoliaBalance === 0) {
|
|
85
|
-
console.error(JSON.stringify({
|
|
86
|
-
status: "error",
|
|
87
|
-
message: `No USDC balance on any supported network (Base: $${(mainnetBalance / 1e6).toFixed(2)}, Base Sepolia: $${(sepoliaBalance / 1e6).toFixed(2)}). Fund your wallet or run: run402 allowance fund`,
|
|
88
|
-
}));
|
|
89
|
-
process.exit(1);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const client = new x402Client();
|
|
93
|
-
client.register("eip155:8453", new ExactEvmScheme(toClientEvmSigner(account, mainnetClient)));
|
|
94
|
-
client.register("eip155:84532", new ExactEvmScheme(toClientEvmSigner(account, sepoliaClient)));
|
|
95
|
-
|
|
96
|
-
// Policy: only allow networks where the wallet has funds
|
|
97
|
-
client.registerPolicy((_version, reqs) => {
|
|
98
|
-
const funded = reqs.filter((r) => {
|
|
99
|
-
if (r.network === "eip155:8453") return mainnetBalance > 0;
|
|
100
|
-
if (r.network === "eip155:84532") return sepoliaBalance > 0;
|
|
101
|
-
return false;
|
|
102
|
-
});
|
|
103
|
-
return funded.length > 0 ? funded : reqs;
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
return wrapFetchWithPayment(fetch, client);
|
|
107
|
-
}
|