run402 2.48.0 → 3.0.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/README.md +3 -3
- package/cli.mjs +1 -1
- package/lib/contracts.mjs +74 -74
- package/lib/projects.mjs +14 -2
- package/lib/transfer.mjs +42 -7
- package/package.json +1 -1
- package/sdk/dist/namespaces/contracts.d.ts +38 -38
- package/sdk/dist/namespaces/contracts.d.ts.map +1 -1
- package/sdk/dist/namespaces/contracts.js +44 -44
- package/sdk/dist/namespaces/contracts.js.map +1 -1
- package/sdk/dist/namespaces/projects.d.ts +14 -1
- package/sdk/dist/namespaces/projects.d.ts.map +1 -1
- package/sdk/dist/namespaces/projects.js +17 -0
- package/sdk/dist/namespaces/projects.js.map +1 -1
- package/sdk/dist/namespaces/projects.types.d.ts +50 -0
- package/sdk/dist/namespaces/projects.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.d.ts +43 -3
- package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.js +5 -0
- package/sdk/dist/namespaces/transfers.js.map +1 -1
- package/sdk/dist/scoped.d.ts +10 -9
- package/sdk/dist/scoped.d.ts.map +1 -1
- package/sdk/dist/scoped.js +17 -14
- package/sdk/dist/scoped.js.map +1 -1
package/README.md
CHANGED
|
@@ -175,11 +175,11 @@ run402 image generate "a serif logo" --aspect square --output logo.png
|
|
|
175
175
|
|
|
176
176
|
$0.03 per image via x402.
|
|
177
177
|
|
|
178
|
-
### On-chain (KMS
|
|
178
|
+
### On-chain (KMS signers)
|
|
179
179
|
|
|
180
180
|
```bash
|
|
181
|
-
run402 contracts provision-
|
|
182
|
-
run402 contracts call
|
|
181
|
+
run402 contracts provision-signer --chain base-mainnet
|
|
182
|
+
run402 contracts call <project_id> <signer_id> --to 0x… --abi @abi.json --fn transfer --args '["0x…","1000000"]'
|
|
183
183
|
```
|
|
184
184
|
|
|
185
185
|
Private keys never leave AWS KMS. $0.04/day rental + $0.000005/call.
|
package/cli.mjs
CHANGED
|
@@ -48,7 +48,7 @@ Commands:
|
|
|
48
48
|
auth Manage project user authentication (magic link, passwords, settings)
|
|
49
49
|
sender-domain Manage custom email sender domain (register, status, remove)
|
|
50
50
|
billing Email organizations, Stripe tier checkout, email packs
|
|
51
|
-
contracts KMS
|
|
51
|
+
contracts KMS signers ($0.04/day rental + $0.000005/sign)
|
|
52
52
|
agent Manage agent identity (contact info)
|
|
53
53
|
operator Operator (human/email) session — login, then overview across your wallets
|
|
54
54
|
service Run402 service health and availability (status, health)
|
package/lib/contracts.mjs
CHANGED
|
@@ -9,49 +9,49 @@ import {
|
|
|
9
9
|
validateEvmAddress,
|
|
10
10
|
} from "./argparse.mjs";
|
|
11
11
|
|
|
12
|
-
const HELP = `run402 contracts — KMS-backed Ethereum
|
|
12
|
+
const HELP = `run402 contracts — KMS-backed Ethereum signers for smart-contract calls
|
|
13
13
|
|
|
14
|
-
Pricing: $0.04/day per
|
|
15
|
-
|
|
14
|
+
Pricing: $0.04/day per signer ($1.20/month) plus $0.000005 per contract call.
|
|
15
|
+
Signer creation requires $1.20 in cash credit (30 days of rent).
|
|
16
16
|
Non-custodial: see https://run402.com/humans/terms.html#non-custodial-kms-wallets
|
|
17
17
|
|
|
18
18
|
Usage:
|
|
19
19
|
run402 contracts <subcommand> [args...]
|
|
20
20
|
|
|
21
21
|
Subcommands:
|
|
22
|
-
provision-
|
|
23
|
-
Provision a KMS
|
|
24
|
-
get-
|
|
25
|
-
Get
|
|
26
|
-
list-
|
|
27
|
-
List all KMS
|
|
28
|
-
set-recovery <project_id> <
|
|
22
|
+
provision-signer <project_id> --chain <base-mainnet|base-sepolia> [--recovery 0x...]
|
|
23
|
+
Provision a KMS signer ($0.04/day, requires $1.20 prepay).
|
|
24
|
+
get-signer <project_id> <signer_id>
|
|
25
|
+
Get signer metadata + live native balance.
|
|
26
|
+
list-signers <project_id>
|
|
27
|
+
List all KMS signers for the project (includes deleted).
|
|
28
|
+
set-recovery <project_id> <signer_id> [--address 0x... | --clear]
|
|
29
29
|
Set/clear the optional recovery address.
|
|
30
|
-
set-alert <project_id> <
|
|
30
|
+
set-alert <project_id> <signer_id> --threshold-wei <n>
|
|
31
31
|
Set the low-balance alert threshold (in wei).
|
|
32
|
-
call <project_id> <
|
|
32
|
+
call <project_id> <signer_id> --to 0x... --abi <json> --fn <name> --args <json> [--value-wei <n>] [--idempotency-key <k>]
|
|
33
33
|
Submit a contract write call (chain gas + $0.000005 KMS sign fee).
|
|
34
|
-
deploy <project_id> <
|
|
34
|
+
deploy <project_id> <signer_id> --bytecode 0x... [--chain <base-mainnet|base-sepolia>] [--value-wei <n>] [--idempotency-key <k>]
|
|
35
35
|
Deploy a contract (chain gas + $0.000005 KMS sign fee). Returns deterministic CREATE address synchronously.
|
|
36
36
|
read --chain <chain> --to 0x... --abi <json> --fn <name> --args <json>
|
|
37
37
|
Read-only contract call (free).
|
|
38
38
|
status <project_id> <call_id>
|
|
39
39
|
Get call status, gas used, gas cost USD-micros, receipt.
|
|
40
|
-
drain <project_id> <
|
|
41
|
-
Drain native balance to a destination address. Works on suspended
|
|
42
|
-
delete <project_id> <
|
|
40
|
+
drain <project_id> <signer_id> --to 0x... --confirm
|
|
41
|
+
Drain native balance to a destination address. Works on suspended signers.
|
|
42
|
+
delete <project_id> <signer_id> --confirm
|
|
43
43
|
Schedule the KMS key for deletion (refused if balance >= dust).
|
|
44
44
|
|
|
45
45
|
Examples:
|
|
46
|
-
run402 contracts provision-
|
|
46
|
+
run402 contracts provision-signer proj_abc --chain base-mainnet
|
|
47
47
|
run402 contracts call proj_abc cwlt_xyz --to 0x1234... --abi '[{"type":"function","name":"ping","inputs":[],"outputs":[]}]' --fn ping --args '[]'
|
|
48
48
|
`;
|
|
49
49
|
|
|
50
50
|
const SUB_HELP = {
|
|
51
|
-
"provision-
|
|
51
|
+
"provision-signer": `run402 contracts provision-signer — Provision a KMS-backed signer
|
|
52
52
|
|
|
53
53
|
Usage:
|
|
54
|
-
run402 contracts provision-
|
|
54
|
+
run402 contracts provision-signer <project_id> --chain <chain> [options]
|
|
55
55
|
|
|
56
56
|
Arguments:
|
|
57
57
|
<project_id> Target project ID
|
|
@@ -59,39 +59,39 @@ Arguments:
|
|
|
59
59
|
Options:
|
|
60
60
|
--chain <chain> Required: base-mainnet or base-sepolia
|
|
61
61
|
--recovery 0x... Optional recovery address (can be set later)
|
|
62
|
-
--yes Skip confirmation when project already has a
|
|
62
|
+
--yes Skip confirmation when project already has a signer
|
|
63
63
|
`,
|
|
64
|
-
"set-recovery": `run402 contracts set-recovery — Set or clear the
|
|
64
|
+
"set-recovery": `run402 contracts set-recovery — Set or clear the signer recovery address
|
|
65
65
|
|
|
66
66
|
Usage:
|
|
67
|
-
run402 contracts set-recovery <project_id> <
|
|
67
|
+
run402 contracts set-recovery <project_id> <signer_id> [options]
|
|
68
68
|
`,
|
|
69
69
|
"set-alert": `run402 contracts set-alert — Set the low-balance alert threshold
|
|
70
70
|
|
|
71
71
|
Usage:
|
|
72
|
-
run402 contracts set-alert <project_id> <
|
|
72
|
+
run402 contracts set-alert <project_id> <signer_id> --threshold-wei <n>
|
|
73
73
|
`,
|
|
74
74
|
call: `run402 contracts call — Submit a contract write call
|
|
75
75
|
|
|
76
76
|
Usage:
|
|
77
|
-
run402 contracts call <project_id> <
|
|
77
|
+
run402 contracts call <project_id> <signer_id> --to 0x... --abi <json>
|
|
78
78
|
--fn <name> --args <json> [options]
|
|
79
79
|
`,
|
|
80
|
-
deploy: `run402 contracts deploy — Deploy a smart contract from a KMS
|
|
80
|
+
deploy: `run402 contracts deploy — Deploy a smart contract from a KMS signer
|
|
81
81
|
|
|
82
82
|
KMS-signs a contract-creation transaction (to: null + data: bytecode) and broadcasts.
|
|
83
|
-
Returns the deterministic CREATE address synchronously — known from (
|
|
83
|
+
Returns the deterministic CREATE address synchronously — known from (signer, nonce)
|
|
84
84
|
before the tx confirms. Cost: chain gas at-cost + $0.000005 KMS sign fee.
|
|
85
85
|
|
|
86
86
|
Usage:
|
|
87
|
-
run402 contracts deploy <project_id> <
|
|
87
|
+
run402 contracts deploy <project_id> <signer_id> --bytecode 0x... [options]
|
|
88
88
|
|
|
89
89
|
Options:
|
|
90
90
|
--bytecode 0x... Full creation calldata as 0x-prefixed hex (creation
|
|
91
91
|
bytecode + ABI-encoded constructor args, concatenated
|
|
92
92
|
client-side via viem/ethers). Required. ≤ 128 KB.
|
|
93
93
|
--chain <chain> base-mainnet (default) or base-sepolia. Must match
|
|
94
|
-
the
|
|
94
|
+
the signer's chain.
|
|
95
95
|
--value-wei <n> Optional native-token value in wei to attach.
|
|
96
96
|
--idempotency-key <k> Optional. Same key + same bytecode returns the
|
|
97
97
|
existing call without re-broadcasting.
|
|
@@ -108,38 +108,38 @@ Usage:
|
|
|
108
108
|
drain: `run402 contracts drain — Drain native balance to a destination address
|
|
109
109
|
|
|
110
110
|
Usage:
|
|
111
|
-
run402 contracts drain <project_id> <
|
|
111
|
+
run402 contracts drain <project_id> <signer_id> --to 0x... --confirm
|
|
112
112
|
`,
|
|
113
113
|
delete: `run402 contracts delete — Schedule the KMS key for deletion
|
|
114
114
|
|
|
115
115
|
Usage:
|
|
116
|
-
run402 contracts delete <project_id> <
|
|
116
|
+
run402 contracts delete <project_id> <signer_id> --confirm
|
|
117
117
|
`,
|
|
118
|
-
"get-
|
|
118
|
+
"get-signer": `run402 contracts get-signer — Get signer metadata + live balance
|
|
119
119
|
|
|
120
120
|
Usage:
|
|
121
|
-
run402 contracts get-
|
|
121
|
+
run402 contracts get-signer <project_id> <signer_id>
|
|
122
122
|
|
|
123
123
|
Arguments:
|
|
124
|
-
<project_id> Project ID that owns the
|
|
125
|
-
<
|
|
124
|
+
<project_id> Project ID that owns the signer
|
|
125
|
+
<signer_id> Signer ID (e.g. cwlt_abc123)
|
|
126
126
|
|
|
127
127
|
Examples:
|
|
128
|
-
run402 contracts get-
|
|
128
|
+
run402 contracts get-signer prj_abc123 cwlt_abc123
|
|
129
129
|
`,
|
|
130
|
-
"list-
|
|
130
|
+
"list-signers": `run402 contracts list-signers — List all KMS signers for a project
|
|
131
131
|
|
|
132
132
|
Usage:
|
|
133
|
-
run402 contracts list-
|
|
133
|
+
run402 contracts list-signers <project_id>
|
|
134
134
|
|
|
135
135
|
Arguments:
|
|
136
|
-
<project_id> Project ID to list
|
|
136
|
+
<project_id> Project ID to list signers for
|
|
137
137
|
|
|
138
138
|
Notes:
|
|
139
|
-
- Includes deleted
|
|
139
|
+
- Includes deleted signers
|
|
140
140
|
|
|
141
141
|
Examples:
|
|
142
|
-
run402 contracts list-
|
|
142
|
+
run402 contracts list-signers prj_abc123
|
|
143
143
|
`,
|
|
144
144
|
status: `run402 contracts status — Get a contract call's status and receipt
|
|
145
145
|
|
|
@@ -171,13 +171,13 @@ function validateWeiFlag(flag, value) {
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
async function
|
|
174
|
+
async function provisionSigner(projectId, args) {
|
|
175
175
|
const parsedArgs = normalizeArgv(args);
|
|
176
176
|
const valueFlags = ["--chain", "--recovery"];
|
|
177
177
|
assertKnownFlags(parsedArgs, [...valueFlags, "--yes", "--help", "-h"], valueFlags);
|
|
178
178
|
const extra = positionalArgs(parsedArgs, valueFlags);
|
|
179
179
|
if (extra.length > 0) {
|
|
180
|
-
fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts provision-
|
|
180
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts provision-signer: ${extra[0]}` });
|
|
181
181
|
}
|
|
182
182
|
const chain = flagValue(parsedArgs, "--chain");
|
|
183
183
|
if (!chain) {
|
|
@@ -189,22 +189,22 @@ async function provisionWallet(projectId, args) {
|
|
|
189
189
|
assertAllowedValue(chain, ["base-mainnet", "base-sepolia"], "--chain");
|
|
190
190
|
const recovery = flagValue(parsedArgs, "--recovery");
|
|
191
191
|
if (recovery) validateEvmAddress(recovery, "--recovery");
|
|
192
|
-
// Soft default of one
|
|
193
|
-
let
|
|
192
|
+
// Soft default of one signer — confirm if project already has one.
|
|
193
|
+
let activeSigners = null;
|
|
194
194
|
try {
|
|
195
|
-
const list = await getSdk().contracts.
|
|
196
|
-
|
|
195
|
+
const list = await getSdk().contracts.listSigners(projectId);
|
|
196
|
+
activeSigners = (list.signers || []).filter((s) => s.status === "active").length;
|
|
197
197
|
} catch { /* best-effort */ }
|
|
198
|
-
if (
|
|
198
|
+
if (activeSigners !== null && activeSigners >= 1 && !hasFlag(parsedArgs, "--yes")) {
|
|
199
199
|
fail({
|
|
200
200
|
code: "CONFIRMATION_REQUIRED",
|
|
201
|
-
message: `This project already has ${
|
|
202
|
-
details: {
|
|
201
|
+
message: `This project already has ${activeSigners} active signer(s). Adding another costs $0.04/day each ($1.20/month). Re-run with --yes to confirm.`,
|
|
202
|
+
details: { active_signers: activeSigners },
|
|
203
203
|
});
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
try {
|
|
207
|
-
const data = await getSdk().contracts.
|
|
207
|
+
const data = await getSdk().contracts.provisionSigner(projectId, {
|
|
208
208
|
chain,
|
|
209
209
|
recoveryAddress: recovery ?? undefined,
|
|
210
210
|
});
|
|
@@ -214,37 +214,37 @@ async function provisionWallet(projectId, args) {
|
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
async function
|
|
217
|
+
async function getSigner(projectId, signerId, args = []) {
|
|
218
218
|
const parsedArgs = normalizeArgv(args);
|
|
219
219
|
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
220
220
|
const extra = positionalArgs(parsedArgs);
|
|
221
221
|
if (extra.length > 0) {
|
|
222
|
-
fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts get-
|
|
222
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts get-signer: ${extra[0]}` });
|
|
223
223
|
}
|
|
224
224
|
try {
|
|
225
|
-
const data = await getSdk().contracts.
|
|
225
|
+
const data = await getSdk().contracts.getSigner(projectId, signerId);
|
|
226
226
|
console.log(JSON.stringify(data, null, 2));
|
|
227
227
|
} catch (err) {
|
|
228
228
|
reportSdkError(err);
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
async function
|
|
232
|
+
async function listSigners(projectId, args = []) {
|
|
233
233
|
const parsedArgs = normalizeArgv(args);
|
|
234
234
|
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
235
235
|
const extra = positionalArgs(parsedArgs);
|
|
236
236
|
if (extra.length > 0) {
|
|
237
|
-
fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts list-
|
|
237
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for contracts list-signers: ${extra[0]}` });
|
|
238
238
|
}
|
|
239
239
|
try {
|
|
240
|
-
const data = await getSdk().contracts.
|
|
240
|
+
const data = await getSdk().contracts.listSigners(projectId);
|
|
241
241
|
console.log(JSON.stringify(data, null, 2));
|
|
242
242
|
} catch (err) {
|
|
243
243
|
reportSdkError(err);
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
async function setRecovery(projectId,
|
|
247
|
+
async function setRecovery(projectId, signerId, args) {
|
|
248
248
|
const parsedArgs = normalizeArgv(args);
|
|
249
249
|
const valueFlags = ["--address"];
|
|
250
250
|
assertKnownFlags(parsedArgs, [...valueFlags, "--clear", "--help", "-h"], valueFlags);
|
|
@@ -265,14 +265,14 @@ async function setRecovery(projectId, walletId, args) {
|
|
|
265
265
|
}
|
|
266
266
|
if (address) validateEvmAddress(address, "--address");
|
|
267
267
|
try {
|
|
268
|
-
await getSdk().contracts.setRecovery(projectId,
|
|
269
|
-
console.log(JSON.stringify({
|
|
268
|
+
await getSdk().contracts.setRecovery(projectId, signerId, clear ? null : address);
|
|
269
|
+
console.log(JSON.stringify({ signer_id: signerId, recovery_address: clear ? null : address, updated: true }));
|
|
270
270
|
} catch (err) {
|
|
271
271
|
reportSdkError(err);
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
async function setAlert(projectId,
|
|
275
|
+
async function setAlert(projectId, signerId, args) {
|
|
276
276
|
const parsedArgs = normalizeArgv(args);
|
|
277
277
|
const valueFlags = ["--threshold-wei"];
|
|
278
278
|
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
@@ -286,14 +286,14 @@ async function setAlert(projectId, walletId, args) {
|
|
|
286
286
|
}
|
|
287
287
|
validateWeiFlag("--threshold-wei", threshold);
|
|
288
288
|
try {
|
|
289
|
-
await getSdk().contracts.setLowBalanceAlert(projectId,
|
|
290
|
-
console.log(JSON.stringify({
|
|
289
|
+
await getSdk().contracts.setLowBalanceAlert(projectId, signerId, threshold);
|
|
290
|
+
console.log(JSON.stringify({ signer_id: signerId, threshold_wei: threshold, updated: true }));
|
|
291
291
|
} catch (err) {
|
|
292
292
|
reportSdkError(err);
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
|
|
296
|
-
async function call(projectId,
|
|
296
|
+
async function call(projectId, signerId, args) {
|
|
297
297
|
const parsedArgs = normalizeArgv(args);
|
|
298
298
|
const valueFlags = ["--to", "--abi", "--fn", "--args", "--value-wei", "--chain", "--idempotency-key"];
|
|
299
299
|
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
@@ -322,7 +322,7 @@ async function call(projectId, walletId, args) {
|
|
|
322
322
|
validateEvmAddress(to, "--to");
|
|
323
323
|
try {
|
|
324
324
|
const data = await getSdk().contracts.call(projectId, {
|
|
325
|
-
|
|
325
|
+
signerId,
|
|
326
326
|
chain,
|
|
327
327
|
contractAddress: to,
|
|
328
328
|
abiFragment,
|
|
@@ -337,7 +337,7 @@ async function call(projectId, walletId, args) {
|
|
|
337
337
|
}
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
async function deploy(projectId,
|
|
340
|
+
async function deploy(projectId, signerId, args) {
|
|
341
341
|
const parsedArgs = normalizeArgv(args);
|
|
342
342
|
const valueFlags = ["--bytecode", "--value-wei", "--chain", "--idempotency-key"];
|
|
343
343
|
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
@@ -360,7 +360,7 @@ async function deploy(projectId, walletId, args) {
|
|
|
360
360
|
if (value !== null) validateWeiFlag("--value-wei", value);
|
|
361
361
|
try {
|
|
362
362
|
const data = await getSdk().contracts.deploy(projectId, {
|
|
363
|
-
|
|
363
|
+
signerId,
|
|
364
364
|
chain,
|
|
365
365
|
bytecode,
|
|
366
366
|
value: value ?? undefined,
|
|
@@ -424,7 +424,7 @@ async function status(projectId, callId, args = []) {
|
|
|
424
424
|
}
|
|
425
425
|
}
|
|
426
426
|
|
|
427
|
-
async function drain(projectId,
|
|
427
|
+
async function drain(projectId, signerId, args) {
|
|
428
428
|
const parsedArgs = normalizeArgv(args);
|
|
429
429
|
const valueFlags = ["--to"];
|
|
430
430
|
assertKnownFlags(parsedArgs, [...valueFlags, "--confirm", "--help", "-h"], valueFlags);
|
|
@@ -442,14 +442,14 @@ async function drain(projectId, walletId, args) {
|
|
|
442
442
|
}
|
|
443
443
|
validateEvmAddress(to, "--to");
|
|
444
444
|
try {
|
|
445
|
-
const data = await getSdk().contracts.drain(projectId,
|
|
445
|
+
const data = await getSdk().contracts.drain(projectId, signerId, to);
|
|
446
446
|
console.log(JSON.stringify(data, null, 2));
|
|
447
447
|
} catch (err) {
|
|
448
448
|
reportSdkError(err);
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
|
|
452
|
-
async function
|
|
452
|
+
async function deleteSigner(projectId, signerId, args) {
|
|
453
453
|
const parsedArgs = normalizeArgv(args);
|
|
454
454
|
assertKnownFlags(parsedArgs, ["--confirm", "--help", "-h"]);
|
|
455
455
|
const extra = positionalArgs(parsedArgs);
|
|
@@ -460,7 +460,7 @@ async function deleteWallet(projectId, walletId, args) {
|
|
|
460
460
|
fail({ code: "BAD_USAGE", message: "Required: --confirm" });
|
|
461
461
|
}
|
|
462
462
|
try {
|
|
463
|
-
const data = await getSdk().contracts.
|
|
463
|
+
const data = await getSdk().contracts.deleteSigner(projectId, signerId);
|
|
464
464
|
console.log(JSON.stringify(data, null, 2));
|
|
465
465
|
} catch (err) {
|
|
466
466
|
reportSdkError(err);
|
|
@@ -471,9 +471,9 @@ export async function run(sub, args) {
|
|
|
471
471
|
if (!sub || sub === "--help" || sub === "-h") { console.log(HELP); process.exit(0); }
|
|
472
472
|
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h"))) { console.log(SUB_HELP[sub] || HELP); process.exit(0); }
|
|
473
473
|
switch (sub) {
|
|
474
|
-
case "provision-
|
|
475
|
-
case "get-
|
|
476
|
-
case "list-
|
|
474
|
+
case "provision-signer": await provisionSigner(args[0], args.slice(1)); break;
|
|
475
|
+
case "get-signer": await getSigner(args[0], args[1], args.slice(2)); break;
|
|
476
|
+
case "list-signers": await listSigners(args[0], args.slice(1)); break;
|
|
477
477
|
case "set-recovery": await setRecovery(args[0], args[1], args.slice(2)); break;
|
|
478
478
|
case "set-alert": await setAlert(args[0], args[1], args.slice(2)); break;
|
|
479
479
|
case "call": await call(args[0], args[1], args.slice(2)); break;
|
|
@@ -481,7 +481,7 @@ export async function run(sub, args) {
|
|
|
481
481
|
case "read": await read(args); break;
|
|
482
482
|
case "status": await status(args[0], args[1], args.slice(2)); break;
|
|
483
483
|
case "drain": await drain(args[0], args[1], args.slice(2)); break;
|
|
484
|
-
case "delete": await
|
|
484
|
+
case "delete": await deleteSigner(args[0], args[1], args.slice(2)); break;
|
|
485
485
|
default:
|
|
486
486
|
console.error(`Unknown subcommand: ${sub}\n`);
|
|
487
487
|
console.log(HELP);
|
package/lib/projects.mjs
CHANGED
|
@@ -16,8 +16,9 @@ Subcommands:
|
|
|
16
16
|
use <id> Set the active project (used as default for other commands)
|
|
17
17
|
list [--org <id>] [--all] List your projects from the server (name, site_url, custom domains, org_id, active marker)
|
|
18
18
|
rename <id> --name <label> Rename a project (fix an auto-generated name)
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
get [id] Authoritative server read: status, org, tier, active deploy, mailbox, usage vs limits (live; no keys)
|
|
20
|
+
info [id] Show local project details: REST URL, keys (local keystore only)
|
|
21
|
+
keys [id] Print anon_key and service_key as JSON (local keystore only)
|
|
21
22
|
sql [id] "<query>" [--file <path>] [--params '<json>'] Run a SQL query (supports parameterized queries)
|
|
22
23
|
rest [id] <table> [params] Query a table via the REST API (PostgREST)
|
|
23
24
|
usage [id] Show compute/storage usage for a project
|
|
@@ -41,6 +42,7 @@ Examples:
|
|
|
41
42
|
run402 projects list --org 11111111-2222-3333-4444-555555555555
|
|
42
43
|
run402 projects list --all
|
|
43
44
|
run402 projects rename prj_abc123 --name "My Site"
|
|
45
|
+
run402 projects get prj_abc123
|
|
44
46
|
run402 projects info prj_abc123
|
|
45
47
|
run402 projects sql prj_abc123 "SELECT * FROM users LIMIT 5"
|
|
46
48
|
run402 projects sql prj_abc123 "SELECT * FROM users WHERE id = $1" --params '[42]'
|
|
@@ -508,6 +510,15 @@ async function rename(projectId, args = []) {
|
|
|
508
510
|
}
|
|
509
511
|
}
|
|
510
512
|
|
|
513
|
+
async function get(projectId) {
|
|
514
|
+
try {
|
|
515
|
+
const data = await getSdk().projects.get(projectId);
|
|
516
|
+
console.log(JSON.stringify(data, null, 2));
|
|
517
|
+
} catch (err) {
|
|
518
|
+
reportSdkError(err);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
511
522
|
async function info(projectId) {
|
|
512
523
|
try {
|
|
513
524
|
const data = await getSdk().projects.info(projectId);
|
|
@@ -755,6 +766,7 @@ export async function run(sub, args) {
|
|
|
755
766
|
case "use": await use(args[0]); break;
|
|
756
767
|
case "list": await list(args); break;
|
|
757
768
|
case "rename": { const { projectId, rest } = resolvePositionalProject(args, { rejectBareFirst: true, valueFlags: FLAGS_BY_SUB.rename.values }); await rename(projectId, rest); break; }
|
|
769
|
+
case "get": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await get(projectId); break; }
|
|
758
770
|
case "info": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await info(projectId); break; }
|
|
759
771
|
case "keys": { const { projectId } = resolvePositionalProject(args, { rejectBareFirst: true }); await keys(projectId); break; }
|
|
760
772
|
case "sql": { const { projectId, rest } = resolvePositionalProject(args, { maxBarePositionals: 1, valueFlags: FLAGS_BY_SUB.sql.values, rejectBareFirstWhenFlagPresent: ["--file"] }); await sqlCmd(projectId, rest); break; }
|
package/lib/transfer.mjs
CHANGED
|
@@ -13,11 +13,11 @@ import {
|
|
|
13
13
|
const HELP = `run402 transfer — Two-party project transfer (v1.59)
|
|
14
14
|
|
|
15
15
|
Usage:
|
|
16
|
-
run402 transfer init --to <wallet|email> [--project <id>] [--billing-policy migrate] [--message <text>] [--kysigned <record_id>]
|
|
16
|
+
run402 transfer init --to <wallet|email> [--project <id>] [--billing-policy migrate] [--message <text>] [--kysigned <record_id>] [--retain-collaborator developer]
|
|
17
17
|
run402 transfer preview <transfer_id>
|
|
18
18
|
run402 transfer list [--incoming | --outgoing] [--limit N] [--offset N]
|
|
19
19
|
run402 transfer accept <transfer_id>
|
|
20
|
-
run402 transfer claim <transfer_id> [--into <organization_id>]
|
|
20
|
+
run402 transfer claim <transfer_id> [--into <organization_id>] [--accept-retained-collaborator]
|
|
21
21
|
run402 transfer cancel <transfer_id> [--reason <text>] [--handoff]
|
|
22
22
|
|
|
23
23
|
Subcommands:
|
|
@@ -41,7 +41,7 @@ const SUB_HELP = {
|
|
|
41
41
|
init: `run402 transfer init — Initiate a project transfer
|
|
42
42
|
|
|
43
43
|
Usage:
|
|
44
|
-
run402 transfer init --to <wallet|email> [--project <id>] [--billing-policy migrate] [--message <text>] [--kysigned <record_id>]
|
|
44
|
+
run402 transfer init --to <wallet|email> [--project <id>] [--billing-policy migrate] [--message <text>] [--kysigned <record_id>] [--retain-collaborator developer]
|
|
45
45
|
|
|
46
46
|
Options:
|
|
47
47
|
--project <id> Project id (defaults to the active project)
|
|
@@ -49,6 +49,9 @@ Options:
|
|
|
49
49
|
--billing-policy <p> Billing policy. Phase 1A only allows 'migrate' (default).
|
|
50
50
|
--message <text> Optional note shown to the recipient in preview + emails.
|
|
51
51
|
--kysigned <record_id> Optional KySigned record id (Phase 1A: informational only).
|
|
52
|
+
--retain-collaborator <role> Email handoffs only (v1.91): keep a 'developer' membership in
|
|
53
|
+
the recipient's org after handoff. The recipient must accept it at
|
|
54
|
+
claim (--accept-retained-collaborator); omit for full severance.
|
|
52
55
|
|
|
53
56
|
Notes:
|
|
54
57
|
- Caller's wallet must currently own the project (gateway re-checks fresh DB).
|
|
@@ -97,18 +100,24 @@ email->org handoff instead of a wallet transfer.
|
|
|
97
100
|
claim: `run402 transfer claim — Claim an incoming email handoff
|
|
98
101
|
|
|
99
102
|
Usage:
|
|
100
|
-
run402 transfer claim <transfer_id> [--into <organization_id>]
|
|
103
|
+
run402 transfer claim <transfer_id> [--into <organization_id>] [--accept-retained-collaborator]
|
|
101
104
|
|
|
102
105
|
Claims a handoff addressed to your email into an org you own. Omit --into to
|
|
103
106
|
claim into a brand-new org. This is the email-handoff analog of 'accept'.
|
|
107
|
+
|
|
108
|
+
Options:
|
|
109
|
+
--into <organization_id> Org to claim into (omit = brand-new org).
|
|
110
|
+
--accept-retained-collaborator Accept the sender's v1.91 retained-developer-membership offer
|
|
111
|
+
(see 'transfer preview' retain_collaborator). Omit = full severance.
|
|
104
112
|
`,
|
|
105
113
|
};
|
|
106
114
|
|
|
107
115
|
const BILLING_POLICIES = new Set(["migrate"]);
|
|
116
|
+
const RETAIN_ROLES = new Set(["developer"]);
|
|
108
117
|
|
|
109
118
|
async function init(args) {
|
|
110
119
|
const parsedArgs = normalizeArgv(args);
|
|
111
|
-
const valueFlags = ["--project", "--to", "--billing-policy", "--message", "--kysigned"];
|
|
120
|
+
const valueFlags = ["--project", "--to", "--billing-policy", "--message", "--kysigned", "--retain-collaborator"];
|
|
112
121
|
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
113
122
|
const extra = positionalArgs(parsedArgs, valueFlags);
|
|
114
123
|
if (extra.length > 0) {
|
|
@@ -133,10 +142,31 @@ async function init(args) {
|
|
|
133
142
|
}
|
|
134
143
|
const message = flagValue(parsedArgs, "--message");
|
|
135
144
|
const kysigned = flagValue(parsedArgs, "--kysigned");
|
|
145
|
+
const retainCollaborator = flagValue(parsedArgs, "--retain-collaborator");
|
|
136
146
|
|
|
137
147
|
// One noun, two rails: an email recipient routes to the email->org handoff;
|
|
138
148
|
// a wallet recipient routes to the two-party wallet transfer.
|
|
139
149
|
const isEmail = toWallet.includes("@");
|
|
150
|
+
|
|
151
|
+
// --retain-collaborator (v1.91) is a handoff-only opt-in: the sender keeps a
|
|
152
|
+
// developer membership in the recipient's org (recipient must accept at claim).
|
|
153
|
+
if (retainCollaborator !== null) {
|
|
154
|
+
if (!isEmail) {
|
|
155
|
+
fail({
|
|
156
|
+
code: "BAD_FLAG",
|
|
157
|
+
message: "--retain-collaborator applies only to email handoffs; a wallet --to uses the two-party transfer rail.",
|
|
158
|
+
details: { flag: "--retain-collaborator" },
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
if (!RETAIN_ROLES.has(retainCollaborator)) {
|
|
162
|
+
fail({
|
|
163
|
+
code: "BAD_FLAG",
|
|
164
|
+
message: `Unsupported --retain-collaborator role: ${retainCollaborator}. Allowed: ${[...RETAIN_ROLES].join(", ")}.`,
|
|
165
|
+
details: { flag: "--retain-collaborator", value: retainCollaborator, allowed: [...RETAIN_ROLES] },
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
140
170
|
allowanceAuthHeaders(
|
|
141
171
|
isEmail ? `/projects/v1/${projectId}/handoffs` : `/projects/v1/${projectId}/transfers`,
|
|
142
172
|
);
|
|
@@ -147,6 +177,7 @@ async function init(args) {
|
|
|
147
177
|
projectId,
|
|
148
178
|
toEmail: toWallet,
|
|
149
179
|
message: message ?? undefined,
|
|
180
|
+
retainCollaborator: retainCollaborator ? { role: retainCollaborator } : undefined,
|
|
150
181
|
})
|
|
151
182
|
: await getSdk().admin.transfers.initiate({
|
|
152
183
|
projectId,
|
|
@@ -278,18 +309,22 @@ async function cancel(args) {
|
|
|
278
309
|
async function claim(args) {
|
|
279
310
|
const parsedArgs = normalizeArgv(args);
|
|
280
311
|
const valueFlags = ["--into"];
|
|
281
|
-
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
312
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--accept-retained-collaborator", "--help", "-h"], valueFlags);
|
|
282
313
|
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
283
314
|
if (positionals.length !== 1) {
|
|
284
|
-
fail({ code: "BAD_USAGE", message: "Usage: run402 transfer claim <transfer_id> [--into <organization_id>]" });
|
|
315
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 transfer claim <transfer_id> [--into <organization_id>] [--accept-retained-collaborator]" });
|
|
285
316
|
}
|
|
286
317
|
const transferId = positionals[0];
|
|
287
318
|
const into = flagValue(parsedArgs, "--into");
|
|
319
|
+
// v1.91: accept the sender's retained-developer-membership offer (see the
|
|
320
|
+
// preview's `retain_collaborator` block). Absent = full severance (default).
|
|
321
|
+
const acceptRetain = parsedArgs.includes("--accept-retained-collaborator");
|
|
288
322
|
allowanceAuthHeaders(`/agent/v1/handoffs/${transferId}/claim`);
|
|
289
323
|
|
|
290
324
|
try {
|
|
291
325
|
const data = await getSdk().admin.transfers.claimHandoff(transferId, {
|
|
292
326
|
organizationId: into ?? undefined,
|
|
327
|
+
acceptRetainedCollaborator: acceptRetain || undefined,
|
|
293
328
|
});
|
|
294
329
|
console.log(JSON.stringify(data, null, 2));
|
|
295
330
|
} catch (err) {
|
package/package.json
CHANGED