run402 4.73.4 → 4.75.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/gitvault-surface.json +1 -1
- package/lib/billing.mjs +59 -0
- package/lib/buzz.mjs +11 -8
- package/lib/buzz.test.mjs +20 -0
- package/lib/command-manifest.mjs +2 -1
- package/lib/deploy-rehearse-discovery.test.mjs +25 -0
- package/lib/deploy-v2.mjs +125 -24
- package/package.json +1 -1
- package/sdk/dist/actions.d.ts +11 -6
- package/sdk/dist/actions.d.ts.map +1 -1
- package/sdk/dist/namespaces/billing.d.ts +63 -0
- package/sdk/dist/namespaces/billing.d.ts.map +1 -1
- package/sdk/dist/namespaces/billing.js +45 -0
- package/sdk/dist/namespaces/billing.js.map +1 -1
- package/sdk/dist/namespaces/buzz-notifications.types.d.ts +20 -0
- package/sdk/dist/namespaces/buzz-notifications.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/buzz.d.ts +8 -2
- package/sdk/dist/namespaces/buzz.d.ts.map +1 -1
- package/sdk/dist/namespaces/buzz.js +9 -4
- package/sdk/dist/namespaces/buzz.js.map +1 -1
- package/sdk/dist/namespaces/buzz.types.d.ts +30 -22
- package/sdk/dist/namespaces/buzz.types.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.d.ts.map +1 -1
- package/sdk/dist/node/actions-node.js +29 -5
- package/sdk/dist/node/actions-node.js.map +1 -1
- package/sdk/dist/node/client-detect.d.ts +8 -6
- package/sdk/dist/node/client-detect.d.ts.map +1 -1
- package/sdk/dist/node/client-detect.js +7 -1
- package/sdk/dist/node/client-detect.js.map +1 -1
package/gitvault-surface.json
CHANGED
package/lib/billing.mjs
CHANGED
|
@@ -12,6 +12,7 @@ Subcommands:
|
|
|
12
12
|
create-email <email> Create an email organization
|
|
13
13
|
link-wallet [<org_id>] <wallet_address> Link a wallet to an email organization
|
|
14
14
|
checkout <identifier> --product <p> Create an org checkout
|
|
15
|
+
topup <identifier> --sats <n> [--wait] Top up the cash balance over Lightning (a bolt11 invoice; no node, no Stripe)
|
|
15
16
|
auto-recharge [<org_id>] <on|off> [--threshold <n>]
|
|
16
17
|
balance <identifier> Balance by organization id (UUID), wallet (0x...), or email
|
|
17
18
|
history <identifier> [--limit <n>] Ledger history by organization id (UUID), wallet, or email
|
|
@@ -21,6 +22,7 @@ Examples:
|
|
|
21
22
|
run402 billing checkout 00000000-0000-4000-8000-000000000001 --product tier --tier hobby
|
|
22
23
|
run402 billing checkout 0x1234... --product email-pack
|
|
23
24
|
run402 billing checkout 0x1234... --product balance-topup --amount 5000000
|
|
25
|
+
run402 billing topup 0x1234... --sats 2000 --wait
|
|
24
26
|
run402 billing auto-recharge org_abc on --threshold 2000
|
|
25
27
|
run402 billing balance user@example.com
|
|
26
28
|
`;
|
|
@@ -208,6 +210,62 @@ async function checkout(args) {
|
|
|
208
210
|
}
|
|
209
211
|
}
|
|
210
212
|
|
|
213
|
+
// lightning-cash-topup: "top up N sats" → one invoice, optionally waited on.
|
|
214
|
+
// stdout stays one JSON doc per step (the pipe contract); the human-facing
|
|
215
|
+
// invoice line and the receipt go to stderr.
|
|
216
|
+
async function topup(args) {
|
|
217
|
+
const parsedArgs = normalizeArgv(args);
|
|
218
|
+
const valueFlags = ["--sats", "--timeout", "--idempotency-key"];
|
|
219
|
+
assertKnownFlags(parsedArgs, [...valueFlags, "--wait", "--help", "-h"], valueFlags);
|
|
220
|
+
const positionals = positionalArgs(parsedArgs, valueFlags);
|
|
221
|
+
const identifier = positionals[0];
|
|
222
|
+
if (!identifier || positionals.length > 1) {
|
|
223
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 billing topup <identifier> --sats <n> [--wait]", hint: "run402 billing topup 0x1234... --sats 2000 --wait" });
|
|
224
|
+
}
|
|
225
|
+
const satsRaw = flagValue(parsedArgs, "--sats");
|
|
226
|
+
const sats = Number(satsRaw);
|
|
227
|
+
if (satsRaw === null || !Number.isSafeInteger(sats) || sats <= 0) {
|
|
228
|
+
fail({ code: "BAD_FLAG", message: "--sats must be a positive whole number of satoshis (100–1000000).", details: { flag: "--sats" } });
|
|
229
|
+
}
|
|
230
|
+
const timeoutRaw = flagValue(parsedArgs, "--timeout");
|
|
231
|
+
const timeoutMs = timeoutRaw === null ? 600_000 : Number(timeoutRaw) * 1000;
|
|
232
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
233
|
+
fail({ code: "BAD_FLAG", message: "--timeout must be a positive number of seconds.", details: { flag: "--timeout" } });
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const sdk = getSdk();
|
|
237
|
+
const org = await sdk.billing.lookupOrganization(identifier);
|
|
238
|
+
const created = await sdk.billing.createLightningTopup(org.org_id, {
|
|
239
|
+
amountSats: sats,
|
|
240
|
+
idempotencyKey: flagValue(parsedArgs, "--idempotency-key") ?? undefined,
|
|
241
|
+
});
|
|
242
|
+
console.log(JSON.stringify(created, null, 2));
|
|
243
|
+
console.error(`Invoice for ${created.amount_sats} sats (≈ $${(created.amount_usd_micros / 1_000_000).toFixed(2)} at the quoted rate), expires ${created.invoice_expires_at}.`);
|
|
244
|
+
console.error(`Pay it from any Lightning wallet:\n lightning:${created.bolt11}`);
|
|
245
|
+
if (!parsedArgs.includes("--wait")) {
|
|
246
|
+
console.error(`Then read it: run402 billing topup is one-shot; poll GET /orgs/v1/${org.org_id}/checkouts/${created.topup_id} (or rerun with --wait).`);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
let announced = false;
|
|
250
|
+
const final = await sdk.billing.waitForTopup(org.org_id, created.topup_id, {
|
|
251
|
+
timeoutMs,
|
|
252
|
+
onPoll: () => { if (!announced) { announced = true; console.error("Waiting for the payment…"); } },
|
|
253
|
+
});
|
|
254
|
+
console.log(JSON.stringify(final, null, 2));
|
|
255
|
+
if (final.status === "paid" || final.status === "paid_late") {
|
|
256
|
+
console.error(`Received — ${final.amount_sats} sats credited $${(final.amount_usd_micros / 1_000_000).toFixed(2)} to the balance${final.status === "paid_late" ? " (paid after the invoice expired; still credited)" : ""}.`);
|
|
257
|
+
} else if (final.status === "expired") {
|
|
258
|
+
console.error("The invoice expired unpaid. Mint a fresh one with the same command.");
|
|
259
|
+
process.exitCode = 2;
|
|
260
|
+
} else {
|
|
261
|
+
console.error("Timed out still pending — a payment that lands later still credits (up to an hour after expiry); poll the top-up.");
|
|
262
|
+
process.exitCode = 2;
|
|
263
|
+
}
|
|
264
|
+
} catch (err) {
|
|
265
|
+
reportSdkError(err);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
211
269
|
async function createEmail(args) {
|
|
212
270
|
const parsedArgs = normalizeArgv(args);
|
|
213
271
|
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
@@ -353,6 +411,7 @@ export async function run(sub, args) {
|
|
|
353
411
|
case "create-email": await createEmail(args); break;
|
|
354
412
|
case "link-wallet": await linkWallet(args); break;
|
|
355
413
|
case "checkout": await checkout(args); break;
|
|
414
|
+
case "topup": await topup(args); break;
|
|
356
415
|
case "auto-recharge": await autoRecharge(args); break;
|
|
357
416
|
case "balance": await balance(args); break;
|
|
358
417
|
case "history": await history(args); break;
|
package/lib/buzz.mjs
CHANGED
|
@@ -26,7 +26,7 @@ Canonical workflows:
|
|
|
26
26
|
--org the Run402 organization id as "run402 org whoami" returns it (a UUID)
|
|
27
27
|
--deployment-context-file JSON with exactly these five non-empty strings, and no others:
|
|
28
28
|
project_id, release_id, live_url, source_revision, verified_at
|
|
29
|
-
run402 buzz install --org <org_id> --community <buzz:community:host> --authority <hex-pubkey>
|
|
29
|
+
run402 buzz install --org <org_id> --community <buzz:community:host> [--authority <hex-pubkey>]
|
|
30
30
|
run402 buzz enroll --installation <buzzci_id> --identity-link <idlnk_id> --grants-file <json> --expires-at <ISO-8601>
|
|
31
31
|
|
|
32
32
|
Explicit consent/decision commands:
|
|
@@ -34,7 +34,7 @@ Explicit consent/decision commands:
|
|
|
34
34
|
run402 buzz adopt offer cancel <buzzhao_id>
|
|
35
35
|
run402 buzz adopt complete <buzzha_id> --event-file <owner-event.json>
|
|
36
36
|
run402 buzz adopt cancel <buzzha_id>
|
|
37
|
-
run402 buzz install activate <buzzci_id> --
|
|
37
|
+
run402 buzz install activate <buzzci_id> --invite <link|code> (a one-use invite minted in Buzz Desktop; no key leaves Desktop)
|
|
38
38
|
run402 buzz install update <buzzci_id> --policy-file <policy.json> --policy-revision <n> --default <true|false>
|
|
39
39
|
run402 buzz install revoke <buzzci_id>
|
|
40
40
|
run402 buzz approve <buzzae_id> --grants-file <json> --descriptor-revision <n> --policy-revision <n>
|
|
@@ -199,12 +199,15 @@ async function install(args) {
|
|
|
199
199
|
const [operation, ...rest] = args;
|
|
200
200
|
if (operation === "activate") {
|
|
201
201
|
const a = normalizeArgv(rest);
|
|
202
|
-
const values = ["--
|
|
202
|
+
const values = ["--invite", "--idempotency-key"];
|
|
203
203
|
assertKnownFlags(a, values, values);
|
|
204
|
-
const [id] = requirePositionalCount(a, values, { min: 1, max: 1, command: "run402 buzz install activate <buzzci_id> --
|
|
205
|
-
|
|
204
|
+
const [id] = requirePositionalCount(a, values, { min: 1, max: 1, command: "run402 buzz install activate <buzzci_id> --invite <link|code>" });
|
|
205
|
+
// The invite is a one-use bearer artifact: it goes to the gateway once
|
|
206
|
+
// and is never echoed. A bare code, an https://<relay>/invite/<code>
|
|
207
|
+
// link, or a buzz://join?relay=…&code=… link are all accepted.
|
|
208
|
+
const invite = requiredFlag(a, "--invite");
|
|
206
209
|
const key = flagValue(a, "--idempotency-key") ?? undefined;
|
|
207
|
-
return invoke(() => getSdk().buzz.communityInstallations.activate(id,
|
|
210
|
+
return invoke(() => getSdk().buzz.communityInstallations.activate(id, invite, key));
|
|
208
211
|
}
|
|
209
212
|
if (operation === "revoke") {
|
|
210
213
|
const a = normalizeArgv(rest);
|
|
@@ -252,13 +255,13 @@ async function install(args) {
|
|
|
252
255
|
const a = normalizeArgv(args);
|
|
253
256
|
const values = ["--org", "--community", "--authority", "--policy-file", "--idempotency-key"];
|
|
254
257
|
assertKnownFlags(a, values, values);
|
|
255
|
-
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz install [--org <org_id>] --community <subject> --authority <hex>" });
|
|
258
|
+
requirePositionalCount(a, values, { min: 0, max: 0, command: "run402 buzz install [--org <org_id>] --community <subject> [--authority <hex>]" });
|
|
256
259
|
const policyFile = flagValue(a, "--policy-file");
|
|
257
260
|
const organizationId = await resolveOrgId(a, { cmd: "buzz" });
|
|
258
261
|
return invoke(() => getSdk().buzz.install({
|
|
259
262
|
organizationId,
|
|
260
263
|
buzzCommunitySubject: requiredFlag(a, "--community"),
|
|
261
|
-
buzzCommunityAuthoritySubject:
|
|
264
|
+
buzzCommunityAuthoritySubject: flagValue(a, "--authority") ?? undefined,
|
|
262
265
|
enrollmentPolicy: policyFile ? readJsonFile(policyFile, "--policy-file") : undefined,
|
|
263
266
|
idempotencyKey: flagValue(a, "--idempotency-key") ?? undefined,
|
|
264
267
|
}));
|
package/lib/buzz.test.mjs
CHANGED
|
@@ -194,6 +194,26 @@ describe("run402 buzz CLI", () => {
|
|
|
194
194
|
assert.match(stderr.join("\n"), /pending/);
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
+
it("installs without naming a Buzz authority and activates through the invite front door", async () => {
|
|
198
|
+
const calls = [];
|
|
199
|
+
sdk = {
|
|
200
|
+
buzz: {
|
|
201
|
+
install: async (input) => { calls.push(["install", input]); return { status: "pending", installation_identity: { pubkey: "ab".repeat(32) }, next_actions: [{ type: "mint_buzz_invite" }] }; },
|
|
202
|
+
communityInstallations: {
|
|
203
|
+
activate: async (id, invite, key) => { calls.push(["activate", id, invite, key]); return { status: "active", bot_mode: "attested" }; },
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
await run("install", ["--org", "22222222-2222-4222-8222-222222222222", "--community", "buzz:community:acme.communities.buzz.xyz"]);
|
|
208
|
+
assert.equal(calls[0][0], "install");
|
|
209
|
+
assert.equal(calls[0][1].buzzCommunitySubject, "buzz:community:acme.communities.buzz.xyz");
|
|
210
|
+
assert.equal(calls[0][1].buzzCommunityAuthoritySubject, undefined);
|
|
211
|
+
assert.equal(JSON.parse(stdout[0]).next_actions[0].type, "mint_buzz_invite");
|
|
212
|
+
await run("install", ["activate", `buzzci_${"2".repeat(32)}`, "--invite", "https://acme.communities.buzz.xyz/invite/v2.abcdefghij", "--idempotency-key", "activate-1"]);
|
|
213
|
+
assert.deepEqual(calls[1], ["activate", `buzzci_${"2".repeat(32)}`, "https://acme.communities.buzz.xyz/invite/v2.abcdefghij", "activate-1"]);
|
|
214
|
+
assert.equal(JSON.parse(stdout[1]).bot_mode, "attested");
|
|
215
|
+
});
|
|
216
|
+
|
|
197
217
|
it("discovers descriptors by community without authentication", async () => {
|
|
198
218
|
let observed;
|
|
199
219
|
sdk = {
|
package/lib/command-manifest.mjs
CHANGED
|
@@ -182,7 +182,7 @@ export const COMMAND_MANIFEST = [
|
|
|
182
182
|
|
|
183
183
|
// ── deploy (unified deploy v2) ───────────────────────────────────────────
|
|
184
184
|
{ path: ["deploy", "apply"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: ["--spec", "{}", "--check"], runStyle: "deployV2" },
|
|
185
|
-
{ path: ["deploy", "rehearse"], positionals: [p("plan_id")], projectScoped: true, legacyPositionalProject: false, minimalArgs: ["plan_gate1"], runStyle: "deployV2" },
|
|
185
|
+
{ path: ["deploy", "rehearse"], positionals: [p("plan_id", { required: false })], projectScoped: true, legacyPositionalProject: false, minimalArgs: ["plan_gate1"], runStyle: "deployV2" },
|
|
186
186
|
{ path: ["deploy", "promote"], positionals: [p("release_id")], projectScoped: true, legacyPositionalProject: false, minimalArgs: ["rel_gate1"], runStyle: "deployV2" },
|
|
187
187
|
{ path: ["deploy", "resume"], positionals: [p("operation_id")], projectScoped: true, legacyPositionalProject: false, minimalArgs: ["op_gate1"], runStyle: "deployV2" },
|
|
188
188
|
{ path: ["deploy", "list"], positionals: [], projectScoped: true, legacyPositionalProject: false, minimalArgs: [], runStyle: "deployV2" },
|
|
@@ -453,6 +453,7 @@ export const COMMAND_MANIFEST = [
|
|
|
453
453
|
{ path: ["billing", "create-email"], positionals: [p("email")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["gate@example.com"] },
|
|
454
454
|
{ path: ["billing", "link-wallet"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "0x1111111111111111111111111111111111111111"] },
|
|
455
455
|
{ path: ["billing", "checkout"], positionals: [p("identifier")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["00000000-0000-4000-8000-000000000001", "--product", "email-pack"] },
|
|
456
|
+
{ path: ["billing", "topup"], positionals: [p("identifier")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["00000000-0000-4000-8000-000000000001", "--sats", "2000"] },
|
|
456
457
|
{ path: ["billing", "auto-recharge"], positionals: [p("org_id", { required: false })], projectScoped: false, orgScoped: true, legacyPositionalProject: false, minimalArgs: [GATE_ORG, "--state", "on"] },
|
|
457
458
|
{ path: ["billing", "balance"], positionals: [p("identifier")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["gate@example.com"] },
|
|
458
459
|
{ path: ["billing", "history"], positionals: [p("identifier")], projectScoped: false, legacyPositionalProject: false, minimalArgs: ["gate@example.com"] },
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { discoverRehearseManifest } from "./deploy-v2.mjs";
|
|
7
|
+
|
|
8
|
+
describe("deploy rehearse — manifest discovery (the way up does it)", () => {
|
|
9
|
+
it("prefers run402.json, then run402.deploy.json, then app.json, then executable configs", () => {
|
|
10
|
+
const dir = mkdtempSync(join(tmpdir(), "run402-rehearse-discover-"));
|
|
11
|
+
try {
|
|
12
|
+
assert.equal(discoverRehearseManifest(dir), null);
|
|
13
|
+
writeFileSync(join(dir, "run402.deploy.ts"), "export default {}");
|
|
14
|
+
assert.equal(discoverRehearseManifest(dir), join(dir, "run402.deploy.ts"));
|
|
15
|
+
writeFileSync(join(dir, "app.json"), "{}");
|
|
16
|
+
assert.equal(discoverRehearseManifest(dir), join(dir, "app.json"));
|
|
17
|
+
writeFileSync(join(dir, "run402.deploy.json"), "{}");
|
|
18
|
+
assert.equal(discoverRehearseManifest(dir), join(dir, "run402.deploy.json"));
|
|
19
|
+
writeFileSync(join(dir, "run402.json"), "{}");
|
|
20
|
+
assert.equal(discoverRehearseManifest(dir), join(dir, "run402.json"));
|
|
21
|
+
} finally {
|
|
22
|
+
rmSync(dir, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
});
|
package/lib/deploy-v2.mjs
CHANGED
|
@@ -228,19 +228,28 @@ Output:
|
|
|
228
228
|
stderr: one JSON poll progress line per attempt when --wait is set
|
|
229
229
|
`;
|
|
230
230
|
|
|
231
|
-
const REHEARSE_HELP = `run402 deploy rehearse — Run a
|
|
231
|
+
const REHEARSE_HELP = `run402 deploy rehearse — Run a plan on a contained branch (ADVANCED; rehearsal is automatic in up / deploy apply)
|
|
232
232
|
|
|
233
233
|
Usage:
|
|
234
|
-
run402 deploy rehearse <plan_id> [--project <id>] [--teardown on_pass|keep|always] [--json]
|
|
234
|
+
run402 deploy rehearse [<plan_id>] [--manifest <path>] [--project <id>] [--teardown on_pass|keep|always] [--json]
|
|
235
235
|
|
|
236
236
|
Options:
|
|
237
|
+
<plan_id> An already-persisted plan. Its bytes must be uploaded; when
|
|
238
|
+
the gateway answers REHEARSAL_CONTENT_MISSING the manifest
|
|
239
|
+
in the current directory (or --manifest) is used to upload
|
|
240
|
+
them and the rehearsal is retried. If facts changed since
|
|
241
|
+
that plan, a fresh reviewed plan is created and rehearsed
|
|
242
|
+
instead — the result names which plan was rehearsed.
|
|
243
|
+
--manifest <path> Plan from this manifest (run402.json, run402.deploy.json,
|
|
244
|
+
app.json, or an executable config), upload its bytes, then
|
|
245
|
+
rehearse. Without <plan_id> the manifest is discovered in
|
|
246
|
+
the current directory the same way run402 up does.
|
|
237
247
|
--teardown <mode> on_pass (default: passed rehearsals delete their branch;
|
|
238
|
-
failed rehearsals keep it), keep, always.
|
|
239
|
-
|
|
248
|
+
failed rehearsals keep it), keep, always.
|
|
249
|
+
--project <id> Project for operator-approval metadata and project resolution.
|
|
240
250
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
primitive for rehearsing an already-persisted plan without committing.
|
|
251
|
+
Nothing is committed. The result carries the rehearsal report and the exact
|
|
252
|
+
bound commit command (run402 deploy apply --require-plan <plan_id>).
|
|
244
253
|
`;
|
|
245
254
|
|
|
246
255
|
const RELEASE_HELP = `run402 deploy release — Inspect deploy release inventory and diffs
|
|
@@ -356,14 +365,52 @@ export async function runDeployV2(sub, args) {
|
|
|
356
365
|
});
|
|
357
366
|
}
|
|
358
367
|
|
|
368
|
+
const REHEARSE_MANIFEST_CANDIDATES = ["run402.json", "run402.deploy.json", "app.json", "run402.deploy.ts", "run402.deploy.mts", "run402.deploy.js", "run402.deploy.mjs"];
|
|
369
|
+
|
|
370
|
+
/** The manifest `deploy rehearse` would plan from in `dir`, discovered the way `up` does, or null. */
|
|
371
|
+
export function discoverRehearseManifest(dir = process.cwd()) {
|
|
372
|
+
for (const name of REHEARSE_MANIFEST_CANDIDATES) {
|
|
373
|
+
const candidate = resolve(dir, name);
|
|
374
|
+
if (existsSync(candidate)) return candidate;
|
|
375
|
+
}
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
async function loadReleaseSpecForRehearse(manifestPath, project) {
|
|
380
|
+
const executable = EXECUTABLE_MANIFEST_EXTENSIONS.has(extname(manifestPath).toLowerCase());
|
|
381
|
+
let normalized;
|
|
382
|
+
try {
|
|
383
|
+
if (executable) {
|
|
384
|
+
normalized = await loadDeployManifest(manifestPath, { ...(project ? { project } : {}) });
|
|
385
|
+
} else {
|
|
386
|
+
const spec = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
387
|
+
rejectLegacySecretManifest(spec, { source: "manifest", path: manifestPath });
|
|
388
|
+
const defaultProject = project || spec?.project || spec?.project_id ? undefined : resolveProjectId(null);
|
|
389
|
+
normalized = await normalizeDeployManifest(spec, {
|
|
390
|
+
baseDir: dirname(manifestPath),
|
|
391
|
+
...(project ? { project } : {}),
|
|
392
|
+
...(defaultProject ? { defaultProject } : {}),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
} catch (err) {
|
|
396
|
+
reportSdkError(err);
|
|
397
|
+
}
|
|
398
|
+
return normalized;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function isContentMissing(err) {
|
|
402
|
+
const code = err?.code ?? err?.body?.code ?? err?.envelope?.code;
|
|
403
|
+
return code === "REHEARSAL_CONTENT_MISSING";
|
|
404
|
+
}
|
|
405
|
+
|
|
359
406
|
async function rehearseCmd(rawArgs) {
|
|
360
407
|
const args = normalizeArgv(rawArgs);
|
|
361
408
|
if (args.includes("--help") || args.includes("-h")) {
|
|
362
409
|
console.log(REHEARSE_HELP);
|
|
363
410
|
return;
|
|
364
411
|
}
|
|
365
|
-
const valueFlags = new Set(["--project", "--teardown"]);
|
|
366
|
-
const allowedFlags = ["--project", "--teardown", "--json", "--help", "-h"];
|
|
412
|
+
const valueFlags = new Set(["--project", "--teardown", "--manifest"]);
|
|
413
|
+
const allowedFlags = ["--project", "--teardown", "--manifest", "--json", "--help", "-h"];
|
|
367
414
|
const positionals = [];
|
|
368
415
|
for (let i = 0; i < args.length; i += 1) {
|
|
369
416
|
const arg = args[i];
|
|
@@ -382,9 +429,23 @@ async function rehearseCmd(rawArgs) {
|
|
|
382
429
|
}
|
|
383
430
|
positionals.push(arg);
|
|
384
431
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
432
|
+
if (positionals.length > 1) {
|
|
433
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 deploy rehearse [<plan_id>] [--manifest <path>] [--project <id>] [--teardown on_pass|keep|always] [--json]" });
|
|
434
|
+
}
|
|
435
|
+
const givenPlanId = positionals[0] ?? null;
|
|
436
|
+
const explicitManifest = flagValue(args, "--manifest");
|
|
437
|
+
const manifestPath = explicitManifest
|
|
438
|
+
? (isAbsolute(explicitManifest) ? explicitManifest : resolve(process.cwd(), explicitManifest))
|
|
439
|
+
: discoverRehearseManifest();
|
|
440
|
+
if (explicitManifest && !existsSync(manifestPath)) {
|
|
441
|
+
fail({ code: "BAD_USAGE", message: `Manifest not found: ${manifestPath}`, details: { flag: "--manifest", path: explicitManifest } });
|
|
442
|
+
}
|
|
443
|
+
if (!givenPlanId && !manifestPath) {
|
|
444
|
+
fail({
|
|
445
|
+
code: "BAD_USAGE",
|
|
446
|
+
message: "Nothing to rehearse: pass a <plan_id>, or run from a directory with a manifest (run402.json, run402.deploy.json, app.json), or pass --manifest <path>.",
|
|
447
|
+
details: { searched: REHEARSE_MANIFEST_CANDIDATES },
|
|
448
|
+
});
|
|
388
449
|
}
|
|
389
450
|
// When --teardown is absent, omit it from the request body entirely — the
|
|
390
451
|
// gateway defaults to on_pass (passed rehearsals delete their branch).
|
|
@@ -394,23 +455,63 @@ async function rehearseCmd(rawArgs) {
|
|
|
394
455
|
}
|
|
395
456
|
const project = flagValue(args, "--project") ?? undefined;
|
|
396
457
|
// A delegate is a complete deploy credential and the gateway explicitly
|
|
397
|
-
// supports rehearsing with one
|
|
398
|
-
//
|
|
399
|
-
// only CI sessions (REHEARSAL_CI_UNSUPPORTED), whose own next_action reads
|
|
400
|
-
// "Rehearse with a wallet, control-plane session, or scoped agent delegate."
|
|
401
|
-
// Without this branch the CLI refuses locally with NO_ALLOWANCE and tells the
|
|
402
|
-
// caller to run `run402 init` — a wrong remedy for a holder who has no wallet
|
|
403
|
-
// by design, and the same misleading-error shape we removed from the payment
|
|
404
|
-
// path in 4.11.2. Rehearsal is the SAFE path; never make it the harder one.
|
|
458
|
+
// supports rehearsing with one (the route rejects only CI sessions).
|
|
459
|
+
// Rehearsal is the SAFE path; never make it the harder one.
|
|
405
460
|
if (!isCoreApiTarget() && !loadLiveControlPlaneSession() && !delegateTokenFromEnv()) {
|
|
406
|
-
allowanceAuthHeaders(`/apply/v1/plans/${
|
|
461
|
+
allowanceAuthHeaders(`/apply/v1/plans/${givenPlanId ?? "_"}/rehearse`);
|
|
462
|
+
}
|
|
463
|
+
const sdk = getSdk();
|
|
464
|
+
const emit = makeStderrEventWriter(false);
|
|
465
|
+
|
|
466
|
+
// Plan from the manifest, upload its bytes, and hand back the persisted
|
|
467
|
+
// plan id to rehearse. Used when no plan id was given, and as the recovery
|
|
468
|
+
// for a plan whose bytes were never uploaded.
|
|
469
|
+
async function planAndUpload() {
|
|
470
|
+
const normalized = await loadReleaseSpecForRehearse(manifestPath, project);
|
|
471
|
+
const planned = await sdk._applyEngine.plan(normalized.spec, {
|
|
472
|
+
idempotencyKey: normalized.idempotencyKey,
|
|
473
|
+
mode: "reviewedPlan",
|
|
474
|
+
});
|
|
475
|
+
const planId = planned.plan.plan_id;
|
|
476
|
+
if (!planId) {
|
|
477
|
+
fail({ code: "DRY_RUN_PLAN_NOT_COMMITTABLE", message: "Rehearsal requires a persisted plan_id, but the plan response did not include one.", details: { project_id: normalized.spec.project } });
|
|
478
|
+
}
|
|
479
|
+
await sdk._applyEngine.upload(planned.plan, {
|
|
480
|
+
project: normalized.spec.project,
|
|
481
|
+
byteReaders: planned.byteReaders,
|
|
482
|
+
onEvent: emit,
|
|
483
|
+
});
|
|
484
|
+
return { planId, plan: planned.plan, projectId: normalized.spec.project };
|
|
407
485
|
}
|
|
486
|
+
|
|
408
487
|
try {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
488
|
+
let planId = givenPlanId;
|
|
489
|
+
let replanned = null;
|
|
490
|
+
let rehearsal;
|
|
491
|
+
if (!planId) {
|
|
492
|
+
const fresh = await planAndUpload();
|
|
493
|
+
planId = fresh.planId;
|
|
494
|
+
rehearsal = await withAutoApprove(() => sdk._applyEngine.rehearse(planId, { project: project ?? fresh.projectId, teardown }));
|
|
495
|
+
} else {
|
|
496
|
+
try {
|
|
497
|
+
rehearsal = await withAutoApprove(() => sdk._applyEngine.rehearse(planId, { project, teardown }));
|
|
498
|
+
} catch (err) {
|
|
499
|
+
if (!isContentMissing(err) || !manifestPath) throw err;
|
|
500
|
+
// The plan's bytes were never uploaded (a --plan-only plan). Plan from
|
|
501
|
+
// the manifest to get byte readers, upload, and retry. When facts
|
|
502
|
+
// changed since the given plan the fresh plan is the one rehearsed,
|
|
503
|
+
// and the result says so — never silently substituted.
|
|
504
|
+
const fresh = await planAndUpload();
|
|
505
|
+
if (fresh.planId !== givenPlanId) replanned = { original_plan_id: givenPlanId, plan_id: fresh.planId, why: "plan facts changed since the given plan; a fresh reviewed plan was created, its bytes uploaded, and that plan rehearsed" };
|
|
506
|
+
planId = fresh.planId;
|
|
507
|
+
rehearsal = await withAutoApprove(() => sdk._applyEngine.rehearse(planId, { project: project ?? fresh.projectId, teardown }));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
412
510
|
console.log(JSON.stringify({
|
|
413
511
|
ok: rehearsal.report.status === "passed",
|
|
512
|
+
plan_id: planId,
|
|
513
|
+
...(manifestPath ? { manifest_path: manifestPath } : {}),
|
|
514
|
+
...(replanned ? { replanned } : {}),
|
|
414
515
|
rehearsal,
|
|
415
516
|
commit_command: `run402 deploy apply --require-plan ${planId}`,
|
|
416
517
|
}, null, 2));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "run402",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.75.0",
|
|
4
4
|
"description": "CLI for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/sdk/dist/actions.d.ts
CHANGED
|
@@ -70,17 +70,22 @@ export interface Run402UpActionInput {
|
|
|
70
70
|
* project with a live release gets. Default false. */
|
|
71
71
|
noRehearse?: boolean;
|
|
72
72
|
/** Explicit display name to set on the principal when it has none yet.
|
|
73
|
-
* Omitted:
|
|
74
|
-
*
|
|
73
|
+
* Omitted: `RUN402_AGENT_NAME` when set, else a specifically detected
|
|
74
|
+
* client (`claude-code`, `codex`, `cursor`) reported as `identity.source:
|
|
75
|
+
* "detected"`; when nothing is known no name is written and the result
|
|
76
|
+
* says `identity.source: "undetected"`. */
|
|
75
77
|
identityName?: string;
|
|
76
78
|
}
|
|
77
79
|
/** How `up` resolved the principal's display name (first-deploy-agent-dx). */
|
|
78
80
|
export interface Run402UpIdentity {
|
|
79
81
|
display_name: string | null;
|
|
80
|
-
/** `existing`: already set; `explicit`: set now from `identityName
|
|
81
|
-
* `detected`: set now from
|
|
82
|
-
*
|
|
83
|
-
|
|
82
|
+
/** `existing`: already set; `explicit`: set now from `identityName` or
|
|
83
|
+
* `RUN402_AGENT_NAME`; `detected`: set now from a specifically detected
|
|
84
|
+
* client (`claude-code`, `codex`, `cursor`); `undetected`: nothing known
|
|
85
|
+
* and nothing persisted — a guess is never written as a name (the room
|
|
86
|
+
* presence is `agent` for coordination only); `unavailable`: could not be
|
|
87
|
+
* read or set (never fails the deploy). */
|
|
88
|
+
source: "existing" | "explicit" | "detected" | "undetected" | "unavailable";
|
|
84
89
|
/** The project room presence `up` registered under that name, when it could. */
|
|
85
90
|
presence?: {
|
|
86
91
|
presence_id: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC5F,OAAO,KAAK,EACV,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAC1B,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAEjD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;AAE3C,MAAM,MAAM,iBAAiB,GACzB,kCAAkC,GAClC,wBAAwB,GACxB,mBAAmB,CAAC;AAExB,MAAM,WAAW,kCAAkC;IACjD,IAAI,EAAE,OAAO,YAAY,CAAC,iBAAiB,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,YAAY,CAAC,OAAO,CAAC;IAClC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,YAAY,CAAC,EAAE,CAAC;IAC7B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,8FAA8F;IAC9F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8FAA8F;IAC9F,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,kGAAkG;IAClG,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;2DACuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC5F,OAAO,KAAK,EACV,qBAAqB,EACrB,0BAA0B,EAC1B,yBAAyB,EACzB,uBAAuB,EACxB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD;;;GAGG;AACH,eAAO,MAAM,YAAY;;;;CAIf,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAC1B,OAAO,YAAY,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC;AAEjD,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;AAE3C,MAAM,MAAM,iBAAiB,GACzB,kCAAkC,GAClC,wBAAwB,GACxB,mBAAmB,CAAC;AAExB,MAAM,WAAW,kCAAkC;IACjD,IAAI,EAAE,OAAO,YAAY,CAAC,iBAAiB,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,YAAY,CAAC,OAAO,CAAC;IAClC,IAAI,EAAE,mBAAmB,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,OAAO,YAAY,CAAC,EAAE,CAAC;IAC7B,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,yEAAyE;IACzE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,8FAA8F;IAC9F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8FAA8F;IAC9F,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,kGAAkG;IAClG,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;2DACuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;gDAI4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B;;;;;gDAK4C;IAC5C,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,GAAG,aAAa,CAAC;IAC5E,gFAAgF;IAChF,QAAQ,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACzD;AAED,MAAM,MAAM,oBAAoB,GAC5B,OAAO,GACP,KAAK,GACL,+BAA+B,CAAC;AAEpC,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,CAAC,OAAO,EAAE,2BAA2B,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,2BAA2B;IAC1C,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,oBAAoB,EAAE,CAAC;CACnC;AAED,MAAM,MAAM,oBAAoB,GAC5B,kBAAkB,GAClB,kBAAkB,GAClB,UAAU,GACV,oBAAoB,GACpB,sBAAsB,GACtB,oBAAoB,GACpB,aAAa,GACb,oBAAoB,GACpB,mBAAmB,GACnB,WAAW,GACX,oBAAoB,GACpB,YAAY,GACZ,mBAAmB,GACnB,cAAc,CAAC;AAEnB,MAAM,WAAW,sBAAsB;IACrC;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,mBAAmB,CAAC;IAC3B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sCAAsC;IACtC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,MAAM,qBAAqB,GAC7B,SAAS,GACT,SAAS,GACT,WAAW,GACX,SAAS,GACT,SAAS,GACT,QAAQ,GACR,qBAAqB,CAAC;AAE1B,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;IACxF,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,qBAAqB,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,GAAG,OAAO;IAC7C,MAAM,EAAE,gBAAgB,CAAC;IACzB,IAAI,EAAE,mBAAmB,GAAG,cAAc,CAAC;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,CAAC,CAAC;CACZ;AAED;iFACiF;AACjF,MAAM,WAAW,6BAA6B;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,0BAA0B,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,UAAU,CAAC,EAAE,yBAAyB,CAAC;IACvC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;kEAC8D;IAC9D,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,6BAA6B,EAAE,CAAA;KAAE,CAAC;IACzD,0EAA0E;IAC1E,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B;;6EAEyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,mCAAmC,GAC7C,kBAAkB,CAAC,eAAe,CAAC,CAAC;AAEtC,MAAM,MAAM,yBAAyB,GACnC,kBAAkB,CAAC,aAAa,CAAC,CAAC;AAEpC,MAAM,MAAM,oBAAoB,GAC9B,kBAAkB,CAAC,cAAc,CAAC,CAAC;AAErC,MAAM,WAAW,aAAa;IAC5B,GAAG,CACD,KAAK,EAAE,kCAAkC,EACzC,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,mCAAmC,CAAC,CAAC;IAChD,GAAG,CACD,KAAK,EAAE,wBAAwB,EAC/B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtC,GAAG,CACD,KAAK,EAAE,mBAAmB,EAC1B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACjC,GAAG,CAAC,KAAK,EAAE,iBAAiB,EAAE,IAAI,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC3F"}
|
|
@@ -56,6 +56,51 @@ export interface CreateCheckoutResult {
|
|
|
56
56
|
checkout_url: string;
|
|
57
57
|
topup_id: string;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* A Lightning cash top-up (lightning-cash-topup). `amount_usd_micros` is a
|
|
61
|
+
* QUOTE fixed at mint (`usd_value_is_quote: true`) and is what settlement
|
|
62
|
+
* credits. Never carries the provider's credential.
|
|
63
|
+
*/
|
|
64
|
+
export interface LightningTopup {
|
|
65
|
+
org_id: string;
|
|
66
|
+
product: "balance_topup";
|
|
67
|
+
rail: "lightning";
|
|
68
|
+
topup_id: string;
|
|
69
|
+
/** The payable invoice, verbatim. */
|
|
70
|
+
bolt11: string | null;
|
|
71
|
+
payment_hash: string | null;
|
|
72
|
+
amount_sats: number | null;
|
|
73
|
+
amount_usd_micros: number;
|
|
74
|
+
usd_value_is_quote: true;
|
|
75
|
+
quoted_rate: {
|
|
76
|
+
usd_per_btc: number;
|
|
77
|
+
source: string;
|
|
78
|
+
observed_at: string;
|
|
79
|
+
amount_sats: number;
|
|
80
|
+
} | null;
|
|
81
|
+
invoice_expires_at: string | null;
|
|
82
|
+
status: "pending" | "paid" | "paid_late" | "expired";
|
|
83
|
+
paid_at: string | null;
|
|
84
|
+
credited_ledger_id: string | null;
|
|
85
|
+
created_at: string | null;
|
|
86
|
+
next_actions: Array<{
|
|
87
|
+
type: string;
|
|
88
|
+
method: string;
|
|
89
|
+
path: string;
|
|
90
|
+
why: string;
|
|
91
|
+
}>;
|
|
92
|
+
}
|
|
93
|
+
export interface CreateLightningTopupOptions {
|
|
94
|
+
/** Whole satoshis, 100–1,000,000. */
|
|
95
|
+
amountSats: number;
|
|
96
|
+
/** Replay-safe create: the same key returns the same top-up. */
|
|
97
|
+
idempotencyKey?: string;
|
|
98
|
+
}
|
|
99
|
+
export interface WaitForTopupOptions {
|
|
100
|
+
pollMs?: number;
|
|
101
|
+
timeoutMs?: number;
|
|
102
|
+
onPoll?: (state: LightningTopup) => void;
|
|
103
|
+
}
|
|
59
104
|
export interface EmailOrganization {
|
|
60
105
|
id: string;
|
|
61
106
|
email: string;
|
|
@@ -92,6 +137,11 @@ export type CreateCheckoutOptions = {
|
|
|
92
137
|
amountUsdMicros: number;
|
|
93
138
|
successUrl?: string;
|
|
94
139
|
cancelUrl?: string;
|
|
140
|
+
} | {
|
|
141
|
+
/** lightning-cash-topup: a bolt11 invoice instead of a Stripe session. */
|
|
142
|
+
product?: "balance_topup";
|
|
143
|
+
rail: "lightning";
|
|
144
|
+
amountSats: number;
|
|
95
145
|
} | {
|
|
96
146
|
product: "tier";
|
|
97
147
|
tier: ProjectTier;
|
|
@@ -149,6 +199,19 @@ export declare class Billing {
|
|
|
149
199
|
getHistory(identifier: OrganizationIdentifier, opts?: BillingHistoryOptions): Promise<BillingHistoryResult>;
|
|
150
200
|
/** Create a Stripe checkout URL for an organization. */
|
|
151
201
|
createCheckout(organizationId: string, checkout: CreateCheckoutOptions): Promise<CreateCheckoutResult>;
|
|
202
|
+
/**
|
|
203
|
+
* lightning-cash-topup: mint a bolt11 invoice that tops up the org's cash
|
|
204
|
+
* balance when paid. No funds move at creation; any active org member or a
|
|
205
|
+
* delegate for one of the org's projects may call it.
|
|
206
|
+
*/
|
|
207
|
+
createLightningTopup(organizationId: string, options: CreateLightningTopupOptions): Promise<LightningTopup>;
|
|
208
|
+
/** Read one top-up (the waiting client's poll). */
|
|
209
|
+
getTopup(organizationId: string, topupId: string): Promise<LightningTopup>;
|
|
210
|
+
/**
|
|
211
|
+
* Poll a top-up until it is paid, paid late, or expired (or the timeout
|
|
212
|
+
* elapses, in which case the last observed state is returned).
|
|
213
|
+
*/
|
|
214
|
+
waitForTopup(organizationId: string, topupId: string, options?: WaitForTopupOptions): Promise<LightningTopup>;
|
|
152
215
|
/** Create an email-only (no-wallet) organization. Sends a verification email. */
|
|
153
216
|
createEmailOrganization(email: string): Promise<EmailOrganization>;
|
|
154
217
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../../src/namespaces/billing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAS3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uFAAuF;IACvF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB,EAAE,MAAM,CAAC;IAChC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,qBAAqB,EAAE,OAAO,CAAC;IAC/B,uBAAuB,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uBAAuB,EAAE,MAAM,CAAC;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wEAAwE;AACxE,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB,EAAE,MAAM,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,8BAA8B,EAAE,MAAM,CAAC;IACvC,kCAAkC,EAAE,MAAM,CAAC;IAC3C,WAAW,EAAE;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;KACvB,CAAC;IACF,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,0BAA0B,CAAC;CAChD;AAED,MAAM,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAE5C,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,MAAM,GAAG,YAAY,CAAC;AAEtE,MAAM,MAAM,qBAAqB,GAC7B;IACE,OAAO,EAAE,eAAe,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEN,MAAM,WAAW,mBAAmB;IAClC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"billing.d.ts","sourceRoot":"","sources":["../../src/namespaces/billing.ts"],"names":[],"mappings":"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"}
|