run402 2.39.4 → 2.41.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/cli.mjs +1 -1
- package/core-dist/control-plane-session.js +114 -0
- package/lib/operator.mjs +203 -12
- package/lib/org.mjs +205 -103
- package/lib/transfer.mjs +94 -27
- package/package.json +1 -1
- package/sdk/core-dist/control-plane-session.js +114 -0
- package/sdk/dist/control-plane-credentials.d.ts +45 -0
- package/sdk/dist/control-plane-credentials.d.ts.map +1 -0
- package/sdk/dist/control-plane-credentials.js +57 -0
- package/sdk/dist/control-plane-credentials.js.map +1 -0
- package/sdk/dist/errors.d.ts +31 -1
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +59 -0
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/index.d.ts +6 -2
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +4 -2
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/kernel.d.ts.map +1 -1
- package/sdk/dist/kernel.js +4 -1
- package/sdk/dist/kernel.js.map +1 -1
- package/sdk/dist/namespaces/operator-session.d.ts +223 -0
- package/sdk/dist/namespaces/operator-session.d.ts.map +1 -0
- package/sdk/dist/namespaces/operator-session.js +230 -0
- package/sdk/dist/namespaces/operator-session.js.map +1 -0
- package/sdk/dist/namespaces/operator.d.ts +63 -0
- package/sdk/dist/namespaces/operator.d.ts.map +1 -1
- package/sdk/dist/namespaces/operator.js +51 -0
- package/sdk/dist/namespaces/operator.js.map +1 -1
- package/sdk/dist/namespaces/org.d.ts +55 -23
- package/sdk/dist/namespaces/org.d.ts.map +1 -1
- package/sdk/dist/namespaces/org.js +117 -52
- package/sdk/dist/namespaces/org.js.map +1 -1
- package/sdk/dist/namespaces/org.types.d.ts +37 -1
- package/sdk/dist/namespaces/org.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.d.ts +58 -0
- package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.js +40 -0
- package/sdk/dist/namespaces/transfers.js.map +1 -1
package/lib/org.mjs
CHANGED
|
@@ -1,42 +1,49 @@
|
|
|
1
1
|
import { getSdk } from "./sdk.mjs";
|
|
2
|
-
import { reportSdkError } from "./sdk-errors.mjs";
|
|
2
|
+
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
3
3
|
import {
|
|
4
4
|
normalizeArgv,
|
|
5
5
|
assertKnownFlags,
|
|
6
6
|
flagValue,
|
|
7
|
+
parseIntegerFlag,
|
|
7
8
|
requirePositionalCount,
|
|
8
9
|
} from "./argparse.mjs";
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
+
const ROLE_LIST = "owner | admin | developer | billing | viewer";
|
|
12
|
+
|
|
13
|
+
const HELP = `run402 org — org-owned control plane: identity, membership, invites
|
|
11
14
|
|
|
12
15
|
Usage:
|
|
13
|
-
run402 org
|
|
16
|
+
run402 org whoami
|
|
17
|
+
run402 org list
|
|
18
|
+
run402 org audit <billing_account> [--limit N] [--before <cursor>]
|
|
19
|
+
run402 org member list <billing_account>
|
|
20
|
+
run402 org member add <billing_account> <wallet> [--role <role>]
|
|
21
|
+
run402 org member role <billing_account> <principal_id> <role>
|
|
22
|
+
run402 org member rm <billing_account> <principal_id>
|
|
23
|
+
run402 org invite list <billing_account>
|
|
24
|
+
run402 org invite create <billing_account> <email> [--role <role>] [--ttl-hours N]
|
|
25
|
+
run402 org invite rm <billing_account> <principal_id>
|
|
14
26
|
|
|
15
27
|
Subcommands:
|
|
16
|
-
whoami
|
|
17
|
-
list
|
|
18
|
-
members
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
set-role <billing_account> <principal_id> <role>
|
|
22
|
-
Change a member's role (owner-gated)
|
|
23
|
-
remove-member <billing_account> <principal_id>
|
|
24
|
-
Remove a member (owner-gated)
|
|
28
|
+
whoami Resolved principal + org memberships (GET /agent/v1/whoami)
|
|
29
|
+
list Orgs you are a member of
|
|
30
|
+
member Manage members (list, add, role, rm) — mutations require owner
|
|
31
|
+
invite Manage email invites (list, create, rm) — mutations require owner
|
|
32
|
+
audit Control-plane audit trail for an org (admin+)
|
|
25
33
|
|
|
26
34
|
Notes:
|
|
27
35
|
- A wallet AUTHENTICATES; the org (billing account) owns projects. Membership/role authorizes.
|
|
28
|
-
- Roles:
|
|
29
|
-
- "add-member" is by WALLET (email-first invite is a separate, not-yet-shipped flow).
|
|
36
|
+
- Roles: ${ROLE_LIST}. Member/invite changes need an active owner.
|
|
30
37
|
- Removing/demoting the org's only active owner fails with 409 LAST_OWNER.
|
|
31
38
|
- JSON in, JSON out.
|
|
32
39
|
|
|
33
40
|
Examples:
|
|
34
41
|
run402 org whoami
|
|
35
|
-
run402 org list
|
|
36
|
-
run402 org
|
|
37
|
-
run402 org
|
|
38
|
-
run402 org
|
|
39
|
-
run402 org
|
|
42
|
+
run402 org member list ba_abc
|
|
43
|
+
run402 org member add ba_abc 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --role admin
|
|
44
|
+
run402 org member role ba_abc prn_xyz owner
|
|
45
|
+
run402 org invite create ba_abc dev@example.com --role developer
|
|
46
|
+
run402 org audit ba_abc --limit 50
|
|
40
47
|
`;
|
|
41
48
|
|
|
42
49
|
const SUB_HELP = {
|
|
@@ -46,57 +53,46 @@ Usage:
|
|
|
46
53
|
run402 org whoami
|
|
47
54
|
|
|
48
55
|
Calls GET /agent/v1/whoami. Returns the control-plane principal (id/type/displayName/createdAt),
|
|
49
|
-
authenticator_id, and every org membership with role + status.
|
|
50
|
-
|
|
56
|
+
authenticator_id, and every org membership with role + status. REMOTE identity; for local
|
|
57
|
+
wallet/profile state use 'run402 status'.
|
|
51
58
|
`,
|
|
52
59
|
list: `run402 org list — orgs you are a member of
|
|
53
60
|
|
|
54
61
|
Usage:
|
|
55
62
|
run402 org list
|
|
56
|
-
|
|
57
|
-
Returns each org (billing account) you belong to with your role and membership status.
|
|
58
|
-
`,
|
|
59
|
-
members: `run402 org members — members + roles of an org
|
|
60
|
-
|
|
61
|
-
Usage:
|
|
62
|
-
run402 org members <billing_account>
|
|
63
|
-
|
|
64
|
-
Arguments:
|
|
65
|
-
<billing_account> Org (billing account) id, e.g. ba_...
|
|
66
63
|
`,
|
|
67
|
-
|
|
64
|
+
member: `run402 org member — manage org members
|
|
68
65
|
|
|
69
66
|
Usage:
|
|
70
|
-
run402 org
|
|
67
|
+
run402 org member list <billing_account>
|
|
68
|
+
run402 org member add <billing_account> <wallet> [--role <role>]
|
|
69
|
+
run402 org member role <billing_account> <principal_id> <role>
|
|
70
|
+
run402 org member rm <billing_account> <principal_id>
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<wallet> EVM address or named wallet (a new wallet is provisioned as a human principal)
|
|
75
|
-
|
|
76
|
-
Options:
|
|
77
|
-
--role <role> owner | admin | developer | billing | viewer (default: developer)
|
|
72
|
+
Roles: ${ROLE_LIST} (add defaults to developer). Mutations require an active owner.
|
|
73
|
+
Demoting/removing the org's only active owner fails with 409 LAST_OWNER.
|
|
78
74
|
`,
|
|
79
|
-
|
|
75
|
+
invite: `run402 org invite — manage email invites
|
|
80
76
|
|
|
81
77
|
Usage:
|
|
82
|
-
run402 org
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<billing_account> Org (billing account) id
|
|
86
|
-
<principal_id> Member principal id (prn_..., from \`run402 org members\`)
|
|
87
|
-
<role> owner | admin | developer | billing | viewer
|
|
78
|
+
run402 org invite list <billing_account>
|
|
79
|
+
run402 org invite create <billing_account> <email> [--role <role>] [--ttl-hours N]
|
|
80
|
+
run402 org invite rm <billing_account> <principal_id>
|
|
88
81
|
|
|
89
|
-
|
|
82
|
+
An invite is claimed at the recipient's first login. Mutations require an active owner
|
|
83
|
+
(plus step-up when driven by a control-plane session).
|
|
90
84
|
`,
|
|
91
|
-
|
|
85
|
+
audit: `run402 org audit — control-plane audit trail
|
|
92
86
|
|
|
93
87
|
Usage:
|
|
94
|
-
run402 org
|
|
88
|
+
run402 org audit <billing_account> [--limit N] [--before <cursor>]
|
|
95
89
|
|
|
96
|
-
|
|
90
|
+
Requires an admin+ membership on the org. Newest-first; page with --before.
|
|
97
91
|
`,
|
|
98
92
|
};
|
|
99
93
|
|
|
94
|
+
// ── Top-level: whoami / list / audit ───────────────────────────────────────────
|
|
95
|
+
|
|
100
96
|
async function whoami(args) {
|
|
101
97
|
const a = normalizeArgv(args);
|
|
102
98
|
assertKnownFlags(a, ["--help", "-h"]);
|
|
@@ -119,70 +115,169 @@ async function list(args) {
|
|
|
119
115
|
}
|
|
120
116
|
}
|
|
121
117
|
|
|
122
|
-
async function
|
|
118
|
+
async function audit(args) {
|
|
123
119
|
const a = normalizeArgv(args);
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
const valueFlags = ["--limit", "--before"];
|
|
121
|
+
assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
|
|
122
|
+
const [ba] = requirePositionalCount(a, valueFlags, {
|
|
126
123
|
min: 1,
|
|
127
124
|
max: 1,
|
|
128
|
-
command: "run402 org
|
|
125
|
+
command: "run402 org audit <billing_account>",
|
|
129
126
|
missing: "Missing <billing_account>.",
|
|
130
127
|
});
|
|
128
|
+
const limitFlag = flagValue(a, "--limit");
|
|
129
|
+
const before = flagValue(a, "--before");
|
|
130
|
+
const limit = limitFlag === null ? undefined : parseIntegerFlag("--limit", limitFlag, { min: 1, max: 1000 });
|
|
131
131
|
try {
|
|
132
|
-
|
|
132
|
+
const events = await getSdk().org.audit(ba, { limit, before: before ?? undefined });
|
|
133
|
+
console.log(JSON.stringify({ events }, null, 2));
|
|
133
134
|
} catch (err) {
|
|
134
135
|
reportSdkError(err);
|
|
135
136
|
}
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
console.log(JSON.stringify(res, null, 2));
|
|
151
|
-
} catch (err) {
|
|
152
|
-
reportSdkError(err);
|
|
139
|
+
// ── Member group ───────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
async function runMember(args) {
|
|
142
|
+
const memberAction = args[0];
|
|
143
|
+
const rest = args.slice(1);
|
|
144
|
+
if (!memberAction || memberAction === "--help" || memberAction === "-h") {
|
|
145
|
+
console.log(SUB_HELP.member);
|
|
146
|
+
process.exit(memberAction ? 0 : 1);
|
|
147
|
+
}
|
|
148
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
149
|
+
console.log(SUB_HELP.member);
|
|
150
|
+
process.exit(0);
|
|
153
151
|
}
|
|
154
|
-
}
|
|
155
152
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
153
|
+
if (memberAction === "list") {
|
|
154
|
+
const a = normalizeArgv(rest);
|
|
155
|
+
assertKnownFlags(a, ["--help", "-h"]);
|
|
156
|
+
const [ba] = requirePositionalCount(a, [], {
|
|
157
|
+
min: 1, max: 1, command: "run402 org member list <billing_account>", missing: "Missing <billing_account>.",
|
|
158
|
+
});
|
|
159
|
+
try {
|
|
160
|
+
console.log(JSON.stringify({ members: await getSdk().org.members.list(ba) }, null, 2));
|
|
161
|
+
} catch (err) {
|
|
162
|
+
reportSdkError(err);
|
|
163
|
+
}
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (memberAction === "add") {
|
|
168
|
+
const a = normalizeArgv(rest);
|
|
169
|
+
assertKnownFlags(a, ["--role", "--help", "-h"], ["--role"]);
|
|
170
|
+
const role = flagValue(a, "--role");
|
|
171
|
+
const [ba, wallet] = requirePositionalCount(a, ["--role"], {
|
|
172
|
+
min: 2, max: 2, command: "run402 org member add <billing_account> <wallet> [--role <role>]",
|
|
173
|
+
missing: "Missing <billing_account> and/or <wallet>.",
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
const res = await getSdk().org.members.add(ba, { wallet, role: role || undefined });
|
|
177
|
+
console.log(JSON.stringify(res, null, 2));
|
|
178
|
+
} catch (err) {
|
|
179
|
+
reportSdkError(err);
|
|
180
|
+
}
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (memberAction === "role") {
|
|
185
|
+
const a = normalizeArgv(rest);
|
|
186
|
+
assertKnownFlags(a, ["--help", "-h"]);
|
|
187
|
+
const [ba, principalId, role] = requirePositionalCount(a, [], {
|
|
188
|
+
min: 3, max: 3, command: "run402 org member role <billing_account> <principal_id> <role>",
|
|
189
|
+
missing: "Missing <billing_account>, <principal_id>, and/or <role>.",
|
|
190
|
+
});
|
|
191
|
+
try {
|
|
192
|
+
console.log(JSON.stringify(await getSdk().org.members.setRole(ba, principalId, role), null, 2));
|
|
193
|
+
} catch (err) {
|
|
194
|
+
reportSdkError(err);
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (memberAction === "rm") {
|
|
200
|
+
const a = normalizeArgv(rest);
|
|
201
|
+
assertKnownFlags(a, ["--help", "-h"]);
|
|
202
|
+
const [ba, principalId] = requirePositionalCount(a, [], {
|
|
203
|
+
min: 2, max: 2, command: "run402 org member rm <billing_account> <principal_id>",
|
|
204
|
+
missing: "Missing <billing_account> and/or <principal_id>.",
|
|
205
|
+
});
|
|
206
|
+
try {
|
|
207
|
+
console.log(JSON.stringify(await getSdk().org.members.revoke(ba, principalId), null, 2));
|
|
208
|
+
} catch (err) {
|
|
209
|
+
reportSdkError(err);
|
|
210
|
+
}
|
|
211
|
+
return;
|
|
169
212
|
}
|
|
213
|
+
|
|
214
|
+
fail({ code: "BAD_USAGE", message: `Unknown 'org member' action: ${memberAction}. Try list | add | role | rm.` });
|
|
170
215
|
}
|
|
171
216
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
console.log(
|
|
183
|
-
|
|
184
|
-
reportSdkError(err);
|
|
217
|
+
// ── Invite group ─────────────────────────────────────────────────────────────────
|
|
218
|
+
|
|
219
|
+
async function runInvite(args) {
|
|
220
|
+
const inviteAction = args[0];
|
|
221
|
+
const rest = args.slice(1);
|
|
222
|
+
if (!inviteAction || inviteAction === "--help" || inviteAction === "-h") {
|
|
223
|
+
console.log(SUB_HELP.invite);
|
|
224
|
+
process.exit(inviteAction ? 0 : 1);
|
|
225
|
+
}
|
|
226
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
227
|
+
console.log(SUB_HELP.invite);
|
|
228
|
+
process.exit(0);
|
|
185
229
|
}
|
|
230
|
+
|
|
231
|
+
if (inviteAction === "list") {
|
|
232
|
+
const a = normalizeArgv(rest);
|
|
233
|
+
assertKnownFlags(a, ["--help", "-h"]);
|
|
234
|
+
const [ba] = requirePositionalCount(a, [], {
|
|
235
|
+
min: 1, max: 1, command: "run402 org invite list <billing_account>", missing: "Missing <billing_account>.",
|
|
236
|
+
});
|
|
237
|
+
try {
|
|
238
|
+
console.log(JSON.stringify({ invites: await getSdk().org.invites.list(ba) }, null, 2));
|
|
239
|
+
} catch (err) {
|
|
240
|
+
reportSdkError(err);
|
|
241
|
+
}
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (inviteAction === "create") {
|
|
246
|
+
const a = normalizeArgv(rest);
|
|
247
|
+
const valueFlags = ["--role", "--ttl-hours"];
|
|
248
|
+
assertKnownFlags(a, [...valueFlags, "--help", "-h"], valueFlags);
|
|
249
|
+
const role = flagValue(a, "--role");
|
|
250
|
+
const ttlFlag = flagValue(a, "--ttl-hours");
|
|
251
|
+
const [ba, email] = requirePositionalCount(a, valueFlags, {
|
|
252
|
+
min: 2, max: 2, command: "run402 org invite create <billing_account> <email> [--role <role>]",
|
|
253
|
+
missing: "Missing <billing_account> and/or <email>.",
|
|
254
|
+
});
|
|
255
|
+
const inviteTtlHours = ttlFlag === null ? undefined : parseIntegerFlag("--ttl-hours", ttlFlag, { min: 1, max: 8760 });
|
|
256
|
+
try {
|
|
257
|
+
const res = await getSdk().org.invites.create(ba, { email, role: role || "developer", inviteTtlHours });
|
|
258
|
+
console.log(JSON.stringify(res, null, 2));
|
|
259
|
+
} catch (err) {
|
|
260
|
+
reportSdkError(err);
|
|
261
|
+
}
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (inviteAction === "rm") {
|
|
266
|
+
const a = normalizeArgv(rest);
|
|
267
|
+
assertKnownFlags(a, ["--help", "-h"]);
|
|
268
|
+
const [ba, principalId] = requirePositionalCount(a, [], {
|
|
269
|
+
min: 2, max: 2, command: "run402 org invite rm <billing_account> <principal_id>",
|
|
270
|
+
missing: "Missing <billing_account> and/or <principal_id>.",
|
|
271
|
+
});
|
|
272
|
+
try {
|
|
273
|
+
console.log(JSON.stringify(await getSdk().org.invites.revoke(ba, principalId), null, 2));
|
|
274
|
+
} catch (err) {
|
|
275
|
+
reportSdkError(err);
|
|
276
|
+
}
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
fail({ code: "BAD_USAGE", message: `Unknown 'org invite' action: ${inviteAction}. Try list | create | rm.` });
|
|
186
281
|
}
|
|
187
282
|
|
|
188
283
|
export async function run(sub, args) {
|
|
@@ -190,17 +285,24 @@ export async function run(sub, args) {
|
|
|
190
285
|
console.log(HELP);
|
|
191
286
|
process.exit(0);
|
|
192
287
|
}
|
|
193
|
-
if (
|
|
194
|
-
|
|
288
|
+
// Nested groups use `if (sub === ...)` (not `case`) so the sync test extracts
|
|
289
|
+
// their leaf actions via the dedicated memberAction/inviteAction parsers.
|
|
290
|
+
if (sub === "member" || sub === "members") {
|
|
291
|
+
await runMember(args ?? []);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (sub === "invite" || sub === "invites") {
|
|
295
|
+
await runInvite(args ?? []);
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (Array.isArray(args) && (args.includes("--help") || args.includes("-h")) && SUB_HELP[sub]) {
|
|
299
|
+
console.log(SUB_HELP[sub]);
|
|
195
300
|
process.exit(0);
|
|
196
301
|
}
|
|
197
302
|
switch (sub) {
|
|
198
303
|
case "whoami": await whoami(args); break;
|
|
199
304
|
case "list": await list(args); break;
|
|
200
|
-
case "
|
|
201
|
-
case "add-member": await addMember(args); break;
|
|
202
|
-
case "set-role": await setRole(args); break;
|
|
203
|
-
case "remove-member": await removeMember(args); break;
|
|
305
|
+
case "audit": await audit(args); break;
|
|
204
306
|
default:
|
|
205
307
|
console.error(`Unknown subcommand: ${sub}\n`);
|
|
206
308
|
console.log(HELP);
|
package/lib/transfer.mjs
CHANGED
|
@@ -13,18 +13,21 @@ import {
|
|
|
13
13
|
const HELP = `run402 transfer — Two-party project transfer (v1.59)
|
|
14
14
|
|
|
15
15
|
Usage:
|
|
16
|
-
run402 transfer init --to <wallet> [--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>]
|
|
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
|
|
20
|
+
run402 transfer claim <transfer_id> [--into <billing_account_id>]
|
|
21
|
+
run402 transfer cancel <transfer_id> [--reason <text>] [--handoff]
|
|
21
22
|
|
|
22
23
|
Subcommands:
|
|
23
|
-
init Initiate
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
init Initiate ownership change. --to <wallet> = two-party wallet transfer;
|
|
25
|
+
--to <email> = email->org handoff (the recipient claims it).
|
|
26
|
+
preview Fetch the safe review document (add --handoff for an email handoff)
|
|
27
|
+
list List pending transfers (incoming default, --outgoing, or --handoffs)
|
|
28
|
+
accept Accept an incoming wallet transfer (your wallet must be the to_wallet)
|
|
29
|
+
claim Claim an incoming email handoff into an org (--into <id>; omit = new org)
|
|
30
|
+
cancel Cancel a pending transfer/handoff (--handoff routes to a handoff)
|
|
28
31
|
|
|
29
32
|
Notes:
|
|
30
33
|
- Owner-side mutations on a project with a pending transfer return 409
|
|
@@ -38,7 +41,7 @@ const SUB_HELP = {
|
|
|
38
41
|
init: `run402 transfer init — Initiate a project transfer
|
|
39
42
|
|
|
40
43
|
Usage:
|
|
41
|
-
run402 transfer init --to <wallet> [--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>]
|
|
42
45
|
|
|
43
46
|
Options:
|
|
44
47
|
--project <id> Project id (defaults to the active project)
|
|
@@ -85,10 +88,19 @@ project, enqueues notifications to both parties, and stamps a
|
|
|
85
88
|
cancel: `run402 transfer cancel — Cancel a pending transfer
|
|
86
89
|
|
|
87
90
|
Usage:
|
|
88
|
-
run402 transfer cancel <transfer_id> [--reason <text>]
|
|
91
|
+
run402 transfer cancel <transfer_id> [--reason <text>] [--handoff]
|
|
89
92
|
|
|
90
93
|
Either the from_wallet or the to_wallet may cancel. Already-processed
|
|
91
|
-
transfers return 409 TRANSFER_ALREADY_PROCESSED.
|
|
94
|
+
transfers return 409 TRANSFER_ALREADY_PROCESSED. Pass --handoff to cancel an
|
|
95
|
+
email->org handoff instead of a wallet transfer.
|
|
96
|
+
`,
|
|
97
|
+
claim: `run402 transfer claim — Claim an incoming email handoff
|
|
98
|
+
|
|
99
|
+
Usage:
|
|
100
|
+
run402 transfer claim <transfer_id> [--into <billing_account_id>]
|
|
101
|
+
|
|
102
|
+
Claims a handoff addressed to your email into an org you own. Omit --into to
|
|
103
|
+
claim into a brand-new org. This is the email-handoff analog of 'accept'.
|
|
92
104
|
`,
|
|
93
105
|
};
|
|
94
106
|
|
|
@@ -122,16 +134,27 @@ async function init(args) {
|
|
|
122
134
|
const message = flagValue(parsedArgs, "--message");
|
|
123
135
|
const kysigned = flagValue(parsedArgs, "--kysigned");
|
|
124
136
|
|
|
125
|
-
|
|
137
|
+
// One noun, two rails: an email recipient routes to the email->org handoff;
|
|
138
|
+
// a wallet recipient routes to the two-party wallet transfer.
|
|
139
|
+
const isEmail = toWallet.includes("@");
|
|
140
|
+
allowanceAuthHeaders(
|
|
141
|
+
isEmail ? `/projects/v1/${projectId}/handoffs` : `/projects/v1/${projectId}/transfers`,
|
|
142
|
+
);
|
|
126
143
|
|
|
127
144
|
try {
|
|
128
|
-
const res =
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
145
|
+
const res = isEmail
|
|
146
|
+
? await getSdk().admin.transfers.initiateHandoff({
|
|
147
|
+
projectId,
|
|
148
|
+
toEmail: toWallet,
|
|
149
|
+
message: message ?? undefined,
|
|
150
|
+
})
|
|
151
|
+
: await getSdk().admin.transfers.initiate({
|
|
152
|
+
projectId,
|
|
153
|
+
toWallet,
|
|
154
|
+
billingPolicy: billingPolicy ?? undefined,
|
|
155
|
+
message: message ?? undefined,
|
|
156
|
+
kysignedRecordId: kysigned ?? undefined,
|
|
157
|
+
});
|
|
135
158
|
console.log(JSON.stringify(res, null, 2));
|
|
136
159
|
} catch (err) {
|
|
137
160
|
reportSdkError(err);
|
|
@@ -140,16 +163,19 @@ async function init(args) {
|
|
|
140
163
|
|
|
141
164
|
async function preview(args) {
|
|
142
165
|
const parsedArgs = normalizeArgv(args);
|
|
143
|
-
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
166
|
+
assertKnownFlags(parsedArgs, ["--handoff", "--help", "-h"]);
|
|
144
167
|
const positionals = positionalArgs(parsedArgs);
|
|
145
168
|
if (positionals.length !== 1) {
|
|
146
|
-
fail({ code: "BAD_USAGE", message: "Usage: run402 transfer preview <transfer_id>" });
|
|
169
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 transfer preview <transfer_id> [--handoff]" });
|
|
147
170
|
}
|
|
148
171
|
const transferId = positionals[0];
|
|
149
|
-
|
|
172
|
+
const handoff = parsedArgs.includes("--handoff");
|
|
173
|
+
allowanceAuthHeaders(`/agent/v1/${handoff ? "handoffs" : "transfers"}/${transferId}`);
|
|
150
174
|
|
|
151
175
|
try {
|
|
152
|
-
const data =
|
|
176
|
+
const data = handoff
|
|
177
|
+
? await getSdk().admin.transfers.previewHandoff(transferId)
|
|
178
|
+
: await getSdk().admin.transfers.preview(transferId);
|
|
153
179
|
console.log(JSON.stringify(data, null, 2));
|
|
154
180
|
} catch (err) {
|
|
155
181
|
reportSdkError(err);
|
|
@@ -159,11 +185,24 @@ async function preview(args) {
|
|
|
159
185
|
async function list(args) {
|
|
160
186
|
const parsedArgs = normalizeArgv(args);
|
|
161
187
|
const valueFlags = ["--limit", "--offset"];
|
|
162
|
-
assertKnownFlags(parsedArgs, [...valueFlags, "--incoming", "--outgoing", "--help", "-h"], valueFlags);
|
|
188
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--incoming", "--outgoing", "--handoffs", "--help", "-h"], valueFlags);
|
|
163
189
|
const extra = positionalArgs(parsedArgs, valueFlags);
|
|
164
190
|
if (extra.length > 0) {
|
|
165
191
|
fail({ code: "BAD_USAGE", message: `Unexpected argument for transfer list: ${extra[0]}` });
|
|
166
192
|
}
|
|
193
|
+
|
|
194
|
+
// Email->org handoffs ride the same rail but have their own incoming inbox.
|
|
195
|
+
if (parsedArgs.includes("--handoffs")) {
|
|
196
|
+
allowanceAuthHeaders("/agent/v1/handoffs/incoming");
|
|
197
|
+
try {
|
|
198
|
+
const handoffs = await getSdk().admin.transfers.listIncomingHandoffs();
|
|
199
|
+
console.log(JSON.stringify({ kind: "handoffs", handoffs }, null, 2));
|
|
200
|
+
} catch (err) {
|
|
201
|
+
reportSdkError(err);
|
|
202
|
+
}
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
167
206
|
const incoming = parsedArgs.includes("--incoming");
|
|
168
207
|
const outgoing = parsedArgs.includes("--outgoing");
|
|
169
208
|
if (incoming && outgoing) {
|
|
@@ -216,17 +255,42 @@ async function accept(args) {
|
|
|
216
255
|
async function cancel(args) {
|
|
217
256
|
const parsedArgs = normalizeArgv(args);
|
|
218
257
|
const valueFlags = ["--reason"];
|
|
219
|
-
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
258
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--handoff", "--help", "-h"], valueFlags);
|
|
220
259
|
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
221
260
|
if (positionals.length !== 1) {
|
|
222
|
-
fail({ code: "BAD_USAGE", message: "Usage: run402 transfer cancel <transfer_id> [--reason <text>]" });
|
|
261
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 transfer cancel <transfer_id> [--reason <text>] [--handoff]" });
|
|
223
262
|
}
|
|
224
263
|
const transferId = positionals[0];
|
|
225
264
|
const reason = flagValue(parsedArgs, "--reason");
|
|
226
|
-
|
|
265
|
+
const handoff = parsedArgs.includes("--handoff");
|
|
266
|
+
allowanceAuthHeaders(`/agent/v1/${handoff ? "handoffs" : "transfers"}/${transferId}/cancel`);
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
const data = handoff
|
|
270
|
+
? await getSdk().admin.transfers.cancelHandoff(transferId)
|
|
271
|
+
: await getSdk().admin.transfers.cancel(transferId, reason ?? undefined);
|
|
272
|
+
console.log(JSON.stringify(data, null, 2));
|
|
273
|
+
} catch (err) {
|
|
274
|
+
reportSdkError(err);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async function claim(args) {
|
|
279
|
+
const parsedArgs = normalizeArgv(args);
|
|
280
|
+
const valueFlags = ["--into"];
|
|
281
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
282
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
283
|
+
if (positionals.length !== 1) {
|
|
284
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 transfer claim <transfer_id> [--into <billing_account_id>]" });
|
|
285
|
+
}
|
|
286
|
+
const transferId = positionals[0];
|
|
287
|
+
const into = flagValue(parsedArgs, "--into");
|
|
288
|
+
allowanceAuthHeaders(`/agent/v1/handoffs/${transferId}/claim`);
|
|
227
289
|
|
|
228
290
|
try {
|
|
229
|
-
const data = await getSdk().admin.transfers.
|
|
291
|
+
const data = await getSdk().admin.transfers.claimHandoff(transferId, {
|
|
292
|
+
billingAccountId: into ?? undefined,
|
|
293
|
+
});
|
|
230
294
|
console.log(JSON.stringify(data, null, 2));
|
|
231
295
|
} catch (err) {
|
|
232
296
|
reportSdkError(err);
|
|
@@ -255,6 +319,9 @@ export async function run(sub, args) {
|
|
|
255
319
|
case "accept":
|
|
256
320
|
await accept(args);
|
|
257
321
|
return;
|
|
322
|
+
case "claim":
|
|
323
|
+
await claim(args);
|
|
324
|
+
return;
|
|
258
325
|
case "cancel":
|
|
259
326
|
await cancel(args);
|
|
260
327
|
return;
|
package/package.json
CHANGED