run402 2.43.0 → 2.45.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 +1 -1
- package/cli.mjs +1 -1
- package/lib/admin.mjs +22 -22
- package/lib/allowance.mjs +8 -4
- package/lib/billing.mjs +123 -125
- package/lib/operator.mjs +3 -3
- package/lib/projects.mjs +4 -4
- package/lib/sdk-errors.mjs +1 -1
- package/lib/service.mjs +1 -1
- package/lib/status.mjs +5 -5
- package/lib/tier.mjs +4 -4
- package/lib/transfer.mjs +5 -5
- package/package.json +1 -1
- package/sdk/dist/errors.d.ts +8 -8
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +6 -6
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/namespaces/admin.d.ts +15 -16
- package/sdk/dist/namespaces/admin.d.ts.map +1 -1
- package/sdk/dist/namespaces/admin.js +14 -15
- package/sdk/dist/namespaces/admin.js.map +1 -1
- package/sdk/dist/namespaces/billing.d.ts +66 -62
- package/sdk/dist/namespaces/billing.d.ts.map +1 -1
- package/sdk/dist/namespaces/billing.js +96 -106
- package/sdk/dist/namespaces/billing.js.map +1 -1
- package/sdk/dist/namespaces/operator.d.ts +3 -3
- package/sdk/dist/namespaces/operator.d.ts.map +1 -1
- package/sdk/dist/namespaces/operator.js +1 -1
- package/sdk/dist/namespaces/org.types.d.ts +2 -2
- package/sdk/dist/namespaces/org.types.js +1 -1
- package/sdk/dist/namespaces/projects.d.ts +2 -2
- package/sdk/dist/namespaces/projects.js +2 -2
- package/sdk/dist/namespaces/projects.types.d.ts +15 -15
- package/sdk/dist/namespaces/projects.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/tier.d.ts +11 -11
- package/sdk/dist/namespaces/tier.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.d.ts +8 -8
- package/sdk/dist/namespaces/transfers.d.ts.map +1 -1
- package/sdk/dist/namespaces/transfers.js +3 -3
- package/sdk/dist/namespaces/transfers.js.map +1 -1
package/README.md
CHANGED
|
@@ -188,7 +188,7 @@ Private keys never leave AWS KMS. $0.04/day rental + $0.000005/call.
|
|
|
188
188
|
```bash
|
|
189
189
|
run402 tier set prototype # free on testnet
|
|
190
190
|
run402 tier set hobby # $5 / 30 days
|
|
191
|
-
run402 billing
|
|
191
|
+
run402 billing checkout <org_id> --product tier --tier hobby # Stripe alternative
|
|
192
192
|
```
|
|
193
193
|
|
|
194
194
|
## State
|
package/cli.mjs
CHANGED
|
@@ -47,7 +47,7 @@ Commands:
|
|
|
47
47
|
message Send messages to Run402 developers
|
|
48
48
|
auth Manage project user authentication (magic link, passwords, settings)
|
|
49
49
|
sender-domain Manage custom email sender domain (register, status, remove)
|
|
50
|
-
billing Email
|
|
50
|
+
billing Email organizations, Stripe tier checkout, email packs
|
|
51
51
|
contracts KMS contract wallets ($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
|
package/lib/admin.mjs
CHANGED
|
@@ -8,9 +8,9 @@ Usage:
|
|
|
8
8
|
run402 admin <subcommand> [args...]
|
|
9
9
|
|
|
10
10
|
Subcommands:
|
|
11
|
-
lease-perpetual <
|
|
12
|
-
Toggle the
|
|
13
|
-
When enabled, the
|
|
11
|
+
lease-perpetual <organization_id> (--enable | --disable)
|
|
12
|
+
Toggle the organization-level escape hatch.
|
|
13
|
+
When enabled, the organization never advances
|
|
14
14
|
past 'active' regardless of lease expiry.
|
|
15
15
|
If the account is currently in a grace
|
|
16
16
|
state, enabling reactivates it inline
|
|
@@ -19,12 +19,12 @@ Subcommands:
|
|
|
19
19
|
|
|
20
20
|
archive <project_id> [--reason "..."] Moderate-archive a single project. Sets
|
|
21
21
|
projects.archived_at = NOW(). Independent
|
|
22
|
-
of
|
|
23
|
-
|
|
22
|
+
of organization lifecycle; the rest of the
|
|
23
|
+
organization's projects keep serving.
|
|
24
24
|
|
|
25
25
|
reactivate <project_id> Un-archive a project (flips archived_at
|
|
26
26
|
back to NULL). In v1.57 this no longer
|
|
27
|
-
touches
|
|
27
|
+
touches organization-level lifecycle — to
|
|
28
28
|
reactivate a grace-state account, use
|
|
29
29
|
\`tier set <tier>\` or enable
|
|
30
30
|
lease-perpetual above.
|
|
@@ -36,17 +36,17 @@ Notes:
|
|
|
36
36
|
- Output is JSON.
|
|
37
37
|
|
|
38
38
|
Examples:
|
|
39
|
-
run402 admin lease-perpetual
|
|
40
|
-
run402 admin lease-perpetual
|
|
39
|
+
run402 admin lease-perpetual org_abc123 --enable
|
|
40
|
+
run402 admin lease-perpetual org_abc123 --disable
|
|
41
41
|
run402 admin archive prj_abuse --reason "ToS violation"
|
|
42
42
|
run402 admin reactivate prj_abuse
|
|
43
43
|
`;
|
|
44
44
|
|
|
45
45
|
const SUB_HELP = {
|
|
46
|
-
"lease-perpetual": `run402 admin lease-perpetual — Toggle the
|
|
46
|
+
"lease-perpetual": `run402 admin lease-perpetual — Toggle the organization-level escape hatch
|
|
47
47
|
|
|
48
48
|
Usage:
|
|
49
|
-
run402 admin lease-perpetual <
|
|
49
|
+
run402 admin lease-perpetual <organization_id> (--enable | --disable)
|
|
50
50
|
|
|
51
51
|
Options:
|
|
52
52
|
--enable Set lease_perpetual = true (pins every project on the account)
|
|
@@ -59,8 +59,8 @@ Notes:
|
|
|
59
59
|
the gateway reactivates inline and reports \`reactivated: true\`.
|
|
60
60
|
|
|
61
61
|
Examples:
|
|
62
|
-
run402 admin lease-perpetual
|
|
63
|
-
run402 admin lease-perpetual
|
|
62
|
+
run402 admin lease-perpetual org_abc123 --enable
|
|
63
|
+
run402 admin lease-perpetual org_abc123 --disable
|
|
64
64
|
`,
|
|
65
65
|
archive: `run402 admin archive — Moderate-archive a single project
|
|
66
66
|
|
|
@@ -71,8 +71,8 @@ Options:
|
|
|
71
71
|
--reason <text> Free-text moderation reason recorded in the audit log.
|
|
72
72
|
|
|
73
73
|
Notes:
|
|
74
|
-
- Sets projects.archived_at = NOW(). Independent of
|
|
75
|
-
only this project goes dark; siblings on the same
|
|
74
|
+
- Sets projects.archived_at = NOW(). Independent of organization-level lifecycle —
|
|
75
|
+
only this project goes dark; siblings on the same organization keep
|
|
76
76
|
serving.
|
|
77
77
|
- No-op when the project is already archived (returns \`note: "already
|
|
78
78
|
archived"\` without changing archived_at).
|
|
@@ -88,9 +88,9 @@ Usage:
|
|
|
88
88
|
|
|
89
89
|
Notes:
|
|
90
90
|
- Flips projects.archived_at back to NULL. In v1.57 this was narrowed:
|
|
91
|
-
|
|
91
|
+
organization-level lifecycle reactivation is NOT triggered. Use
|
|
92
92
|
\`run402 tier set <tier>\` (the tier flow runs the lifecycle advance) or
|
|
93
|
-
\`run402 admin lease-perpetual <
|
|
93
|
+
\`run402 admin lease-perpetual <org_id> --enable\` for that.
|
|
94
94
|
- No-op when the project is not archived (returns \`note: "not archived"\`).
|
|
95
95
|
|
|
96
96
|
Examples:
|
|
@@ -110,25 +110,25 @@ function validateFlags(sub, args) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
async function leasePerpetual(args) {
|
|
113
|
-
const
|
|
113
|
+
const organizationId = args.find((a) => typeof a === "string" && !a.startsWith("--"));
|
|
114
114
|
const enable = args.includes("--enable");
|
|
115
115
|
const disable = args.includes("--disable");
|
|
116
|
-
if (!
|
|
116
|
+
if (!organizationId) {
|
|
117
117
|
fail({
|
|
118
118
|
code: "BAD_USAGE",
|
|
119
|
-
message: "Missing <
|
|
120
|
-
hint: "run402 admin lease-perpetual <
|
|
119
|
+
message: "Missing <organization_id>.",
|
|
120
|
+
hint: "run402 admin lease-perpetual <organization_id> --enable | --disable",
|
|
121
121
|
});
|
|
122
122
|
}
|
|
123
123
|
if (enable === disable) {
|
|
124
124
|
fail({
|
|
125
125
|
code: "BAD_USAGE",
|
|
126
126
|
message: "Pass exactly one of --enable / --disable.",
|
|
127
|
-
hint: "run402 admin lease-perpetual <
|
|
127
|
+
hint: "run402 admin lease-perpetual <organization_id> --enable | --disable",
|
|
128
128
|
});
|
|
129
129
|
}
|
|
130
130
|
try {
|
|
131
|
-
const data = await getSdk().admin.setLeasePerpetual(
|
|
131
|
+
const data = await getSdk().admin.setLeasePerpetual(organizationId, enable);
|
|
132
132
|
console.log(JSON.stringify(data, null, 2));
|
|
133
133
|
} catch (err) {
|
|
134
134
|
reportSdkError(err);
|
package/lib/allowance.mjs
CHANGED
|
@@ -14,7 +14,7 @@ Subcommands:
|
|
|
14
14
|
fund Request test funds from the faucet (Base Sepolia or Tempo)
|
|
15
15
|
balance Show on-chain balances and Run402 billing balance
|
|
16
16
|
export Print the allowance address (useful for scripting)
|
|
17
|
-
checkout Create
|
|
17
|
+
checkout Create an org balance checkout session (--amount <usd_micros>)
|
|
18
18
|
history View billing transaction history (--limit <n>)
|
|
19
19
|
|
|
20
20
|
Notes:
|
|
@@ -33,7 +33,7 @@ Examples:
|
|
|
33
33
|
`;
|
|
34
34
|
|
|
35
35
|
const SUB_HELP = {
|
|
36
|
-
checkout: `run402 allowance checkout — Create
|
|
36
|
+
checkout: `run402 allowance checkout — Create an org balance checkout session
|
|
37
37
|
|
|
38
38
|
Usage:
|
|
39
39
|
run402 allowance checkout --amount <usd_micros>
|
|
@@ -238,7 +238,7 @@ async function balance() {
|
|
|
238
238
|
"base-sepolia_usd_micros": sepoliaUsdc,
|
|
239
239
|
"tempo-moderato_pathusd_micros": tempoPathUsd,
|
|
240
240
|
},
|
|
241
|
-
run402: billingRes ? { balance_usd_micros: billingRes.available_usd_micros } : "no
|
|
241
|
+
run402: billingRes ? { balance_usd_micros: billingRes.available_usd_micros } : "no organization",
|
|
242
242
|
}, null, 2));
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -280,7 +280,11 @@ async function checkout(args) {
|
|
|
280
280
|
}
|
|
281
281
|
const amount = parseIntegerFlag("--amount", amountRaw, { min: 1 });
|
|
282
282
|
try {
|
|
283
|
-
const
|
|
283
|
+
const org = await getSdk().billing.lookupOrganization(w.address);
|
|
284
|
+
const data = await getSdk().billing.createCheckout(org.organization_id, {
|
|
285
|
+
product: "balance_topup",
|
|
286
|
+
amountUsdMicros: amount,
|
|
287
|
+
});
|
|
284
288
|
console.log(JSON.stringify(data, null, 2));
|
|
285
289
|
} catch (err) {
|
|
286
290
|
reportSdkError(err);
|
package/lib/billing.mjs
CHANGED
|
@@ -2,88 +2,78 @@ import { getSdk } from "./sdk.mjs";
|
|
|
2
2
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
3
3
|
import { assertKnownFlags, flagValue, normalizeArgv, parseIntegerFlag, positionalArgs } from "./argparse.mjs";
|
|
4
4
|
|
|
5
|
-
const HELP = `run402 billing — Email
|
|
5
|
+
const HELP = `run402 billing — Email organizations and org checkouts
|
|
6
6
|
|
|
7
7
|
Usage:
|
|
8
8
|
run402 billing <subcommand> [args...]
|
|
9
9
|
|
|
10
10
|
Subcommands:
|
|
11
|
-
create-email <email> Create an email
|
|
12
|
-
link-wallet <
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
history <identifier> [--limit <n>] Ledger history by account id (UUID), wallet, or email
|
|
11
|
+
create-email <email> Create an email organization
|
|
12
|
+
link-wallet <org_id> <wallet> Link a wallet to an email organization
|
|
13
|
+
checkout <identifier> --product <p> Create an org checkout
|
|
14
|
+
auto-recharge <org_id> <on|off> [--threshold <n>]
|
|
15
|
+
balance <identifier> Balance by organization id (UUID), wallet (0x...), or email
|
|
16
|
+
history <identifier> [--limit <n>] Ledger history by organization id (UUID), wallet, or email
|
|
18
17
|
|
|
19
18
|
Examples:
|
|
20
19
|
run402 billing create-email user@example.com
|
|
21
|
-
run402 billing
|
|
22
|
-
run402 billing
|
|
23
|
-
run402 billing
|
|
20
|
+
run402 billing checkout 00000000-0000-4000-8000-000000000001 --product tier --tier hobby
|
|
21
|
+
run402 billing checkout 0x1234... --product email-pack
|
|
22
|
+
run402 billing checkout 0x1234... --product balance-topup --amount 5000000
|
|
23
|
+
run402 billing auto-recharge org_abc on --threshold 2000
|
|
24
24
|
run402 billing balance user@example.com
|
|
25
25
|
`;
|
|
26
26
|
|
|
27
27
|
const SUB_HELP = {
|
|
28
|
-
|
|
28
|
+
checkout: `run402 billing checkout — Create an org checkout
|
|
29
29
|
|
|
30
30
|
Usage:
|
|
31
|
-
run402 billing
|
|
31
|
+
run402 billing checkout <identifier> --product <tier|email-pack|balance-topup> [options]
|
|
32
32
|
|
|
33
33
|
Arguments:
|
|
34
|
-
<
|
|
34
|
+
<identifier> Organization id (UUID), wallet (0x...), or email.
|
|
35
|
+
Wallet/email are resolved to the organization id first.
|
|
35
36
|
|
|
36
37
|
Options:
|
|
37
|
-
--
|
|
38
|
-
--
|
|
38
|
+
--product <p> tier, email-pack, or balance-topup
|
|
39
|
+
--tier <tier> Tier name for --product tier
|
|
40
|
+
--amount <n> USD micros for --product balance-topup
|
|
39
41
|
|
|
40
42
|
Examples:
|
|
41
|
-
run402 billing
|
|
42
|
-
run402 billing
|
|
43
|
-
|
|
44
|
-
"buy-email-pack": `run402 billing buy-email-pack — Buy a $5 email pack (10,000 emails)
|
|
45
|
-
|
|
46
|
-
Usage:
|
|
47
|
-
run402 billing buy-email-pack [--email <e> | --wallet <w>]
|
|
48
|
-
|
|
49
|
-
Options:
|
|
50
|
-
--email <e> Email billing account to charge
|
|
51
|
-
--wallet <w> Wallet address (0x...) to associate with the purchase
|
|
52
|
-
|
|
53
|
-
Examples:
|
|
54
|
-
run402 billing buy-email-pack --email user@example.com
|
|
55
|
-
run402 billing buy-email-pack --wallet 0x1234...
|
|
43
|
+
run402 billing checkout 00000000-0000-4000-8000-000000000001 --product tier --tier hobby
|
|
44
|
+
run402 billing checkout 0x1234... --product email-pack
|
|
45
|
+
run402 billing checkout 0x1234... --product balance-topup --amount 5000000
|
|
56
46
|
`,
|
|
57
47
|
"auto-recharge": `run402 billing auto-recharge — Toggle email-pack auto-recharge
|
|
58
48
|
|
|
59
49
|
Usage:
|
|
60
|
-
run402 billing auto-recharge <
|
|
50
|
+
run402 billing auto-recharge <org_id> <on|off> [--threshold <n>]
|
|
61
51
|
|
|
62
52
|
Arguments:
|
|
63
|
-
<
|
|
53
|
+
<org_id> Organization ID
|
|
64
54
|
<on|off> Enable or disable auto-recharge
|
|
65
55
|
|
|
66
56
|
Options:
|
|
67
57
|
--threshold <n> Remaining-email threshold that triggers auto-recharge
|
|
68
58
|
|
|
69
59
|
Examples:
|
|
70
|
-
run402 billing auto-recharge
|
|
71
|
-
run402 billing auto-recharge
|
|
60
|
+
run402 billing auto-recharge org_abc on --threshold 2000
|
|
61
|
+
run402 billing auto-recharge org_abc off
|
|
72
62
|
`,
|
|
73
|
-
history: `run402 billing history — Show ledger history for a
|
|
63
|
+
history: `run402 billing history — Show ledger history for a organization
|
|
74
64
|
|
|
75
65
|
Usage:
|
|
76
66
|
run402 billing history <identifier> [--limit <n>]
|
|
77
67
|
|
|
78
68
|
Arguments:
|
|
79
|
-
<identifier>
|
|
80
|
-
Wallet/email are resolved to the
|
|
69
|
+
<identifier> Organization id (UUID), wallet (0x...), or email.
|
|
70
|
+
Wallet/email are resolved to the organization id first.
|
|
81
71
|
|
|
82
72
|
Options:
|
|
83
73
|
--limit <n> Max entries to return (default: 50)
|
|
84
74
|
|
|
85
75
|
Auth:
|
|
86
|
-
Requires SIWX from a wallet linked to the
|
|
76
|
+
Requires SIWX from a wallet linked to the organization (signed automatically from
|
|
87
77
|
the local allowance), or an admin key. Email lookups require an admin key.
|
|
88
78
|
|
|
89
79
|
Examples:
|
|
@@ -91,17 +81,17 @@ Examples:
|
|
|
91
81
|
run402 billing history 0x1234... --limit 100
|
|
92
82
|
run402 billing history 00000000-0000-4000-8000-000000000001
|
|
93
83
|
`,
|
|
94
|
-
balance: `run402 billing balance — Show balance for a
|
|
84
|
+
balance: `run402 billing balance — Show balance for a organization
|
|
95
85
|
|
|
96
86
|
Usage:
|
|
97
87
|
run402 billing balance <identifier>
|
|
98
88
|
|
|
99
89
|
Arguments:
|
|
100
|
-
<identifier>
|
|
101
|
-
Wallet/email are resolved via the
|
|
90
|
+
<identifier> Organization id (UUID), wallet (0x...), or email.
|
|
91
|
+
Wallet/email are resolved via the organization lookup.
|
|
102
92
|
|
|
103
93
|
Auth:
|
|
104
|
-
Requires SIWX from a wallet linked to the
|
|
94
|
+
Requires SIWX from a wallet linked to the organization (signed automatically from
|
|
105
95
|
the local allowance), or an admin key. Email lookups require an admin key.
|
|
106
96
|
|
|
107
97
|
Examples:
|
|
@@ -109,56 +99,111 @@ Examples:
|
|
|
109
99
|
run402 billing balance 0x1234abcd...
|
|
110
100
|
run402 billing balance 00000000-0000-4000-8000-000000000001
|
|
111
101
|
`,
|
|
112
|
-
"create-email": `run402 billing create-email — Create an email
|
|
102
|
+
"create-email": `run402 billing create-email — Create an email organization
|
|
113
103
|
|
|
114
104
|
Usage:
|
|
115
105
|
run402 billing create-email <email>
|
|
116
106
|
|
|
117
107
|
Arguments:
|
|
118
|
-
<email> Email address to register as a
|
|
108
|
+
<email> Email address to register as a organization
|
|
119
109
|
|
|
120
110
|
Examples:
|
|
121
111
|
run402 billing create-email user@example.com
|
|
122
112
|
`,
|
|
123
|
-
"link-wallet": `run402 billing link-wallet — Link a wallet to an email
|
|
113
|
+
"link-wallet": `run402 billing link-wallet — Link a wallet to an email organization
|
|
124
114
|
|
|
125
115
|
Usage:
|
|
126
|
-
run402 billing link-wallet <
|
|
116
|
+
run402 billing link-wallet <org_id> <wallet>
|
|
127
117
|
|
|
128
118
|
Arguments:
|
|
129
|
-
<
|
|
119
|
+
<org_id> Organization ID (e.g. org_abc123)
|
|
130
120
|
<wallet> Wallet address (0x...) to link
|
|
131
121
|
|
|
132
122
|
Notes:
|
|
133
|
-
- Tier and quotas are per-
|
|
134
|
-
spend into the
|
|
135
|
-
on this
|
|
123
|
+
- Tier and quotas are per-organization. Linking a wallet merges its
|
|
124
|
+
spend into the organization-wide pool that already includes every project
|
|
125
|
+
on this organization.
|
|
136
126
|
- The response includes a 'pool_implications' block on v1.46+ gateways:
|
|
137
|
-
tier, projects_in_pool_count,
|
|
138
|
-
|
|
127
|
+
tier, projects_in_pool_count, organization_api_calls_current,
|
|
128
|
+
organization_storage_bytes_current, tier_limits, over_limit. Inspect
|
|
139
129
|
'over_limit' before linking a wallet whose existing usage might push
|
|
140
130
|
the merged pool past the tier cap.
|
|
141
131
|
|
|
142
132
|
Examples:
|
|
143
|
-
run402 billing link-wallet
|
|
133
|
+
run402 billing link-wallet org_abc123 0x1234abcd...
|
|
144
134
|
`,
|
|
145
135
|
};
|
|
146
136
|
|
|
147
|
-
function
|
|
148
|
-
if (
|
|
137
|
+
function normalizeCheckoutProduct(raw) {
|
|
138
|
+
if (!raw) {
|
|
149
139
|
fail({
|
|
150
140
|
code: "BAD_USAGE",
|
|
151
|
-
message: "
|
|
152
|
-
hint: "
|
|
141
|
+
message: "Missing --product.",
|
|
142
|
+
hint: "Use --product tier, --product email-pack, or --product balance-topup.",
|
|
153
143
|
});
|
|
154
144
|
}
|
|
155
|
-
|
|
145
|
+
const product = String(raw).replace(/-/g, "_");
|
|
146
|
+
if (product === "tier" || product === "email_pack" || product === "balance_topup") {
|
|
147
|
+
return product;
|
|
148
|
+
}
|
|
149
|
+
fail({
|
|
150
|
+
code: "BAD_USAGE",
|
|
151
|
+
message: `Unknown checkout product: ${raw}`,
|
|
152
|
+
hint: "Use tier, email-pack, or balance-topup.",
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function checkout(args) {
|
|
157
|
+
const parsedArgs = normalizeArgv(args);
|
|
158
|
+
const valueFlags = ["--product", "--tier", "--amount"];
|
|
159
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
160
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
161
|
+
const identifier = positionals[0];
|
|
162
|
+
if (positionals.length > 1) {
|
|
163
|
+
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing checkout: ${positionals[1]}` });
|
|
164
|
+
}
|
|
165
|
+
if (!identifier) {
|
|
156
166
|
fail({
|
|
157
167
|
code: "BAD_USAGE",
|
|
158
|
-
message: "
|
|
159
|
-
hint: "
|
|
168
|
+
message: "Missing <identifier>.",
|
|
169
|
+
hint: "run402 billing checkout <identifier> --product <tier|email-pack|balance-topup>",
|
|
160
170
|
});
|
|
161
171
|
}
|
|
172
|
+
const product = normalizeCheckoutProduct(flagValue(parsedArgs, "--product"));
|
|
173
|
+
let checkoutRequest;
|
|
174
|
+
if (product === "tier") {
|
|
175
|
+
const tier = flagValue(parsedArgs, "--tier");
|
|
176
|
+
if (!tier) {
|
|
177
|
+
fail({
|
|
178
|
+
code: "BAD_USAGE",
|
|
179
|
+
message: "Missing --tier for tier checkout.",
|
|
180
|
+
hint: "run402 billing checkout <identifier> --product tier --tier hobby",
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
checkoutRequest = { product: "tier", tier };
|
|
184
|
+
} else if (product === "email_pack") {
|
|
185
|
+
checkoutRequest = { product: "email_pack" };
|
|
186
|
+
} else {
|
|
187
|
+
const amountRaw = flagValue(parsedArgs, "--amount");
|
|
188
|
+
if (amountRaw === null) {
|
|
189
|
+
fail({
|
|
190
|
+
code: "BAD_USAGE",
|
|
191
|
+
message: "Missing --amount for balance-topup checkout.",
|
|
192
|
+
hint: "run402 billing checkout <identifier> --product balance-topup --amount 5000000",
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
checkoutRequest = {
|
|
196
|
+
product: "balance_topup",
|
|
197
|
+
amountUsdMicros: parseIntegerFlag("--amount", amountRaw, { min: 1 }),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
const org = await getSdk().billing.lookupOrganization(identifier);
|
|
202
|
+
const data = await getSdk().billing.createCheckout(org.organization_id, checkoutRequest);
|
|
203
|
+
console.log(JSON.stringify(data, null, 2));
|
|
204
|
+
} catch (err) {
|
|
205
|
+
reportSdkError(err);
|
|
206
|
+
}
|
|
162
207
|
}
|
|
163
208
|
|
|
164
209
|
async function createEmail(args) {
|
|
@@ -177,7 +222,7 @@ async function createEmail(args) {
|
|
|
177
222
|
});
|
|
178
223
|
}
|
|
179
224
|
try {
|
|
180
|
-
const data = await getSdk().billing.
|
|
225
|
+
const data = await getSdk().billing.createEmailOrganization(email);
|
|
181
226
|
console.log(JSON.stringify(data, null, 2));
|
|
182
227
|
} catch (err) {
|
|
183
228
|
reportSdkError(err);
|
|
@@ -188,23 +233,23 @@ async function linkWallet(args) {
|
|
|
188
233
|
const parsedArgs = normalizeArgv(args);
|
|
189
234
|
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
190
235
|
const positionals = positionalArgs(parsedArgs);
|
|
191
|
-
const
|
|
236
|
+
const organizationId = positionals[0];
|
|
192
237
|
const wallet = positionals[1];
|
|
193
238
|
if (positionals.length > 2) {
|
|
194
239
|
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing link-wallet: ${positionals[2]}` });
|
|
195
240
|
}
|
|
196
|
-
if (!
|
|
241
|
+
if (!organizationId || !wallet) {
|
|
197
242
|
fail({
|
|
198
243
|
code: "BAD_USAGE",
|
|
199
|
-
message: "Missing <
|
|
200
|
-
hint: "run402 billing link-wallet <
|
|
244
|
+
message: "Missing <org_id> and/or <wallet>.",
|
|
245
|
+
hint: "run402 billing link-wallet <org_id> <wallet>",
|
|
201
246
|
});
|
|
202
247
|
}
|
|
203
248
|
try {
|
|
204
|
-
const data = await getSdk().billing.linkWallet(
|
|
249
|
+
const data = await getSdk().billing.linkWallet(organizationId, wallet);
|
|
205
250
|
const output = {
|
|
206
251
|
status: data?.status ?? "ok",
|
|
207
|
-
|
|
252
|
+
organization_id: data?.organization_id ?? organizationId,
|
|
208
253
|
wallet: data?.wallet ?? wallet.toLowerCase(),
|
|
209
254
|
...(data?.pool_implications ? { pool_implications: data.pool_implications } : {}),
|
|
210
255
|
};
|
|
@@ -214,67 +259,21 @@ async function linkWallet(args) {
|
|
|
214
259
|
}
|
|
215
260
|
}
|
|
216
261
|
|
|
217
|
-
async function tierCheckout(args) {
|
|
218
|
-
const parsedArgs = normalizeArgv(args);
|
|
219
|
-
const valueFlags = ["--email", "--wallet"];
|
|
220
|
-
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
221
|
-
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
222
|
-
const tier = positionals[0];
|
|
223
|
-
if (positionals.length > 1) {
|
|
224
|
-
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing tier-checkout: ${positionals[1]}` });
|
|
225
|
-
}
|
|
226
|
-
if (!tier) {
|
|
227
|
-
fail({
|
|
228
|
-
code: "BAD_USAGE",
|
|
229
|
-
message: "Missing <tier>.",
|
|
230
|
-
hint: "run402 billing tier-checkout <tier> [--email <e> | --wallet <w>]",
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
const email = flagValue(parsedArgs, "--email");
|
|
234
|
-
const wallet = flagValue(parsedArgs, "--wallet");
|
|
235
|
-
requireSingleBillingIdentifier(email, wallet);
|
|
236
|
-
try {
|
|
237
|
-
const data = await getSdk().billing.tierCheckout(tier, { email: email ?? undefined, wallet: wallet ?? undefined });
|
|
238
|
-
console.log(JSON.stringify(data, null, 2));
|
|
239
|
-
} catch (err) {
|
|
240
|
-
reportSdkError(err);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
async function buyPack(args) {
|
|
245
|
-
const parsedArgs = normalizeArgv(args);
|
|
246
|
-
const valueFlags = ["--email", "--wallet"];
|
|
247
|
-
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
248
|
-
const extra = positionalArgs(parsedArgs, valueFlags);
|
|
249
|
-
if (extra.length > 0) {
|
|
250
|
-
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing buy-email-pack: ${extra[0]}` });
|
|
251
|
-
}
|
|
252
|
-
const email = flagValue(parsedArgs, "--email");
|
|
253
|
-
const wallet = flagValue(parsedArgs, "--wallet");
|
|
254
|
-
requireSingleBillingIdentifier(email, wallet);
|
|
255
|
-
try {
|
|
256
|
-
const data = await getSdk().billing.buyEmailPack({ email: email ?? undefined, wallet: wallet ?? undefined });
|
|
257
|
-
console.log(JSON.stringify(data, null, 2));
|
|
258
|
-
} catch (err) {
|
|
259
|
-
reportSdkError(err);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
262
|
async function autoRecharge(args) {
|
|
264
263
|
const parsedArgs = normalizeArgv(args);
|
|
265
264
|
const valueFlags = ["--threshold"];
|
|
266
265
|
assertKnownFlags(parsedArgs, [...valueFlags, "--help", "-h"], valueFlags);
|
|
267
266
|
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
268
|
-
const
|
|
267
|
+
const organizationId = positionals[0];
|
|
269
268
|
const state = positionals[1];
|
|
270
269
|
if (positionals.length > 2) {
|
|
271
270
|
fail({ code: "BAD_USAGE", message: `Unexpected argument for billing auto-recharge: ${positionals[2]}` });
|
|
272
271
|
}
|
|
273
|
-
if (!
|
|
272
|
+
if (!organizationId || !state || !["on", "off"].includes(state)) {
|
|
274
273
|
fail({
|
|
275
274
|
code: "BAD_USAGE",
|
|
276
|
-
message: "Missing <
|
|
277
|
-
hint: "run402 billing auto-recharge <
|
|
275
|
+
message: "Missing <org_id> and/or <on|off>.",
|
|
276
|
+
hint: "run402 billing auto-recharge <org_id> <on|off> [--threshold <n>]",
|
|
278
277
|
});
|
|
279
278
|
}
|
|
280
279
|
const thresholdStr = flagValue(parsedArgs, "--threshold");
|
|
@@ -283,11 +282,11 @@ async function autoRecharge(args) {
|
|
|
283
282
|
: undefined;
|
|
284
283
|
try {
|
|
285
284
|
await getSdk().billing.setAutoRecharge({
|
|
286
|
-
|
|
285
|
+
organizationId: organizationId,
|
|
287
286
|
enabled: state === "on",
|
|
288
287
|
threshold,
|
|
289
288
|
});
|
|
290
|
-
console.log(JSON.stringify({
|
|
289
|
+
console.log(JSON.stringify({ organization_id: organizationId, enabled: state === "on", updated: true }));
|
|
291
290
|
} catch (err) {
|
|
292
291
|
reportSdkError(err);
|
|
293
292
|
}
|
|
@@ -305,11 +304,11 @@ async function balance(args) {
|
|
|
305
304
|
fail({
|
|
306
305
|
code: "BAD_USAGE",
|
|
307
306
|
message: "Missing <identifier>.",
|
|
308
|
-
hint: "run402 billing balance <
|
|
307
|
+
hint: "run402 billing balance <org-id | wallet | email>",
|
|
309
308
|
});
|
|
310
309
|
}
|
|
311
310
|
try {
|
|
312
|
-
const data = await getSdk().billing.
|
|
311
|
+
const data = await getSdk().billing.getOrganization(id);
|
|
313
312
|
console.log(JSON.stringify(data, null, 2));
|
|
314
313
|
} catch (err) {
|
|
315
314
|
reportSdkError(err);
|
|
@@ -329,7 +328,7 @@ async function history(args) {
|
|
|
329
328
|
fail({
|
|
330
329
|
code: "BAD_USAGE",
|
|
331
330
|
message: "Missing <identifier>.",
|
|
332
|
-
hint: "run402 billing history <
|
|
331
|
+
hint: "run402 billing history <org-id | wallet | email> [--limit <n>]",
|
|
333
332
|
});
|
|
334
333
|
}
|
|
335
334
|
const limit = parsedArgs.includes("--limit")
|
|
@@ -349,8 +348,7 @@ export async function run(sub, args) {
|
|
|
349
348
|
switch (sub) {
|
|
350
349
|
case "create-email": await createEmail(args); break;
|
|
351
350
|
case "link-wallet": await linkWallet(args); break;
|
|
352
|
-
case "
|
|
353
|
-
case "buy-email-pack": await buyPack(args); break;
|
|
351
|
+
case "checkout": await checkout(args); break;
|
|
354
352
|
case "auto-recharge": await autoRecharge(args); break;
|
|
355
353
|
case "balance": await balance(args); break;
|
|
356
354
|
case "history": await history(args); break;
|
package/lib/operator.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The operator is YOU, the human, identified by email — distinct from the
|
|
5
5
|
* AGENT (your wallet / SIWX identity). One browser login spans every wallet
|
|
6
6
|
* that verified your email, so `operator overview` returns the cross-wallet
|
|
7
|
-
* union. For a single wallet's
|
|
7
|
+
* union. For a single wallet's organization state, use `run402 status`.
|
|
8
8
|
*
|
|
9
9
|
* Auth: browser-delegated device-authorization grant (RFC 8628, the
|
|
10
10
|
* `aws sso login` model). The CLI never performs WebAuthn — the browser does,
|
|
@@ -47,7 +47,7 @@ const HELP = `run402 operator — operator (human / email) session
|
|
|
47
47
|
|
|
48
48
|
The operator is YOU, the human, identified by email — distinct from the agent
|
|
49
49
|
(your wallet). One browser login spans every wallet that verified your email.
|
|
50
|
-
For a single wallet's
|
|
50
|
+
For a single wallet's organization state, use 'run402 status'.
|
|
51
51
|
|
|
52
52
|
Usage:
|
|
53
53
|
run402 operator login [--no-open] (read session, device-flow)
|
|
@@ -289,7 +289,7 @@ async function loopbackLogin(args, { stepUp }) {
|
|
|
289
289
|
if (memberships.length) {
|
|
290
290
|
process.stderr.write(
|
|
291
291
|
`Member of ${memberships.length} org(s):\n` +
|
|
292
|
-
memberships.map((m) => ` - ${m.
|
|
292
|
+
memberships.map((m) => ` - ${m.display_name || m.org_id || m.organization_id || "unknown"} (${m.role}, ${m.status})`).join("\n") +
|
|
293
293
|
"\n",
|
|
294
294
|
);
|
|
295
295
|
}
|
package/lib/projects.mjs
CHANGED
|
@@ -101,7 +101,7 @@ Usage:
|
|
|
101
101
|
run402 projects list [--org <id>] [--all]
|
|
102
102
|
|
|
103
103
|
Options:
|
|
104
|
-
--org <id> Filter to projects owned by one org (
|
|
104
|
+
--org <id> Filter to projects owned by one org (organization).
|
|
105
105
|
Authorize-before-reveal: a non-member or guessed id is a
|
|
106
106
|
403; a non-UUID id is a 400.
|
|
107
107
|
--all Read the cross-wallet inventory across every wallet
|
|
@@ -114,7 +114,7 @@ Notes:
|
|
|
114
114
|
- This is a SERVER read (membership-scoped), not the local keystore. Each row
|
|
115
115
|
has project_id, name, site_url, custom_domains, org_id, status, and an
|
|
116
116
|
'active' marker derived from local state.
|
|
117
|
-
- Tier and lifecycle live on the
|
|
117
|
+
- Tier and lifecycle live on the organization, not each project — use
|
|
118
118
|
'run402 status' or 'run402 tier status' for the account view.
|
|
119
119
|
|
|
120
120
|
Examples:
|
|
@@ -478,7 +478,7 @@ async function list(args = []) {
|
|
|
478
478
|
active: p.id === activeId,
|
|
479
479
|
site_url: p.site_url ?? null,
|
|
480
480
|
custom_domains: p.custom_domains ?? [],
|
|
481
|
-
org_id: p.
|
|
481
|
+
org_id: p.organization_id ?? null,
|
|
482
482
|
status: p.status ?? p.effective_status ?? null,
|
|
483
483
|
}));
|
|
484
484
|
const out = { projects: rows };
|
|
@@ -724,7 +724,7 @@ export async function run(sub, args) {
|
|
|
724
724
|
fail({
|
|
725
725
|
code: "REMOVED_COMMAND",
|
|
726
726
|
message: "`run402 projects pin` was removed in v1.57.",
|
|
727
|
-
hint: "Per-project pin is superseded by the
|
|
727
|
+
hint: "Per-project pin is superseded by the organization-level escape hatch. Use `run402 admin lease-perpetual <organization_id> --enable` (platform-admin only).",
|
|
728
728
|
});
|
|
729
729
|
}
|
|
730
730
|
args = normalizeArgv(args);
|