apiblaze 0.20.34 → 0.20.39
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/dist/index.js +824 -687
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -806,7 +806,7 @@ async function createTenantRow(teamId) {
|
|
|
806
806
|
const { name } = await inquirer3.prompt([{
|
|
807
807
|
type: "input",
|
|
808
808
|
name: "name",
|
|
809
|
-
message: `Tenant name ${
|
|
809
|
+
message: `Tenant name ${import_chalk38.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
|
|
810
810
|
validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
|
|
811
811
|
}]);
|
|
812
812
|
const slug = name.trim();
|
|
@@ -821,7 +821,7 @@ async function createTenantRow(teamId) {
|
|
|
821
821
|
} catch (err) {
|
|
822
822
|
const msg = err instanceof Error ? err.message : String(err);
|
|
823
823
|
if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
|
|
824
|
-
console.log(
|
|
824
|
+
console.log(import_chalk38.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
|
|
825
825
|
continue;
|
|
826
826
|
}
|
|
827
827
|
throw err;
|
|
@@ -838,11 +838,11 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
|
|
|
838
838
|
pageSize: 10,
|
|
839
839
|
choices: [
|
|
840
840
|
...PROVIDERS.map((p) => ({ name: p.label, value: p.id })),
|
|
841
|
-
...opts.allowSkip ? [new inquirer3.Separator(), { name:
|
|
841
|
+
...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk38.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
|
|
842
842
|
]
|
|
843
843
|
}]);
|
|
844
844
|
if (!provider) {
|
|
845
|
-
console.log(
|
|
845
|
+
console.log(import_chalk38.default.dim(" No login method yet \u2014 add one later under Login methods."));
|
|
846
846
|
return false;
|
|
847
847
|
}
|
|
848
848
|
const opt = PROVIDERS.find((p) => p.id === provider);
|
|
@@ -888,26 +888,26 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
|
|
|
888
888
|
async function createTenantInteractive(teamId) {
|
|
889
889
|
const { default: inquirer3 } = await import("inquirer");
|
|
890
890
|
const tenant2 = await createTenantRow(teamId);
|
|
891
|
-
console.log(
|
|
891
|
+
console.log(import_chalk38.default.green(` Tenant ${import_chalk38.default.bold(tenant2)} created.`));
|
|
892
892
|
const { users } = await inquirer3.prompt([{
|
|
893
893
|
type: "confirm",
|
|
894
894
|
name: "users",
|
|
895
895
|
default: false,
|
|
896
|
-
message: `Enable Users & groups? ${
|
|
896
|
+
message: `Enable Users & groups? ${import_chalk38.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
|
|
897
897
|
}]);
|
|
898
898
|
if (users) {
|
|
899
899
|
await admin({ method: "PATCH", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/iam`, body: { enabled: true }, summary: "Enable Users & groups" }).catch(() => {
|
|
900
900
|
});
|
|
901
|
-
console.log(
|
|
901
|
+
console.log(import_chalk38.default.green(" Users & groups enabled."));
|
|
902
902
|
}
|
|
903
903
|
await addApiblazeHostedLogin(teamId, tenant2, { allowSkip: true });
|
|
904
904
|
return tenant2;
|
|
905
905
|
}
|
|
906
|
-
var
|
|
906
|
+
var import_chalk38, import_ora14, PROVIDERS, DEFAULT_SCOPES;
|
|
907
907
|
var init_tenant_create = __esm({
|
|
908
908
|
"src/lib/tenant-create.ts"() {
|
|
909
909
|
"use strict";
|
|
910
|
-
|
|
910
|
+
import_chalk38 = __toESM(require("chalk"));
|
|
911
911
|
import_ora14 = __toESM(require("ora"));
|
|
912
912
|
init_admin();
|
|
913
913
|
PROVIDERS = [
|
|
@@ -946,10 +946,10 @@ async function fetchPage2(teamId, q) {
|
|
|
946
946
|
}
|
|
947
947
|
function label(t, defaultTenant, active) {
|
|
948
948
|
const tags = [
|
|
949
|
-
t.tenant_name === active ?
|
|
950
|
-
t.tenant_name === defaultTenant ?
|
|
949
|
+
t.tenant_name === active ? import_chalk39.default.cyan("active scope") : "",
|
|
950
|
+
t.tenant_name === defaultTenant ? import_chalk39.default.dim("team default") : ""
|
|
951
951
|
].filter(Boolean).join(", ");
|
|
952
|
-
const disp = t.display_name && t.display_name !== t.tenant_name ?
|
|
952
|
+
const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk39.default.dim(` ${t.display_name}`) : "";
|
|
953
953
|
return `${t.tenant_name}${disp}${tags ? ` (${tags})` : ""}`;
|
|
954
954
|
}
|
|
955
955
|
async function pickTenant(teamId, opts = {}) {
|
|
@@ -964,7 +964,7 @@ async function pickTenant(teamId, opts = {}) {
|
|
|
964
964
|
const { make } = await inquirer3.prompt([{ type: "confirm", name: "make", message: "No tenants yet \u2014 create one?", default: true }]);
|
|
965
965
|
if (make) return await createTenantInline(teamId);
|
|
966
966
|
}
|
|
967
|
-
console.error(
|
|
967
|
+
console.error(import_chalk39.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
|
|
968
968
|
return null;
|
|
969
969
|
}
|
|
970
970
|
const truncated = page.total > page.rows.length;
|
|
@@ -973,7 +973,7 @@ async function pickTenant(teamId, opts = {}) {
|
|
|
973
973
|
value: t.tenant_name
|
|
974
974
|
}));
|
|
975
975
|
if (truncated || q) {
|
|
976
|
-
choices.push(new inquirer3.Separator(
|
|
976
|
+
choices.push(new inquirer3.Separator(import_chalk39.default.dim(
|
|
977
977
|
truncated ? `showing ${page.rows.length} of ${page.total}${q ? ` matching "${q}"` : ""} \u2014 search to narrow` : `matches for "${q}"`
|
|
978
978
|
)));
|
|
979
979
|
choices.push({ name: `\u{1F50D} Search${q ? " again" : ""}\u2026`, value: "\0search" });
|
|
@@ -1007,11 +1007,11 @@ async function createTenantInline(teamId) {
|
|
|
1007
1007
|
const { createTenantInteractive: createTenantInteractive2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
|
|
1008
1008
|
return createTenantInteractive2(teamId);
|
|
1009
1009
|
}
|
|
1010
|
-
var
|
|
1010
|
+
var import_chalk39, import_ora15, PAGE;
|
|
1011
1011
|
var init_tenant_pick = __esm({
|
|
1012
1012
|
"src/lib/tenant-pick.ts"() {
|
|
1013
1013
|
"use strict";
|
|
1014
|
-
|
|
1014
|
+
import_chalk39 = __toESM(require("chalk"));
|
|
1015
1015
|
import_ora15 = __toESM(require("ora"));
|
|
1016
1016
|
init_admin();
|
|
1017
1017
|
init_auth();
|
|
@@ -1021,10 +1021,10 @@ var init_tenant_pick = __esm({
|
|
|
1021
1021
|
|
|
1022
1022
|
// src/index.ts
|
|
1023
1023
|
var import_commander = require("commander");
|
|
1024
|
-
var
|
|
1024
|
+
var import_chalk55 = __toESM(require("chalk"));
|
|
1025
1025
|
|
|
1026
1026
|
// package.json
|
|
1027
|
-
var version = "0.20.
|
|
1027
|
+
var version = "0.20.39";
|
|
1028
1028
|
|
|
1029
1029
|
// src/index.ts
|
|
1030
1030
|
init_types();
|
|
@@ -2574,7 +2574,8 @@ function codexInteractive(_spec, prompt) {
|
|
|
2574
2574
|
}
|
|
2575
2575
|
var shellQuote = (s) => `"${s.replace(/(["\\$`])/g, "\\$1")}"`;
|
|
2576
2576
|
function directedPrompt(spec2, question) {
|
|
2577
|
-
|
|
2577
|
+
const ctx = spec2.contextNote ? ` ${spec2.contextNote}` : "";
|
|
2578
|
+
return `Use the "${spec2.name}" MCP server (it exposes this API's tools) to answer: ${question}${ctx}`;
|
|
2578
2579
|
}
|
|
2579
2580
|
function agentInstructionFile(cli, dir = process.cwd()) {
|
|
2580
2581
|
return path4.join(dir, cli === "claude" ? "CLAUDE.md" : "AGENTS.md");
|
|
@@ -2607,6 +2608,7 @@ function writeAgentInstruction(cli, spec2, dir = process.cwd()) {
|
|
|
2607
2608
|
`${spec2.projectLabel} API as tools. For any question about this API \u2014 its data, its`,
|
|
2608
2609
|
"records, what it can do \u2014 call those tools rather than answering from memory or",
|
|
2609
2610
|
"asking for data the API can provide.",
|
|
2611
|
+
...spec2.contextNote ? ["", spec2.contextNote] : [],
|
|
2610
2612
|
"",
|
|
2611
2613
|
`_Added by \`apiblaze apichat\`. Remove this block, or run \`npx apiblaze apichat ${spec2.name} --remove-mcp ${cli}\`._`,
|
|
2612
2614
|
m.end,
|
|
@@ -2638,7 +2640,8 @@ function removeAgentInstruction(cli, name, dir = process.cwd()) {
|
|
|
2638
2640
|
}
|
|
2639
2641
|
}
|
|
2640
2642
|
function claudeSystemHint(spec2) {
|
|
2641
|
-
|
|
2643
|
+
const ctx = spec2.contextNote ? ` ${spec2.contextNote}` : "";
|
|
2644
|
+
return `You are connected to the "${spec2.name}" MCP server, which exposes the ${spec2.projectLabel} API as tools (mcp__${spec2.name}__*). For any question about this API, call those tools rather than answering from memory or asking the user for data the API can provide.${ctx}`;
|
|
2642
2645
|
}
|
|
2643
2646
|
function renderCommand(argv) {
|
|
2644
2647
|
return argv.map((a, i) => i === 0 || /^[A-Za-z0-9_@%+=:,./-]+$/.test(a) ? a : shellQuote(a)).join(" ");
|
|
@@ -4211,6 +4214,9 @@ function rememberCliOffer(p, cli, state) {
|
|
|
4211
4214
|
}
|
|
4212
4215
|
function buildInstallSpec(p) {
|
|
4213
4216
|
return {
|
|
4217
|
+
// Control-plane tools take a team_id the model cannot guess; without it the
|
|
4218
|
+
// authorization check runs against `team:` (empty) and every call 403s.
|
|
4219
|
+
contextNote: p.projectId === "externalauth" && p.teamId ? `Your team_id is "${p.teamId}" \u2014 pass it as the team_id argument to any tool that accepts one, and use it wherever a team is required.` : void 0,
|
|
4214
4220
|
name: p.projectId,
|
|
4215
4221
|
url: `https://${p.mcpHost}/${p.version}/${p.environment}`,
|
|
4216
4222
|
// consumerAuth means the door is a login — install bare, the CLI signs in.
|
|
@@ -4254,6 +4260,12 @@ async function maybeInstallExternalCli(p, opts) {
|
|
|
4254
4260
|
);
|
|
4255
4261
|
if (!await ensureInstallableDoor(p, opts)) return false;
|
|
4256
4262
|
if (!await verifyAndHealMcpHost(p)) {
|
|
4263
|
+
if (p.projectId === "externalauth" && p.anon) {
|
|
4264
|
+
fail3(
|
|
4265
|
+
"Chatting with APIblaze needs an account for now.",
|
|
4266
|
+
"Run `apiblaze login` (free, keeps the proxies you already made), then re-run this command."
|
|
4267
|
+
);
|
|
4268
|
+
}
|
|
4257
4269
|
fail3(`The MCP endpoint https://${p.mcpHost}/${p.version}/${p.environment} is not answering \u2014 not installing it into ${cli.label}.`);
|
|
4258
4270
|
}
|
|
4259
4271
|
await authorizeClientRegistration(p, cli.label);
|
|
@@ -4408,6 +4420,86 @@ async function startChat(p, messages, opts) {
|
|
|
4408
4420
|
}
|
|
4409
4421
|
await runRepl(p, messages);
|
|
4410
4422
|
}
|
|
4423
|
+
function isApiblazeControlPlaneTarget(target) {
|
|
4424
|
+
try {
|
|
4425
|
+
const h = new URL(target).hostname.toLowerCase();
|
|
4426
|
+
return h === "api.mcp.apiblaze.com" || /^externalauth(-[a-z0-9]+)?\.mcp\.apiblaze\.com$/.test(h);
|
|
4427
|
+
} catch {
|
|
4428
|
+
return false;
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
function opTenantForTeam(teamId) {
|
|
4432
|
+
return ("op" + (teamId || "")).toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
4433
|
+
}
|
|
4434
|
+
async function openControlPlaneChat() {
|
|
4435
|
+
const creds = loadCredentials();
|
|
4436
|
+
const anonCred = creds?.teamId ? null : loadAnonCred();
|
|
4437
|
+
if (!creds?.teamId && !anonCred?.team_id) {
|
|
4438
|
+
fail3(
|
|
4439
|
+
"Chatting with APIblaze needs a workspace \u2014 its tools act on YOUR proxies.",
|
|
4440
|
+
"Make one first (no signup): apiblaze create --target <your api or spec> --auto"
|
|
4441
|
+
);
|
|
4442
|
+
}
|
|
4443
|
+
const teamId = creds?.teamId ?? anonCred.team_id;
|
|
4444
|
+
const tenant2 = opTenantForTeam(teamId);
|
|
4445
|
+
const projectId = "externalauth";
|
|
4446
|
+
const version2 = "1.0.0";
|
|
4447
|
+
const environment = "prod";
|
|
4448
|
+
const saved = loadApichats().find((a) => a.projectId === projectId);
|
|
4449
|
+
let dpKey = saved?.dpKey ?? anonCred?.cp_key;
|
|
4450
|
+
if (!dpKey) {
|
|
4451
|
+
const spinner = (0, import_ora4.default)("Preparing your APIblaze control-plane key\u2026").start();
|
|
4452
|
+
try {
|
|
4453
|
+
const out = await admin({
|
|
4454
|
+
method: "POST",
|
|
4455
|
+
path: `/teams/${encodeURIComponent(teamId)}/developer-keys`,
|
|
4456
|
+
body: { name: "apichat (APIblaze control plane)" },
|
|
4457
|
+
summary: "Mint a control-plane key for chatting with APIblaze"
|
|
4458
|
+
});
|
|
4459
|
+
dpKey = out?.key;
|
|
4460
|
+
spinner.stop();
|
|
4461
|
+
} catch (err) {
|
|
4462
|
+
spinner.fail("Could not mint a control-plane key.");
|
|
4463
|
+
throw err;
|
|
4464
|
+
}
|
|
4465
|
+
if (!dpKey) fail3("The server returned no control-plane key.");
|
|
4466
|
+
}
|
|
4467
|
+
const p = {
|
|
4468
|
+
projectId,
|
|
4469
|
+
version: version2,
|
|
4470
|
+
environment,
|
|
4471
|
+
dpKey,
|
|
4472
|
+
consumerAuth: false,
|
|
4473
|
+
mcpHost: `${projectId}-${tenant2}.mcp.apiblaze.com`,
|
|
4474
|
+
proxyUrl: `https://api.apiblaze.com/${version2}/${environment}`,
|
|
4475
|
+
anon: !creds?.teamId,
|
|
4476
|
+
access: "invite",
|
|
4477
|
+
tenant: tenant2,
|
|
4478
|
+
teamId
|
|
4479
|
+
};
|
|
4480
|
+
const who = creds?.teamName ?? (anonCred ? "your anonymous workspace" : teamId);
|
|
4481
|
+
console.log(` ${import_chalk14.default.dim("Chatting with:")} ${import_chalk14.default.bold("APIblaze itself")} ${import_chalk14.default.dim(`(${who})`)}`);
|
|
4482
|
+
if (anonCred) {
|
|
4483
|
+
console.log(import_chalk14.default.dim(" Anonymous workspace \u2014 `apiblaze login` then `/claim` inside the chat to keep it."));
|
|
4484
|
+
}
|
|
4485
|
+
upsertApichat({
|
|
4486
|
+
name: projectId,
|
|
4487
|
+
target: "https://api.mcp.apiblaze.com",
|
|
4488
|
+
projectId,
|
|
4489
|
+
version: version2,
|
|
4490
|
+
environment,
|
|
4491
|
+
mcpHost: p.mcpHost,
|
|
4492
|
+
teamId,
|
|
4493
|
+
tenant: tenant2,
|
|
4494
|
+
dpKey,
|
|
4495
|
+
consumerAuth: false,
|
|
4496
|
+
anon: false,
|
|
4497
|
+
ownerUserId: creds?.apiblazeUserId,
|
|
4498
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4499
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4500
|
+
});
|
|
4501
|
+
return { p };
|
|
4502
|
+
}
|
|
4411
4503
|
async function removeExternalMcp(projectId, cliKind) {
|
|
4412
4504
|
const kind = cliKind.toLowerCase();
|
|
4413
4505
|
if (kind !== "claude" && kind !== "codex") fail3(`--remove-mcp takes "claude" or "codex", not "${cliKind}".`);
|
|
@@ -4428,6 +4520,12 @@ async function removeExternalMcp(projectId, cliKind) {
|
|
|
4428
4520
|
async function runApichat(opts) {
|
|
4429
4521
|
setVerbose(opts.verbose === true);
|
|
4430
4522
|
console.log(import_chalk14.default.bold("\napichat \u2014 turn any API into a chat\n"));
|
|
4523
|
+
if (opts.target && isApiblazeControlPlaneTarget(opts.target)) {
|
|
4524
|
+
const cp = await openControlPlaneChat();
|
|
4525
|
+
if (await maybeInstallExternalCli(cp.p, opts)) return;
|
|
4526
|
+
await startChat(cp.p, [], opts);
|
|
4527
|
+
return;
|
|
4528
|
+
}
|
|
4431
4529
|
if (opts.target && !opts.openapispec) {
|
|
4432
4530
|
const { classifyTargetInput: classifyTargetInput2 } = await Promise.resolve().then(() => (init_spec_or_target(), spec_or_target_exports));
|
|
4433
4531
|
const c = await classifyTargetInput2(opts.target, fail3);
|
|
@@ -5328,44 +5426,80 @@ async function runTeam(arg, opts = {}) {
|
|
|
5328
5426
|
activate(creds, chosen);
|
|
5329
5427
|
}
|
|
5330
5428
|
|
|
5429
|
+
// src/commands/docs.ts
|
|
5430
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
5431
|
+
var CONTROL_PLANE_TARGET = "https://api.mcp.apiblaze.com/openapi.json";
|
|
5432
|
+
async function runDocs(opts) {
|
|
5433
|
+
console.log("");
|
|
5434
|
+
console.log(import_chalk21.default.bgYellow.black.bold(" This is not a docs search \u2014 the chatbot can CHANGE your account. "));
|
|
5435
|
+
console.log(import_chalk21.default.yellow(` It connects ${import_chalk21.default.bold("Claude Code")} or ${import_chalk21.default.bold("Codex")} to the real APIblaze API, acting as you:`));
|
|
5436
|
+
console.log(import_chalk21.default.yellow(" it can create proxies, add logins, invite teammates and point domains for real."));
|
|
5437
|
+
console.log(import_chalk21.default.yellow(" Destructive actions (deleting proxies, teams or products) are deliberately not exposed."));
|
|
5438
|
+
console.log(import_chalk21.default.dim(' Read-only questions ("what proxies do I have?") are of course fine.'));
|
|
5439
|
+
console.log("");
|
|
5440
|
+
if (!opts.yes && !opts.prompt && process.stdin.isTTY) {
|
|
5441
|
+
const { default: inquirer3 } = await import("inquirer");
|
|
5442
|
+
const { ok } = await inquirer3.prompt([{
|
|
5443
|
+
type: "confirm",
|
|
5444
|
+
name: "ok",
|
|
5445
|
+
default: true,
|
|
5446
|
+
message: "Continue, knowing the chatbot can act on your account?"
|
|
5447
|
+
}]);
|
|
5448
|
+
if (!ok) {
|
|
5449
|
+
console.log(import_chalk21.default.dim("\n Nothing connected. The written docs are at https://www.apiblaze.com/docs"));
|
|
5450
|
+
return;
|
|
5451
|
+
}
|
|
5452
|
+
}
|
|
5453
|
+
const forwarded = {
|
|
5454
|
+
target: CONTROL_PLANE_TARGET,
|
|
5455
|
+
prompt: opts.prompt,
|
|
5456
|
+
installMcp: opts.installMcp,
|
|
5457
|
+
removeMcp: opts.removeMcp,
|
|
5458
|
+
verbose: opts.verbose,
|
|
5459
|
+
// `--remove-mcp` needs the project name; the control-plane proxy is `externalauth`.
|
|
5460
|
+
...opts.removeMcp ? { project: "externalauth" } : {}
|
|
5461
|
+
};
|
|
5462
|
+
await runApichat(forwarded);
|
|
5463
|
+
}
|
|
5464
|
+
|
|
5331
5465
|
// src/commands/authz.ts
|
|
5332
|
-
var
|
|
5466
|
+
var import_chalk24 = __toESM(require("chalk"));
|
|
5333
5467
|
init_auth();
|
|
5334
5468
|
init_api();
|
|
5335
5469
|
|
|
5336
5470
|
// src/lib/agent-chat.ts
|
|
5337
5471
|
var import_readline = __toESM(require("readline"));
|
|
5338
|
-
var
|
|
5472
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
5339
5473
|
init_api();
|
|
5340
5474
|
init_admin();
|
|
5341
5475
|
async function runAgentChatRepl(opts) {
|
|
5342
5476
|
const { title, subtitle, endpoint, buildBody, seedPrompt, summarizeProposal, commands } = opts;
|
|
5343
|
-
console.log("\n" +
|
|
5344
|
-
if (subtitle) console.log(
|
|
5477
|
+
console.log("\n" + import_chalk22.default.cyan.bold(title));
|
|
5478
|
+
if (subtitle) console.log(import_chalk22.default.dim(subtitle));
|
|
5345
5479
|
const messages = [];
|
|
5346
5480
|
const ctx = { proposal: null, lastData: null, log: (s) => console.log(s) };
|
|
5347
5481
|
const cmdByName = new Map(commands.map((c) => [c.name, c]));
|
|
5348
5482
|
const footer = () => {
|
|
5349
5483
|
const parts = [
|
|
5350
|
-
|
|
5351
|
-
...commands.map((c) =>
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5484
|
+
import_chalk22.default.dim("type to chat/refine"),
|
|
5485
|
+
...commands.map((c) => import_chalk22.default.dim(`/${c.name} ${c.describe}`)),
|
|
5486
|
+
import_chalk22.default.dim("/show"),
|
|
5487
|
+
import_chalk22.default.dim("/exit when done"),
|
|
5488
|
+
import_chalk22.default.dim("/drop discard changes")
|
|
5355
5489
|
];
|
|
5356
|
-
return " " +
|
|
5490
|
+
return " " + import_chalk22.default.dim("[ ") + parts.join(import_chalk22.default.dim(" \xB7 ")) + import_chalk22.default.dim(" ]");
|
|
5357
5491
|
};
|
|
5358
5492
|
async function turn(content) {
|
|
5359
5493
|
messages.push({ role: "user", content });
|
|
5360
|
-
process.stdout.write(
|
|
5494
|
+
process.stdout.write(import_chalk22.default.dim(" \u2026thinking\n"));
|
|
5361
5495
|
const { status, data } = await agentCall(endpoint, "POST", { messages, ...buildBody(messages) });
|
|
5362
5496
|
if (status === 402) {
|
|
5363
|
-
console.log(
|
|
5497
|
+
console.log(import_chalk22.default.red(" Insufficient credits \u2014 top up to keep using the agents.\n"));
|
|
5364
5498
|
messages.pop();
|
|
5365
5499
|
return;
|
|
5366
5500
|
}
|
|
5367
5501
|
if (status >= 400 || !data) {
|
|
5368
|
-
console.log(
|
|
5502
|
+
console.log(import_chalk22.default.red(` Error (${status}): ${(data && data.error) ?? "request failed"}
|
|
5369
5503
|
`));
|
|
5370
5504
|
messages.pop();
|
|
5371
5505
|
return;
|
|
@@ -5373,24 +5507,24 @@ async function runAgentChatRepl(opts) {
|
|
|
5373
5507
|
ctx.lastData = data;
|
|
5374
5508
|
const reply = data.reply ?? data.message ?? "(no reply)";
|
|
5375
5509
|
messages.push({ role: "assistant", content: reply });
|
|
5376
|
-
console.log("\n" +
|
|
5510
|
+
console.log("\n" + import_chalk22.default.cyan("agent \u203A ") + reply + "\n");
|
|
5377
5511
|
if (data.proposal) {
|
|
5378
5512
|
ctx.proposal = data.proposal;
|
|
5379
5513
|
const summary = summarizeProposal?.(data);
|
|
5380
|
-
if (summary) console.log(
|
|
5514
|
+
if (summary) console.log(import_chalk22.default.yellow(" " + summary));
|
|
5381
5515
|
const applies = commands.filter((c) => c.needsProposal);
|
|
5382
5516
|
const primary = applies[applies.length - 1];
|
|
5383
5517
|
if (primary) {
|
|
5384
|
-
console.log(
|
|
5518
|
+
console.log(import_chalk22.default.bold.green(" \u279C Next: type ") + import_chalk22.default.bold.cyan(`/${primary.name}`) + import_chalk22.default.bold.green(" to apply this, then ") + import_chalk22.default.bold.cyan("/exit") + import_chalk22.default.bold.green(" to leave."));
|
|
5385
5519
|
const rest = applies.slice(0, -1).map((c) => `/${c.name} = ${c.describe}`).join(" \xB7 ");
|
|
5386
|
-
console.log(
|
|
5520
|
+
console.log(import_chalk22.default.dim(` (or keep chatting to refine${rest ? ` \xB7 ${rest}` : ""} \xB7 /show = inspect)`));
|
|
5387
5521
|
}
|
|
5388
5522
|
console.log();
|
|
5389
5523
|
}
|
|
5390
5524
|
const line = formatBilling(data.billing);
|
|
5391
5525
|
if (line) {
|
|
5392
5526
|
const llm2 = data.llm;
|
|
5393
|
-
console.log(
|
|
5527
|
+
console.log(import_chalk22.default.dim(` ${line}${llm2?.model ? ` \xB7 ${llm2.model}` : ""}`));
|
|
5394
5528
|
}
|
|
5395
5529
|
}
|
|
5396
5530
|
const rl = import_readline.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -5398,31 +5532,31 @@ async function runAgentChatRepl(opts) {
|
|
|
5398
5532
|
await turn(seedPrompt);
|
|
5399
5533
|
for (; ; ) {
|
|
5400
5534
|
console.log(footer());
|
|
5401
|
-
const line = (await ask(
|
|
5535
|
+
const line = (await ask(import_chalk22.default.green("you \u203A "))).trim();
|
|
5402
5536
|
if (!line) continue;
|
|
5403
5537
|
const lower = line.toLowerCase();
|
|
5404
5538
|
if (line === "/exit" || line === "/quit" || lower === "exit" || lower === "quit" || lower === "q") {
|
|
5405
|
-
console.log(
|
|
5539
|
+
console.log(import_chalk22.default.dim(" Bye \u2014 anything you enabled or published stays in place.\n"));
|
|
5406
5540
|
break;
|
|
5407
5541
|
}
|
|
5408
5542
|
if (line === "/drop") {
|
|
5409
|
-
console.log(
|
|
5543
|
+
console.log(import_chalk22.default.dim(" Dropped the pending proposal \u2014 rules you already enabled/published are untouched.\n"));
|
|
5410
5544
|
break;
|
|
5411
5545
|
}
|
|
5412
5546
|
if (line === "/show") {
|
|
5413
|
-
if (!ctx.proposal) console.log(
|
|
5547
|
+
if (!ctx.proposal) console.log(import_chalk22.default.dim(" No proposal yet \u2014 keep chatting until the agent proposes one.\n"));
|
|
5414
5548
|
else console.log("\n" + JSON.stringify(ctx.proposal, null, 2) + "\n");
|
|
5415
5549
|
continue;
|
|
5416
5550
|
}
|
|
5417
5551
|
if (line.startsWith("/")) {
|
|
5418
5552
|
const cmd = cmdByName.get(line.slice(1));
|
|
5419
5553
|
if (!cmd) {
|
|
5420
|
-
console.log(
|
|
5554
|
+
console.log(import_chalk22.default.red(` Unknown command "${line}". Try one of: ${commands.map((c) => "/" + c.name).join(", ")}, /show, /drop
|
|
5421
5555
|
`));
|
|
5422
5556
|
continue;
|
|
5423
5557
|
}
|
|
5424
5558
|
if (cmd.needsProposal && !ctx.proposal) {
|
|
5425
|
-
console.log(
|
|
5559
|
+
console.log(import_chalk22.default.yellow(" No proposal yet \u2014 keep chatting until the agent generates one, then try again.\n"));
|
|
5426
5560
|
continue;
|
|
5427
5561
|
}
|
|
5428
5562
|
await cmd.run(ctx);
|
|
@@ -5434,7 +5568,7 @@ async function runAgentChatRepl(opts) {
|
|
|
5434
5568
|
}
|
|
5435
5569
|
|
|
5436
5570
|
// src/lib/authz-apply.ts
|
|
5437
|
-
var
|
|
5571
|
+
var import_chalk23 = __toESM(require("chalk"));
|
|
5438
5572
|
init_api();
|
|
5439
5573
|
async function gatherSampleIds(projectId, apiVersion, cap = 50) {
|
|
5440
5574
|
try {
|
|
@@ -5459,10 +5593,10 @@ async function gatherSampleIds(projectId, apiVersion, cap = 50) {
|
|
|
5459
5593
|
}
|
|
5460
5594
|
function maybeWarnNoTraffic(total, projectArg) {
|
|
5461
5595
|
if (total >= 3) return;
|
|
5462
|
-
console.log(
|
|
5463
|
-
console.log(
|
|
5464
|
-
console.log(
|
|
5465
|
-
console.log(
|
|
5596
|
+
console.log(import_chalk23.default.yellow(total === 0 ? " \u26A0 No captured traffic for this API yet." : ` \u26A0 Only ${total} captured request(s) so far.`));
|
|
5597
|
+
console.log(import_chalk23.default.dim(" The authorization agent designs much better models & rules from REAL requests"));
|
|
5598
|
+
console.log(import_chalk23.default.dim(" (it sees who is allowed vs denied). Send some through your proxy first \u2014"));
|
|
5599
|
+
console.log(import_chalk23.default.dim(` curl a few endpoints, or `) + import_chalk23.default.cyan("npx apiblaze dev") + import_chalk23.default.dim(` \u2014 then re-run.
|
|
5466
5600
|
`));
|
|
5467
5601
|
}
|
|
5468
5602
|
async function applyProposal(opts) {
|
|
@@ -5471,11 +5605,11 @@ async function applyProposal(opts) {
|
|
|
5471
5605
|
{
|
|
5472
5606
|
const m = await agentCall(`/projects/${projectId}/${apiVersion}/policies/model?tenantId=${encodeURIComponent(tenant2)}`, "POST", proposal.model);
|
|
5473
5607
|
if (m.status === 404) {
|
|
5474
|
-
log(
|
|
5608
|
+
log(import_chalk23.default.red(" Authorization store not provisioned yet. Open the dashboard Authorization tab for this project once (it auto-provisions the store), then re-run.\n"));
|
|
5475
5609
|
return { ok: 0, fail: 0, enabled: false, storeMissing: true };
|
|
5476
5610
|
}
|
|
5477
5611
|
if (m.status >= 400) {
|
|
5478
|
-
log(
|
|
5612
|
+
log(import_chalk23.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
|
|
5479
5613
|
`));
|
|
5480
5614
|
return { ok: 0, fail: 0, enabled: false };
|
|
5481
5615
|
}
|
|
@@ -5504,7 +5638,7 @@ async function applyProposal(opts) {
|
|
|
5504
5638
|
if (enable) {
|
|
5505
5639
|
const e = await agentCall(`/projects/${projectId}/${apiVersion}`, "PATCH", { authorization: { enforce_authorization: true }, tenant: tenant2 });
|
|
5506
5640
|
if (e.status >= 400) {
|
|
5507
|
-
log(
|
|
5641
|
+
log(import_chalk23.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
|
|
5508
5642
|
`));
|
|
5509
5643
|
return { ok, fail: fail6, enabled: false };
|
|
5510
5644
|
}
|
|
@@ -5530,10 +5664,10 @@ async function runAuthz(projectArg, apiVersionArg) {
|
|
|
5530
5664
|
const r = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable, log: ctx.log });
|
|
5531
5665
|
if (r.storeMissing) return;
|
|
5532
5666
|
if (enable && r.enabled) {
|
|
5533
|
-
ctx.log(
|
|
5534
|
-
ctx.log(
|
|
5667
|
+
ctx.log(import_chalk24.default.green(` \u2713 Enforcement ON \u2014 ${r.ok} route(s) + project switch on${r.fail ? `, ${r.fail} failed` : ""}.`));
|
|
5668
|
+
ctx.log(import_chalk24.default.dim(" Done here? Type /exit to leave the chat (your rule stays on).\n"));
|
|
5535
5669
|
} else if (!enable) {
|
|
5536
|
-
ctx.log(
|
|
5670
|
+
ctx.log(import_chalk24.default.green(` \u2713 Published (shadow): model + ${r.ok} route(s)${r.fail ? `, ${r.fail} failed` : ""}. Review, then /enable.
|
|
5537
5671
|
`));
|
|
5538
5672
|
}
|
|
5539
5673
|
}
|
|
@@ -5560,7 +5694,7 @@ async function runAuthz(projectArg, apiVersionArg) {
|
|
|
5560
5694
|
}
|
|
5561
5695
|
|
|
5562
5696
|
// src/commands/rule.ts
|
|
5563
|
-
var
|
|
5697
|
+
var import_chalk25 = __toESM(require("chalk"));
|
|
5564
5698
|
var import_ora8 = __toESM(require("ora"));
|
|
5565
5699
|
init_auth();
|
|
5566
5700
|
init_api();
|
|
@@ -5597,27 +5731,27 @@ async function runRule(ruleText, projectArg, opts) {
|
|
|
5597
5731
|
const proposal = data?.proposal;
|
|
5598
5732
|
if (!proposal || !Array.isArray(proposal.routes) || proposal.routes.length === 0) {
|
|
5599
5733
|
spinner.fail("The agent couldn\u2019t turn that into a rule in one shot.");
|
|
5600
|
-
if (data?.reply) console.log(
|
|
5601
|
-
console.log(
|
|
5734
|
+
if (data?.reply) console.log(import_chalk25.default.dim("\n " + String(data.reply).slice(0, 500) + "\n"));
|
|
5735
|
+
console.log(import_chalk25.default.dim(" Try an interactive session for anything nuanced: ") + import_chalk25.default.cyan(`apiblaze agent authz ${projectArg}`));
|
|
5602
5736
|
return;
|
|
5603
5737
|
}
|
|
5604
5738
|
spinner.succeed(`Rule designed \u2014 ${proposal.routes.length} route(s) affected.`);
|
|
5605
|
-
if (data?.reply) console.log(
|
|
5739
|
+
if (data?.reply) console.log(import_chalk25.default.dim(" " + String(data.reply).slice(0, 240)));
|
|
5606
5740
|
const pub = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: false });
|
|
5607
5741
|
if (pub.storeMissing) return;
|
|
5608
|
-
console.log(
|
|
5742
|
+
console.log(import_chalk25.default.green(` \u2713 Published in shadow mode \u2014 model + ${pub.ok} route(s)${pub.fail ? `, ${pub.fail} failed` : ""}.`));
|
|
5609
5743
|
if (opts.enforce) {
|
|
5610
5744
|
const enf = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: true });
|
|
5611
5745
|
if (enf.enabled) {
|
|
5612
|
-
console.log(
|
|
5746
|
+
console.log(import_chalk25.default.green(` \u2713 Enforcement ON \u2014 ${enf.ok} route(s) + project switch on${enf.fail ? `, ${enf.fail} failed` : ""}.`));
|
|
5613
5747
|
}
|
|
5614
5748
|
} else {
|
|
5615
|
-
console.log(
|
|
5749
|
+
console.log(import_chalk25.default.dim(` Review it (shadow logs), then enforce: `) + import_chalk25.default.cyan(`apiblaze rule "${rule}" ${projectArg} --enforce`));
|
|
5616
5750
|
}
|
|
5617
5751
|
}
|
|
5618
5752
|
|
|
5619
5753
|
// src/commands/openapi.ts
|
|
5620
|
-
var
|
|
5754
|
+
var import_chalk26 = __toESM(require("chalk"));
|
|
5621
5755
|
init_auth();
|
|
5622
5756
|
init_api();
|
|
5623
5757
|
async function runOpenapi(projectArg, apiVersionArg) {
|
|
@@ -5628,10 +5762,10 @@ async function runOpenapi(projectArg, apiVersionArg) {
|
|
|
5628
5762
|
if (!match) throw new Error(`Project "${projectArg}" not found in your active team. Run \`apiblaze projects\`.`);
|
|
5629
5763
|
const projectId = match.projectId;
|
|
5630
5764
|
const apiVersion = apiVersionArg || match.apiVersion;
|
|
5631
|
-
console.log(
|
|
5765
|
+
console.log(import_chalk26.default.dim("Gathering captured traffic samples\u2026"));
|
|
5632
5766
|
const routesRes = await agentCall(`/projects/${projectId}/${apiVersion}/samples/routes`, "GET");
|
|
5633
5767
|
if (routesRes.status >= 400) {
|
|
5634
|
-
console.log(
|
|
5768
|
+
console.log(import_chalk26.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
|
|
5635
5769
|
return;
|
|
5636
5770
|
}
|
|
5637
5771
|
const routes = routesRes.data?.routes ?? (Array.isArray(routesRes.data) ? routesRes.data : []);
|
|
@@ -5644,25 +5778,25 @@ async function runOpenapi(projectArg, apiVersionArg) {
|
|
|
5644
5778
|
}
|
|
5645
5779
|
const sampleIds = [...ids];
|
|
5646
5780
|
if (sampleIds.length === 0) {
|
|
5647
|
-
console.log(
|
|
5781
|
+
console.log(import_chalk26.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
|
|
5648
5782
|
return;
|
|
5649
5783
|
}
|
|
5650
5784
|
async function publish(ctx) {
|
|
5651
5785
|
const patch = ctx.proposal.patch;
|
|
5652
5786
|
if (!Array.isArray(patch) || patch.length === 0) {
|
|
5653
|
-
ctx.log(
|
|
5787
|
+
ctx.log(import_chalk26.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
|
|
5654
5788
|
return;
|
|
5655
5789
|
}
|
|
5656
5790
|
const specSource = ctx.lastData?.spec_source ?? "unknown";
|
|
5657
5791
|
const endpoint = specSource === "github" ? "open-pr" : "publish-openapi";
|
|
5658
5792
|
const pub = await agentCall(`/projects/${projectId}/${apiVersion}/samples/${endpoint}`, "POST", { patch, sample_ids_used: sampleIds });
|
|
5659
5793
|
if (pub.status >= 400) {
|
|
5660
|
-
ctx.log(
|
|
5794
|
+
ctx.log(import_chalk26.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
|
|
5661
5795
|
`));
|
|
5662
5796
|
return;
|
|
5663
5797
|
}
|
|
5664
5798
|
const prUrl = pub.data?.pr_url;
|
|
5665
|
-
ctx.log(
|
|
5799
|
+
ctx.log(import_chalk26.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
|
|
5666
5800
|
` : " \u2713 Published updated OpenAPI spec.\n"));
|
|
5667
5801
|
}
|
|
5668
5802
|
await runAgentChatRepl({
|
|
@@ -5683,7 +5817,7 @@ async function runOpenapi(projectArg, apiVersionArg) {
|
|
|
5683
5817
|
}
|
|
5684
5818
|
|
|
5685
5819
|
// src/commands/mcp.ts
|
|
5686
|
-
var
|
|
5820
|
+
var import_chalk27 = __toESM(require("chalk"));
|
|
5687
5821
|
init_auth();
|
|
5688
5822
|
init_api();
|
|
5689
5823
|
async function runMcp(projectArg, apiVersionArg, opts) {
|
|
@@ -5700,11 +5834,11 @@ async function runMcp(projectArg, apiVersionArg, opts) {
|
|
|
5700
5834
|
const spec2 = ctx.proposal;
|
|
5701
5835
|
const pub = await agentCall(`/projects/${projectId}/${apiVersion}/mcp/spec`, "PUT", { environment, spec: spec2 });
|
|
5702
5836
|
if (pub.status >= 400) {
|
|
5703
|
-
ctx.log(
|
|
5837
|
+
ctx.log(import_chalk27.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
|
|
5704
5838
|
`));
|
|
5705
5839
|
return;
|
|
5706
5840
|
}
|
|
5707
|
-
ctx.log(
|
|
5841
|
+
ctx.log(import_chalk27.default.green(` \u2713 Published MCP server \u2014 ${mcpHost}.mcp.apiblaze.com/${apiVersion}/${environment}.
|
|
5708
5842
|
`));
|
|
5709
5843
|
}
|
|
5710
5844
|
await runAgentChatRepl({
|
|
@@ -5726,7 +5860,7 @@ async function runMcp(projectArg, apiVersionArg, opts) {
|
|
|
5726
5860
|
}
|
|
5727
5861
|
|
|
5728
5862
|
// src/commands/delete.ts
|
|
5729
|
-
var
|
|
5863
|
+
var import_chalk28 = __toESM(require("chalk"));
|
|
5730
5864
|
var import_ora9 = __toESM(require("ora"));
|
|
5731
5865
|
init_admin();
|
|
5732
5866
|
init_resolve();
|
|
@@ -5752,10 +5886,10 @@ async function runDelete(project, version2, opts) {
|
|
|
5752
5886
|
return;
|
|
5753
5887
|
}
|
|
5754
5888
|
} else {
|
|
5755
|
-
console.log(`${
|
|
5889
|
+
console.log(`${import_chalk28.default.red.bold("Delete")} ${import_chalk28.default.bold(proj2.projectName)} ${import_chalk28.default.dim("v" + proj2.apiVersion)} ${import_chalk28.default.dim("(" + proj2.projectId + ")")}`);
|
|
5756
5890
|
if (impact && typeof impact === "object") {
|
|
5757
5891
|
const counts = impact.counts ?? impact.impact ?? impact;
|
|
5758
|
-
console.log(
|
|
5892
|
+
console.log(import_chalk28.default.dim(" This removes (cascade): ") + import_chalk28.default.yellow(JSON.stringify(counts)));
|
|
5759
5893
|
}
|
|
5760
5894
|
if (!opts.yes) {
|
|
5761
5895
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -5763,7 +5897,7 @@ async function runDelete(project, version2, opts) {
|
|
|
5763
5897
|
{ type: "confirm", name: "confirm", message: `Permanently delete ${proj2.projectName} v${proj2.apiVersion}? This cannot be undone.`, default: false }
|
|
5764
5898
|
]);
|
|
5765
5899
|
if (!confirm2) {
|
|
5766
|
-
console.log(
|
|
5900
|
+
console.log(import_chalk28.default.dim("Aborted."));
|
|
5767
5901
|
return;
|
|
5768
5902
|
}
|
|
5769
5903
|
}
|
|
@@ -5784,7 +5918,7 @@ async function runDelete(project, version2, opts) {
|
|
|
5784
5918
|
}
|
|
5785
5919
|
|
|
5786
5920
|
// src/commands/export.ts
|
|
5787
|
-
var
|
|
5921
|
+
var import_chalk29 = __toESM(require("chalk"));
|
|
5788
5922
|
var import_fs3 = require("fs");
|
|
5789
5923
|
init_admin();
|
|
5790
5924
|
init_auth();
|
|
@@ -5803,7 +5937,7 @@ async function runExport(projectArg, versionArg, opts) {
|
|
|
5803
5937
|
if (opts.noConsumers) q.set("include_consumers", "0");
|
|
5804
5938
|
if (opts.keys) q.set("keys", opts.keys);
|
|
5805
5939
|
const qs = q.toString() ? `?${q.toString()}` : "";
|
|
5806
|
-
console.log(
|
|
5940
|
+
console.log(import_chalk29.default.dim(`Queuing ${target} export of ${projectId}@${version2}\u2026`));
|
|
5807
5941
|
const job = await admin({
|
|
5808
5942
|
path: `/projects/${projectId}/${version2}/export/${target}${qs}`,
|
|
5809
5943
|
method: "GET",
|
|
@@ -5813,11 +5947,11 @@ async function runExport(projectArg, versionArg, opts) {
|
|
|
5813
5947
|
const statusPath = `/projects/${projectId}/${version2}/export/jobs/${job.job_id}`;
|
|
5814
5948
|
let status = "queued";
|
|
5815
5949
|
const started = Date.now();
|
|
5816
|
-
process.stdout.write(
|
|
5950
|
+
process.stdout.write(import_chalk29.default.dim("Building bundle"));
|
|
5817
5951
|
while (status !== "ready" && status !== "failed") {
|
|
5818
5952
|
if (Date.now() - started > 10 * 6e4) throw new Error("Export timed out after 10 minutes.");
|
|
5819
5953
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
5820
|
-
process.stdout.write(
|
|
5954
|
+
process.stdout.write(import_chalk29.default.dim("."));
|
|
5821
5955
|
const st = await admin({ path: statusPath, method: "GET", summary: "poll export" });
|
|
5822
5956
|
status = st?.status ?? "queued";
|
|
5823
5957
|
if (status === "failed") {
|
|
@@ -5835,14 +5969,14 @@ async function runExport(projectArg, versionArg, opts) {
|
|
|
5835
5969
|
if (!res.ok) throw new Error(`Download failed (${res.status}): ${await res.text().catch(() => "")}`);
|
|
5836
5970
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
5837
5971
|
(0, import_fs3.writeFileSync)(outFile, buf);
|
|
5838
|
-
console.log(
|
|
5839
|
-
if (job.decryption_key) console.log(
|
|
5840
|
-
console.log(
|
|
5841
|
-
if (target === "kong") console.log(
|
|
5972
|
+
console.log(import_chalk29.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
|
|
5973
|
+
if (job.decryption_key) console.log(import_chalk29.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
|
|
5974
|
+
console.log(import_chalk29.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
|
|
5975
|
+
if (target === "kong") console.log(import_chalk29.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
|
|
5842
5976
|
}
|
|
5843
5977
|
|
|
5844
5978
|
// src/commands/recipe-search.ts
|
|
5845
|
-
var
|
|
5979
|
+
var import_chalk30 = __toESM(require("chalk"));
|
|
5846
5980
|
var import_ora10 = __toESM(require("ora"));
|
|
5847
5981
|
init_caller();
|
|
5848
5982
|
|
|
@@ -6043,20 +6177,20 @@ async function runRecipeSearch(query, opts) {
|
|
|
6043
6177
|
return;
|
|
6044
6178
|
}
|
|
6045
6179
|
if (!hits.length) {
|
|
6046
|
-
console.log(
|
|
6047
|
-
console.log(
|
|
6180
|
+
console.log(import_chalk30.default.yellow(query ? `No public recipes match "${query}".` : "No public recipes yet."));
|
|
6181
|
+
console.log(import_chalk30.default.dim(" Publish one with: apiblaze publish <proxy> --as @yourhandle/name"));
|
|
6048
6182
|
return;
|
|
6049
6183
|
}
|
|
6050
6184
|
console.log();
|
|
6051
6185
|
for (const h of hits) {
|
|
6052
|
-
const pin = h.latest_revision ?
|
|
6053
|
-
const installs = h.install_count ?
|
|
6054
|
-
console.log(` ${
|
|
6055
|
-
if (h.summary) console.log(` ${
|
|
6186
|
+
const pin = h.latest_revision ? import_chalk30.default.dim(`@${h.latest_revision}`) : "";
|
|
6187
|
+
const installs = h.install_count ? import_chalk30.default.dim(` ${h.install_count} install${h.install_count === 1 ? "" : "s"}`) : "";
|
|
6188
|
+
console.log(` ${import_chalk30.default.bold(h.name)}${pin}${h.display_name ? import_chalk30.default.dim(` \u2014 ${h.display_name}`) : ""}${installs}`);
|
|
6189
|
+
if (h.summary) console.log(` ${import_chalk30.default.dim(h.summary)}`);
|
|
6056
6190
|
}
|
|
6057
6191
|
console.log();
|
|
6058
|
-
console.log(
|
|
6059
|
-
console.log(
|
|
6192
|
+
console.log(import_chalk30.default.dim(` Install one with: ${import_chalk30.default.cyan(`npx apiblaze install ${hits[0].name}`)}`));
|
|
6193
|
+
console.log(import_chalk30.default.dim(` Read one first: ${import_chalk30.default.cyan(`npx apiblaze show ${hits[0].name}`)}`));
|
|
6060
6194
|
console.log();
|
|
6061
6195
|
}
|
|
6062
6196
|
async function runRecipeShow(nameArg, opts) {
|
|
@@ -6082,8 +6216,8 @@ async function runRecipeShow(nameArg, opts) {
|
|
|
6082
6216
|
return;
|
|
6083
6217
|
}
|
|
6084
6218
|
console.log();
|
|
6085
|
-
console.log(`${
|
|
6086
|
-
if (recipe.display_name) console.log(` ${
|
|
6219
|
+
console.log(`${import_chalk30.default.bold(`${recipe.name}@${recipe.revision}`)}${import_chalk30.default.dim(` \u2014 by ${ref.handle}`)}`);
|
|
6220
|
+
if (recipe.display_name) console.log(` ${import_chalk30.default.bold(recipe.display_name)}`);
|
|
6087
6221
|
if (recipe.summary) console.log(` ${recipe.summary}`);
|
|
6088
6222
|
const meta = [
|
|
6089
6223
|
head?.install_count !== void 0 ? `${head.install_count} install${head.install_count === 1 ? "" : "s"}` : null,
|
|
@@ -6091,7 +6225,7 @@ async function runRecipeShow(nameArg, opts) {
|
|
|
6091
6225
|
recipe.published_at ? `published ${recipe.published_at.slice(0, 10)}` : null,
|
|
6092
6226
|
`api version ${recipe.api_version}`
|
|
6093
6227
|
].filter(Boolean).join(" \xB7 ");
|
|
6094
|
-
console.log(
|
|
6228
|
+
console.log(import_chalk30.default.dim(` ${meta}`));
|
|
6095
6229
|
console.log();
|
|
6096
6230
|
if (wantsSection) {
|
|
6097
6231
|
if (opts.settings) printSection("settings", recipe.settings);
|
|
@@ -6105,34 +6239,34 @@ async function runRecipeShow(nameArg, opts) {
|
|
|
6105
6239
|
const rules = recipe.transformations?.rules?.length ?? 0;
|
|
6106
6240
|
const tables = recipe.transformations?.mapping_tables?.length ?? 0;
|
|
6107
6241
|
const keyTypes = recipe.auth?.key_types?.length ?? 0;
|
|
6108
|
-
if (hosts.length) console.log(` ${
|
|
6109
|
-
console.log(` ${
|
|
6110
|
-
console.log(` ${
|
|
6242
|
+
if (hosts.length) console.log(` ${import_chalk30.default.dim("sends requests to")} ${hosts.join(", ")}`);
|
|
6243
|
+
console.log(` ${import_chalk30.default.dim("creates ")} ${describeCreates(keyTypes, routes, !!recipe.settings.mcp_enabled)}`);
|
|
6244
|
+
console.log(` ${import_chalk30.default.dim("asks you for ")} ${recipe.questions.length} value${recipe.questions.length === 1 ? "" : "s"}`);
|
|
6111
6245
|
if (rules || tables) {
|
|
6112
|
-
console.log(` ${
|
|
6246
|
+
console.log(` ${import_chalk30.default.dim("transforms ")} ${rules} rule${rules === 1 ? "" : "s"}${tables ? `, ${tables} mapping table${tables === 1 ? "" : "s"}` : ""}`);
|
|
6113
6247
|
}
|
|
6114
6248
|
if (recipe.settings.publish_openapi === true) {
|
|
6115
|
-
console.log(` ${
|
|
6249
|
+
console.log(` ${import_chalk30.default.dim("makes public ")} this API's spec`);
|
|
6116
6250
|
}
|
|
6117
6251
|
if (recipe.questions.length) {
|
|
6118
6252
|
console.log();
|
|
6119
|
-
console.log(
|
|
6253
|
+
console.log(import_chalk30.default.bold(" It will ask you for"));
|
|
6120
6254
|
for (const q of recipe.questions) {
|
|
6121
|
-
console.log(` ${q.prompt}${q.secret ?
|
|
6122
|
-
if (q.example) console.log(
|
|
6255
|
+
console.log(` ${q.prompt}${q.secret ? import_chalk30.default.dim(" (hidden while you type)") : ""}`);
|
|
6256
|
+
if (q.example) console.log(import_chalk30.default.dim(` e.g. ${q.example}`));
|
|
6123
6257
|
}
|
|
6124
6258
|
}
|
|
6125
6259
|
if (recipe.requires_confirmation?.length) {
|
|
6126
6260
|
console.log();
|
|
6127
|
-
console.log(
|
|
6261
|
+
console.log(import_chalk30.default.yellow(" Needs your explicit consent at install time"));
|
|
6128
6262
|
for (const c of recipe.requires_confirmation) {
|
|
6129
|
-
console.log(` ${
|
|
6130
|
-
console.log(
|
|
6263
|
+
console.log(` ${import_chalk30.default.bold(c.kind)} ${c.value}`);
|
|
6264
|
+
console.log(import_chalk30.default.dim(` ${c.why}`));
|
|
6131
6265
|
}
|
|
6132
6266
|
}
|
|
6133
6267
|
console.log();
|
|
6134
|
-
console.log(
|
|
6135
|
-
console.log(
|
|
6268
|
+
console.log(import_chalk30.default.dim(` Install: ${import_chalk30.default.cyan(`npx apiblaze install ${recipe.name}`)}`));
|
|
6269
|
+
console.log(import_chalk30.default.dim(" Sections: --settings --auth --transforms --openapi"));
|
|
6136
6270
|
console.log();
|
|
6137
6271
|
}
|
|
6138
6272
|
function describeCreates(keyTypes, routes, mcp, includeProxy = true) {
|
|
@@ -6142,45 +6276,45 @@ function describeCreates(keyTypes, routes, mcp, includeProxy = true) {
|
|
|
6142
6276
|
return parts.length ? parts.join(", ") : "nothing else";
|
|
6143
6277
|
}
|
|
6144
6278
|
function printSection(title, value) {
|
|
6145
|
-
console.log(
|
|
6279
|
+
console.log(import_chalk30.default.bold(` ${title}`));
|
|
6146
6280
|
console.log(indent(JSON.stringify(value ?? null, null, 2), " "));
|
|
6147
6281
|
console.log();
|
|
6148
6282
|
}
|
|
6149
6283
|
function printAuth(recipe) {
|
|
6150
6284
|
const a = recipe.auth ?? { app_client: null, provider: null, key_types: [] };
|
|
6151
|
-
console.log(
|
|
6285
|
+
console.log(import_chalk30.default.bold(" auth"));
|
|
6152
6286
|
if (a.provider) {
|
|
6153
|
-
console.log(` ${
|
|
6154
|
-
if (a.provider.scopes) console.log(` ${
|
|
6155
|
-
if (a.provider.target_server_token) console.log(` ${
|
|
6156
|
-
console.log(
|
|
6287
|
+
console.log(` ${import_chalk30.default.dim("provider ")} ${a.provider.type ?? "(unknown)"}`);
|
|
6288
|
+
if (a.provider.scopes) console.log(` ${import_chalk30.default.dim("scopes ")} ${a.provider.scopes}`);
|
|
6289
|
+
if (a.provider.target_server_token) console.log(` ${import_chalk30.default.dim("sends to API")} ${a.provider.target_server_token}`);
|
|
6290
|
+
console.log(import_chalk30.default.dim(" (no credentials travel in a recipe \u2014 install asks you for your own)"));
|
|
6157
6291
|
} else {
|
|
6158
|
-
console.log(
|
|
6292
|
+
console.log(import_chalk30.default.dim(" no login provider \u2014 consumers call it with an API key"));
|
|
6159
6293
|
}
|
|
6160
6294
|
if (a.app_client) {
|
|
6161
|
-
console.log(` ${
|
|
6295
|
+
console.log(` ${import_chalk30.default.dim("login app ")} ${a.app_client.name ?? "(unnamed)"}`);
|
|
6162
6296
|
}
|
|
6163
6297
|
if (a.key_types?.length) {
|
|
6164
|
-
console.log(` ${
|
|
6298
|
+
console.log(` ${import_chalk30.default.dim("key types ")} ${a.key_types.map((k) => String(k.name)).join(", ")}`);
|
|
6165
6299
|
}
|
|
6166
6300
|
console.log();
|
|
6167
6301
|
}
|
|
6168
6302
|
function printTransforms(recipe) {
|
|
6169
6303
|
const rules = recipe.transformations?.rules ?? [];
|
|
6170
6304
|
const tables = recipe.transformations?.mapping_tables ?? [];
|
|
6171
|
-
console.log(
|
|
6305
|
+
console.log(import_chalk30.default.bold(` transforms (${rules.length})`));
|
|
6172
6306
|
for (const r of rules) {
|
|
6173
|
-
const off = r.enabled === false ?
|
|
6174
|
-
console.log(` ${
|
|
6307
|
+
const off = r.enabled === false ? import_chalk30.default.dim(" (disabled)") : "";
|
|
6308
|
+
console.log(` ${import_chalk30.default.bold(String(r.name ?? "(unnamed)"))} ${import_chalk30.default.dim(String(r.phase ?? "request"))}${off}`);
|
|
6175
6309
|
console.log(indent(JSON.stringify(r.action ?? null, null, 2), " "));
|
|
6176
6310
|
if (r.condition) console.log(indent(`when ${JSON.stringify(r.condition)}`, " "));
|
|
6177
6311
|
}
|
|
6178
6312
|
if (tables.length) {
|
|
6179
6313
|
console.log();
|
|
6180
|
-
console.log(
|
|
6314
|
+
console.log(import_chalk30.default.bold(` mapping tables (${tables.length})`));
|
|
6181
6315
|
for (const t of tables) {
|
|
6182
6316
|
const entries2 = Array.isArray(t.entries) ? t.entries.length : 0;
|
|
6183
|
-
console.log(` ${
|
|
6317
|
+
console.log(` ${import_chalk30.default.bold(String(t.name ?? "(unnamed)"))} ${import_chalk30.default.dim(`${entries2} entr${entries2 === 1 ? "y" : "ies"}`)}`);
|
|
6184
6318
|
}
|
|
6185
6319
|
}
|
|
6186
6320
|
console.log();
|
|
@@ -6190,7 +6324,7 @@ function indent(text, pad) {
|
|
|
6190
6324
|
}
|
|
6191
6325
|
|
|
6192
6326
|
// src/commands/recipe-install.ts
|
|
6193
|
-
var
|
|
6327
|
+
var import_chalk31 = __toESM(require("chalk"));
|
|
6194
6328
|
init_types();
|
|
6195
6329
|
init_caller();
|
|
6196
6330
|
init_api();
|
|
@@ -6207,7 +6341,7 @@ async function runRecipeInstall(nameArg, opts) {
|
|
|
6207
6341
|
const chosenTeamId = picked.chosen ? picked.teamId : void 0;
|
|
6208
6342
|
const teamName = picked.teamName;
|
|
6209
6343
|
console.log();
|
|
6210
|
-
console.log(`${
|
|
6344
|
+
console.log(`${import_chalk31.default.bold(pinned)}${import_chalk31.default.dim(` \u2014 by ${ref.handle}`)}`);
|
|
6211
6345
|
if (recipe.summary) console.log(` ${recipe.summary}`);
|
|
6212
6346
|
console.log();
|
|
6213
6347
|
let project;
|
|
@@ -6231,7 +6365,7 @@ async function runRecipeInstall(nameArg, opts) {
|
|
|
6231
6365
|
reuseTenant = chosenTenant.existing;
|
|
6232
6366
|
printSummary(recipe, project, tenant2, reuseTenant);
|
|
6233
6367
|
if (!assumeYes && !await confirmYesNo(" continue?", interactive)) {
|
|
6234
|
-
console.log(
|
|
6368
|
+
console.log(import_chalk31.default.yellow(" Cancelled \u2014 nothing was created."));
|
|
6235
6369
|
return;
|
|
6236
6370
|
}
|
|
6237
6371
|
}
|
|
@@ -6250,18 +6384,18 @@ async function runRecipeInstall(nameArg, opts) {
|
|
|
6250
6384
|
process.stdout.write(` ${step.label.padEnd(33)}`);
|
|
6251
6385
|
try {
|
|
6252
6386
|
const note = await step.run();
|
|
6253
|
-
console.log(`${
|
|
6387
|
+
console.log(`${import_chalk31.default.green("\u2713")}${note ? ` ${import_chalk31.default.dim(note)}` : ""}`);
|
|
6254
6388
|
} catch (err) {
|
|
6255
|
-
console.log(`${
|
|
6389
|
+
console.log(`${import_chalk31.default.red("\u2717")} ${import_chalk31.default.red(describeError(err))}`);
|
|
6256
6390
|
console.log();
|
|
6257
6391
|
if (step.n === 1) {
|
|
6258
|
-
console.log(
|
|
6392
|
+
console.log(import_chalk31.default.red(`stopped at step 1 of ${steps.length}. Nothing was created.`));
|
|
6259
6393
|
console.log("run the same command again once the problem above is fixed:");
|
|
6260
|
-
console.log(
|
|
6394
|
+
console.log(import_chalk31.default.cyan(` npx apiblaze install ${nameArg}`));
|
|
6261
6395
|
} else {
|
|
6262
|
-
console.log(
|
|
6396
|
+
console.log(import_chalk31.default.red(`stopped at step ${step.n} of ${steps.length}. ${project} exists but is not finished.`));
|
|
6263
6397
|
console.log("continue with:");
|
|
6264
|
-
console.log(
|
|
6398
|
+
console.log(import_chalk31.default.cyan(` npx apiblaze install ${nameArg} --into ${project}`));
|
|
6265
6399
|
}
|
|
6266
6400
|
console.log();
|
|
6267
6401
|
process.exit(1);
|
|
@@ -6271,9 +6405,9 @@ async function runRecipeInstall(nameArg, opts) {
|
|
|
6271
6405
|
const urls = installUrls(ctx);
|
|
6272
6406
|
console.log();
|
|
6273
6407
|
console.log(`done in ${secs}s.`);
|
|
6274
|
-
console.log(` ${
|
|
6275
|
-
if (recipe.settings.mcp_enabled === true) console.log(` ${
|
|
6276
|
-
if (recipe.settings.enable_portal === true) console.log(` ${
|
|
6408
|
+
console.log(` ${import_chalk31.default.dim("proxy ")} ${import_chalk31.default.bold(urls.proxy_url)}`);
|
|
6409
|
+
if (recipe.settings.mcp_enabled === true) console.log(` ${import_chalk31.default.dim("mcp ")} ${import_chalk31.default.bold(urls.mcp_url)}`);
|
|
6410
|
+
if (recipe.settings.enable_portal === true) console.log(` ${import_chalk31.default.dim("portal")} ${import_chalk31.default.bold(urls.portal_url)}`);
|
|
6277
6411
|
console.log();
|
|
6278
6412
|
}
|
|
6279
6413
|
function buildSteps(inp) {
|
|
@@ -6589,7 +6723,7 @@ async function nameIsFree(name, teamId) {
|
|
|
6589
6723
|
async function chooseProxyName(slug, asOpt, teamId, interactive) {
|
|
6590
6724
|
if (asOpt !== void 0) {
|
|
6591
6725
|
const name = normalizeName3(asOpt);
|
|
6592
|
-
if (name !== asOpt) console.log(
|
|
6726
|
+
if (name !== asOpt) console.log(import_chalk31.default.yellow(` Using "${name}" \u2014 names are lowercase letters and digits only.`));
|
|
6593
6727
|
if (name.length < 3) throw new Error("A proxy name must be at least 3 characters (lowercase letters and digits only).");
|
|
6594
6728
|
const free = await nameIsFree(name, teamId);
|
|
6595
6729
|
if (free === false) throw new Error(`"${name}" is already taken. Pick another with --as.`);
|
|
@@ -6606,7 +6740,7 @@ async function chooseProxyName(slug, asOpt, teamId, interactive) {
|
|
|
6606
6740
|
}
|
|
6607
6741
|
if (!interactive) return suggested;
|
|
6608
6742
|
const { default: inquirer3 } = await import("inquirer");
|
|
6609
|
-
console.log(` ${
|
|
6743
|
+
console.log(` ${import_chalk31.default.dim("proxy")} ${slug} \u2192 ${import_chalk31.default.bold(suggested)} ${import_chalk31.default.dim("[enter to accept, or type a name]")}`);
|
|
6610
6744
|
for (; ; ) {
|
|
6611
6745
|
const { raw } = await inquirer3.prompt([{
|
|
6612
6746
|
type: "input",
|
|
@@ -6617,20 +6751,20 @@ async function chooseProxyName(slug, asOpt, teamId, interactive) {
|
|
|
6617
6751
|
}]);
|
|
6618
6752
|
const name = normalizeName3(raw);
|
|
6619
6753
|
if (name !== String(raw).trim()) {
|
|
6620
|
-
console.log(
|
|
6754
|
+
console.log(import_chalk31.default.yellow(` \u2192 using ${import_chalk31.default.bold(name)} (lowercase letters and digits only)`));
|
|
6621
6755
|
}
|
|
6622
6756
|
if (name.length < 3) {
|
|
6623
|
-
console.log(
|
|
6757
|
+
console.log(import_chalk31.default.yellow(" Name must be at least 3 characters.\n"));
|
|
6624
6758
|
continue;
|
|
6625
6759
|
}
|
|
6626
6760
|
const free = await nameIsFree(name, teamId);
|
|
6627
6761
|
if (free === false) {
|
|
6628
|
-
console.log(
|
|
6762
|
+
console.log(import_chalk31.default.yellow(` "${name}" is taken. Try another.
|
|
6629
6763
|
`));
|
|
6630
6764
|
continue;
|
|
6631
6765
|
}
|
|
6632
|
-
if (free === null) console.log(
|
|
6633
|
-
console.log(` ${
|
|
6766
|
+
if (free === null) console.log(import_chalk31.default.dim(" (could not verify availability; continuing)"));
|
|
6767
|
+
console.log(` ${import_chalk31.default.cyan("\u2192")} ${import_chalk31.default.bold(`https://${name}.abz.run`)}`);
|
|
6634
6768
|
return name;
|
|
6635
6769
|
}
|
|
6636
6770
|
}
|
|
@@ -6648,20 +6782,20 @@ function printSummary(recipe, project, tenant2, reuseTenant = false) {
|
|
|
6648
6782
|
const keyTypes = recipe.auth?.key_types?.length ?? 0;
|
|
6649
6783
|
const questions = reuseTenant ? 0 : recipe.questions?.length ?? 0;
|
|
6650
6784
|
const row = (label3, value, note) => {
|
|
6651
|
-
console.log(` ${
|
|
6785
|
+
console.log(` ${import_chalk31.default.dim(label3.padEnd(21))}${value}${note ? import_chalk31.default.dim(` ${note}`) : ""}`);
|
|
6652
6786
|
};
|
|
6653
6787
|
console.log();
|
|
6654
|
-
console.log(
|
|
6788
|
+
console.log(import_chalk31.default.bold(" This will:"));
|
|
6655
6789
|
console.log();
|
|
6656
|
-
row("create a proxy",
|
|
6657
|
-
row("for its users",
|
|
6790
|
+
row("create a proxy", import_chalk31.default.bold(project), `at https://${project}.abz.run`);
|
|
6791
|
+
row("for its users", import_chalk31.default.bold(tenant2), reuseTenant ? "(one you already have)" : "(a new tenant)");
|
|
6658
6792
|
if (hosts.length) row("sending requests to", hosts.join(", "));
|
|
6659
6793
|
row("and set up", describeCreates(keyTypes, routes, recipe.settings.mcp_enabled === true, false));
|
|
6660
6794
|
row("asking you for", questions ? `${questions} value${questions === 1 ? "" : "s"}` : "nothing");
|
|
6661
6795
|
if (reuseTenant) {
|
|
6662
6796
|
console.log();
|
|
6663
|
-
console.log(
|
|
6664
|
-
console.log(
|
|
6797
|
+
console.log(import_chalk31.default.dim(` ${tenant2} is used exactly as it is \u2014 its existing login stays, and this`));
|
|
6798
|
+
console.log(import_chalk31.default.dim(" recipe's own login setup is not applied."));
|
|
6665
6799
|
}
|
|
6666
6800
|
console.log();
|
|
6667
6801
|
}
|
|
@@ -6670,11 +6804,11 @@ function declineAll(items) {
|
|
|
6670
6804
|
const upstreams = items.filter((i) => i.kind === "upstream");
|
|
6671
6805
|
console.log();
|
|
6672
6806
|
for (const u of upstreams) {
|
|
6673
|
-
console.log(
|
|
6807
|
+
console.log(import_chalk31.default.yellow(` --yes: this proxy sends every request to ${import_chalk31.default.bold(u.value)}.`));
|
|
6674
6808
|
}
|
|
6675
6809
|
if (skippable.length) {
|
|
6676
|
-
console.log(
|
|
6677
|
-
for (const i of skippable) console.log(
|
|
6810
|
+
console.log(import_chalk31.default.yellow(` --yes: installing without ${skippable.length} setting${skippable.length === 1 ? "" : "s"} that need consent.`));
|
|
6811
|
+
for (const i of skippable) console.log(import_chalk31.default.dim(` skipped ${i.kind} ${i.value}`));
|
|
6678
6812
|
}
|
|
6679
6813
|
return new Set(skippable.map((i) => i.kind));
|
|
6680
6814
|
}
|
|
@@ -6692,14 +6826,14 @@ async function askConsent(items, interactive) {
|
|
|
6692
6826
|
const count = items.length;
|
|
6693
6827
|
const word = ["", "it", "both", "all three", "all four", "all five", "all six"][count] ?? `all ${count}`;
|
|
6694
6828
|
console.log();
|
|
6695
|
-
console.log(
|
|
6829
|
+
console.log(import_chalk31.default.yellow("\u26A0 This recipe changes who can reach your proxy, what it trusts, and what it can cost."));
|
|
6696
6830
|
console.log();
|
|
6697
6831
|
for (const item of items) {
|
|
6698
|
-
console.log(` ${
|
|
6699
|
-
for (const line of wrapText(item.why, 62)) console.log(` ${" ".repeat(16)} ${
|
|
6832
|
+
console.log(` ${import_chalk31.default.bold(item.kind.padEnd(16))} ${item.value}`);
|
|
6833
|
+
for (const line of wrapText(item.why, 62)) console.log(` ${" ".repeat(16)} ${import_chalk31.default.dim(line)}`);
|
|
6700
6834
|
}
|
|
6701
6835
|
console.log();
|
|
6702
|
-
console.log(`Type "${
|
|
6836
|
+
console.log(`Type "${import_chalk31.default.bold("yes")}" to accept ${word}.`);
|
|
6703
6837
|
console.log("Press enter to install the recipe without them.");
|
|
6704
6838
|
let typed = "";
|
|
6705
6839
|
if (interactive) {
|
|
@@ -6711,7 +6845,7 @@ async function askConsent(items, interactive) {
|
|
|
6711
6845
|
for (const item of items) {
|
|
6712
6846
|
declined.add(item.kind === "transform" ? `transform:${item.value}` : `kind:${item.kind}`);
|
|
6713
6847
|
}
|
|
6714
|
-
console.log(
|
|
6848
|
+
console.log(import_chalk31.default.dim(` Installing without ${count} setting${count === 1 ? "" : "s"} \u2014 everything else is applied.`));
|
|
6715
6849
|
return declined;
|
|
6716
6850
|
}
|
|
6717
6851
|
async function askQuestions(questions, ctx, interactive) {
|
|
@@ -6724,13 +6858,13 @@ async function askQuestions(questions, ctx, interactive) {
|
|
|
6724
6858
|
const BOX = 64;
|
|
6725
6859
|
const title = "\u2500\u2500 from the publisher ";
|
|
6726
6860
|
console.log();
|
|
6727
|
-
console.log(` ${
|
|
6728
|
-
for (const line of fillContext(q.before, ctx).split("\n")) console.log(` ${
|
|
6729
|
-
console.log(` ${
|
|
6861
|
+
console.log(` ${import_chalk31.default.dim(title + "\u2500".repeat(BOX - title.length))}`);
|
|
6862
|
+
for (const line of fillContext(q.before, ctx).split("\n")) console.log(` ${import_chalk31.default.dim("\u2502")} ${line}`);
|
|
6863
|
+
console.log(` ${import_chalk31.default.dim("\u2500".repeat(BOX))}`);
|
|
6730
6864
|
}
|
|
6731
6865
|
if (fromEnv !== void 0 && fromEnv !== "") {
|
|
6732
6866
|
answers[q.id] = fromEnv;
|
|
6733
|
-
console.log(` ${q.prompt}: ${
|
|
6867
|
+
console.log(` ${q.prompt}: ${import_chalk31.default.dim(`(from ${envName})`)}`);
|
|
6734
6868
|
continue;
|
|
6735
6869
|
}
|
|
6736
6870
|
if (!interactive) {
|
|
@@ -6740,7 +6874,7 @@ async function askQuestions(questions, ctx, interactive) {
|
|
|
6740
6874
|
);
|
|
6741
6875
|
}
|
|
6742
6876
|
const { default: inquirer3 } = await import("inquirer");
|
|
6743
|
-
if (q.example && !q.secret) console.log(
|
|
6877
|
+
if (q.example && !q.secret) console.log(import_chalk31.default.dim(` e.g. ${q.example}`));
|
|
6744
6878
|
const { value } = await inquirer3.prompt([{
|
|
6745
6879
|
// `secret: true` masks the input — the Google client secret is typed once,
|
|
6746
6880
|
// goes to provider creation, and is never echoed or stored.
|
|
@@ -6774,30 +6908,30 @@ async function confirmReinstall(recipe, project, tenant2, interactive) {
|
|
|
6774
6908
|
const tables = recipe.transformations?.mapping_tables?.length ?? 0;
|
|
6775
6909
|
const routes = countRoutes(recipe.openapi);
|
|
6776
6910
|
const keyTypes = recipe.auth?.key_types?.length ?? 0;
|
|
6777
|
-
console.log(`This installs ${
|
|
6911
|
+
console.log(`This installs ${import_chalk31.default.bold(`${recipe.name}@${recipe.revision}`)} over ${import_chalk31.default.bold(project)}.`);
|
|
6778
6912
|
console.log();
|
|
6779
|
-
console.log(` ${
|
|
6913
|
+
console.log(` ${import_chalk31.default.dim("settings ".padEnd(16))}replaced`);
|
|
6780
6914
|
if (rules || tables) {
|
|
6781
|
-
console.log(` ${
|
|
6915
|
+
console.log(` ${import_chalk31.default.dim("transforms".padEnd(16))}${rules} rule${rules === 1 ? "" : "s"}${tables ? ` and ${tables} mapping table${tables === 1 ? "" : "s"}` : ""} replaced \u2014 your edits to them are lost`);
|
|
6782
6916
|
}
|
|
6783
6917
|
if (routes) {
|
|
6784
|
-
console.log(` ${
|
|
6918
|
+
console.log(` ${import_chalk31.default.dim("api spec ".padEnd(16))}replaced, ${routes} routes regenerated${recipe.settings.mcp_enabled === true ? ", MCP rebuilt" : ""}`);
|
|
6785
6919
|
}
|
|
6786
6920
|
if (keyTypes) {
|
|
6787
|
-
console.log(` ${
|
|
6921
|
+
console.log(` ${import_chalk31.default.dim("key types ".padEnd(16))}${keyTypes} added if missing; existing types left alone`);
|
|
6788
6922
|
}
|
|
6789
6923
|
console.log();
|
|
6790
|
-
console.log(` ${
|
|
6924
|
+
console.log(` ${import_chalk31.default.dim("unchanged ".padEnd(16))}your API keys, your proxy URL, your users,`);
|
|
6791
6925
|
console.log(` ${" ".repeat(16)}and any tenant other than ${tenant2}`);
|
|
6792
6926
|
console.log();
|
|
6793
|
-
console.log(
|
|
6927
|
+
console.log(import_chalk31.default.yellow("This cannot be undone."));
|
|
6794
6928
|
if (!interactive) {
|
|
6795
6929
|
throw new Error("Reinstall needs a typed confirmation and there is no terminal to ask on.");
|
|
6796
6930
|
}
|
|
6797
6931
|
const { default: inquirer3 } = await import("inquirer");
|
|
6798
6932
|
const { typed } = await inquirer3.prompt([{ type: "input", name: "typed", message: `Type the proxy name (${project}) to continue:` }]);
|
|
6799
6933
|
if (String(typed ?? "").trim() !== project) {
|
|
6800
|
-
console.log(
|
|
6934
|
+
console.log(import_chalk31.default.yellow("Cancelled \u2014 nothing was changed."));
|
|
6801
6935
|
process.exit(0);
|
|
6802
6936
|
}
|
|
6803
6937
|
}
|
|
@@ -6805,7 +6939,7 @@ function requireCallerForInstall() {
|
|
|
6805
6939
|
try {
|
|
6806
6940
|
return requireCaller();
|
|
6807
6941
|
} catch {
|
|
6808
|
-
console.error(
|
|
6942
|
+
console.error(import_chalk31.default.red(
|
|
6809
6943
|
"Installing writes a proxy into an account, so it needs a credential.\n Run `apiblaze login`, or `apiblaze create` first (an anonymous workspace works too)."
|
|
6810
6944
|
));
|
|
6811
6945
|
process.exit(1);
|
|
@@ -6841,7 +6975,7 @@ async function chooseTeam(caller, optTeam, interactive) {
|
|
|
6841
6975
|
message: " which team should own this proxy?",
|
|
6842
6976
|
default: active.teamId,
|
|
6843
6977
|
choices: teams.map((t) => ({
|
|
6844
|
-
name: t.teamId === active.teamId ? `${t.name} ${
|
|
6978
|
+
name: t.teamId === active.teamId ? `${t.name} ${import_chalk31.default.dim("(active)")}` : t.name,
|
|
6845
6979
|
value: t.teamId
|
|
6846
6980
|
}))
|
|
6847
6981
|
}]);
|
|
@@ -6869,10 +7003,10 @@ async function chooseTenant(caller, project, teamId, optTenant, interactive) {
|
|
|
6869
7003
|
message: " where should this proxy's users live?",
|
|
6870
7004
|
default: "__new__",
|
|
6871
7005
|
choices: [
|
|
6872
|
-
{ name: `create ${fresh} ${
|
|
6873
|
-
new inquirer3.Separator(
|
|
7006
|
+
{ name: `create ${fresh} ${import_chalk31.default.dim("(a fresh tenant, set up by the recipe)")}`, value: "__new__" },
|
|
7007
|
+
new inquirer3.Separator(import_chalk31.default.dim(" \u2014 or reuse one you already have \u2014")),
|
|
6874
7008
|
...owned.map((t2) => ({
|
|
6875
|
-
name: `${t2} ${
|
|
7009
|
+
name: `${t2} ${import_chalk31.default.dim("(existing \u2014 its own login is kept)")}`,
|
|
6876
7010
|
value: t2
|
|
6877
7011
|
}))
|
|
6878
7012
|
]
|
|
@@ -6899,7 +7033,7 @@ async function teamTenants(caller, teamId) {
|
|
|
6899
7033
|
}
|
|
6900
7034
|
|
|
6901
7035
|
// src/commands/recipe-publish.ts
|
|
6902
|
-
var
|
|
7036
|
+
var import_chalk32 = __toESM(require("chalk"));
|
|
6903
7037
|
var import_ora11 = __toESM(require("ora"));
|
|
6904
7038
|
init_caller();
|
|
6905
7039
|
init_auth();
|
|
@@ -6909,15 +7043,15 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
6909
7043
|
try {
|
|
6910
7044
|
resolved = resolveRecipeName(opts.as, creds?.githubHandle, normalizeName3(projectArg));
|
|
6911
7045
|
} catch (err) {
|
|
6912
|
-
console.error(
|
|
7046
|
+
console.error(import_chalk32.default.red(err instanceof Error ? err.message : String(err)));
|
|
6913
7047
|
process.exitCode = 1;
|
|
6914
7048
|
return;
|
|
6915
7049
|
}
|
|
6916
7050
|
const ref = resolved.ref;
|
|
6917
7051
|
if (resolved.derivedHandle) {
|
|
6918
|
-
console.log(
|
|
7052
|
+
console.log(import_chalk32.default.dim(` publishing as ${import_chalk32.default.bold(ref.name)}`));
|
|
6919
7053
|
if (resolved.normalizedFrom) {
|
|
6920
|
-
console.log(
|
|
7054
|
+
console.log(import_chalk32.default.dim(` (your GitHub login is ${resolved.normalizedFrom}; apiblaze names are letters and digits only)`));
|
|
6921
7055
|
}
|
|
6922
7056
|
}
|
|
6923
7057
|
const interactive = !!process.stdin.isTTY && !opts.json;
|
|
@@ -6936,7 +7070,7 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
6936
7070
|
let tenant2 = opts.tenant;
|
|
6937
7071
|
if (!prep.tenant_used && prep.tenants.length > 1) {
|
|
6938
7072
|
if (!interactive) {
|
|
6939
|
-
console.error(
|
|
7073
|
+
console.error(import_chalk32.default.red(
|
|
6940
7074
|
`${proj2.projectId} has ${prep.tenants.length} tenants (${prep.tenants.join(", ")}). Pass --tenant <slug> to say which auth setup the recipe carries.`
|
|
6941
7075
|
));
|
|
6942
7076
|
process.exit(1);
|
|
@@ -6952,7 +7086,7 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
6952
7086
|
prep = await prepare(caller, proj2.projectId, proj2.apiVersion, ref.name, tenant2);
|
|
6953
7087
|
}
|
|
6954
7088
|
if (!prep.name_available) {
|
|
6955
|
-
console.error(
|
|
7089
|
+
console.error(import_chalk32.default.red(`${ref.name} belongs to another team, so you cannot publish a revision of it.`));
|
|
6956
7090
|
process.exit(1);
|
|
6957
7091
|
}
|
|
6958
7092
|
if (prep.envelope_violations.length) {
|
|
@@ -6962,13 +7096,13 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
6962
7096
|
if (prep.dropped.length) {
|
|
6963
7097
|
console.log();
|
|
6964
7098
|
console.log(`${prep.dropped.length} setting${prep.dropped.length === 1 ? " was" : "s were"} not included, because they are not on the publish list:`);
|
|
6965
|
-
for (const d of prep.dropped) console.log(
|
|
7099
|
+
for (const d of prep.dropped) console.log(import_chalk32.default.dim(` ${d}`));
|
|
6966
7100
|
if (prep.hidden_tables_excluded) {
|
|
6967
|
-
console.log(
|
|
7101
|
+
console.log(import_chalk32.default.dim(` (${prep.hidden_tables_excluded} hidden mapping table${prep.hidden_tables_excluded === 1 ? "" : "s"} excluded \u2014 those values belong to your consumers.)`));
|
|
6968
7102
|
}
|
|
6969
7103
|
console.log();
|
|
6970
7104
|
if (!opts.yes && !await confirm(" continue without them?", interactive)) {
|
|
6971
|
-
console.log(
|
|
7105
|
+
console.log(import_chalk32.default.yellow("Cancelled."));
|
|
6972
7106
|
return;
|
|
6973
7107
|
}
|
|
6974
7108
|
}
|
|
@@ -6981,12 +7115,12 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
6981
7115
|
console.log();
|
|
6982
7116
|
for (const f of prep.findings) printFinding(f);
|
|
6983
7117
|
console.log();
|
|
6984
|
-
console.error(
|
|
7118
|
+
console.error(import_chalk32.default.red("--yes cannot accept scanner findings. Fix the value in the proxy, or publish interactively and decide."));
|
|
6985
7119
|
process.exit(1);
|
|
6986
7120
|
}
|
|
6987
7121
|
if (!interactive) {
|
|
6988
7122
|
for (const f of prep.findings) printFinding(f);
|
|
6989
|
-
console.error(
|
|
7123
|
+
console.error(import_chalk32.default.red("\nThese need a decision and there is no terminal to ask on."));
|
|
6990
7124
|
process.exit(1);
|
|
6991
7125
|
}
|
|
6992
7126
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -7007,10 +7141,10 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
7007
7141
|
if (verdict === "ask") promotions.push(await askPromotion(f.path));
|
|
7008
7142
|
}
|
|
7009
7143
|
}
|
|
7010
|
-
console.log(
|
|
7144
|
+
console.log(import_chalk32.default.dim(`we cannot judge the other ${prep.unjudged_count} values. run \`apiblaze show ${ref.name}\` after publishing to read the whole recipe.`));
|
|
7011
7145
|
const totalQuestions = prep.question_ids.length + promotions.length;
|
|
7012
7146
|
if (totalQuestions > 5) {
|
|
7013
|
-
console.log(
|
|
7147
|
+
console.log(import_chalk32.default.yellow(`
|
|
7014
7148
|
\u26A0 installers will have to supply ${totalQuestions} values before this works.`));
|
|
7015
7149
|
}
|
|
7016
7150
|
const visibility = opts.private ? "private" : "public";
|
|
@@ -7018,11 +7152,11 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
7018
7152
|
if (visibility === "public" && prep.spec_will_become_public) {
|
|
7019
7153
|
console.log();
|
|
7020
7154
|
console.log("Publishing publicly also makes this API's spec readable at");
|
|
7021
|
-
console.log(` ${
|
|
7155
|
+
console.log(` ${import_chalk32.default.bold(`https://${proj2.projectId}.abz.run/${proj2.apiVersion}/openapi.json`)}`);
|
|
7022
7156
|
console.log("It is currently private.");
|
|
7023
7157
|
confirmSpecPublic = opts.yes ? true : await confirm("Continue?", interactive);
|
|
7024
7158
|
if (!confirmSpecPublic) {
|
|
7025
|
-
console.log(
|
|
7159
|
+
console.log(import_chalk32.default.yellow("Cancelled \u2014 nothing was published."));
|
|
7026
7160
|
return;
|
|
7027
7161
|
}
|
|
7028
7162
|
}
|
|
@@ -7048,7 +7182,7 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
7048
7182
|
},
|
|
7049
7183
|
summary: `Publish ${proj2.projectId} as ${ref.name} (${visibility})`
|
|
7050
7184
|
});
|
|
7051
|
-
spin2?.succeed(`Published ${
|
|
7185
|
+
spin2?.succeed(`Published ${import_chalk32.default.bold(`${out.name}@${out.revision}`)} (${out.visibility}).`);
|
|
7052
7186
|
} catch (err) {
|
|
7053
7187
|
spin2?.fail("Publish failed.");
|
|
7054
7188
|
throw err;
|
|
@@ -7057,15 +7191,15 @@ async function runRecipePublish(projectArg, opts) {
|
|
|
7057
7191
|
console.log(JSON.stringify(out));
|
|
7058
7192
|
return;
|
|
7059
7193
|
}
|
|
7060
|
-
console.log(` ${
|
|
7061
|
-
console.log(` ${
|
|
7194
|
+
console.log(` ${import_chalk32.default.dim("size ")} ${(out.size_bytes / 1024).toFixed(1)} KB`);
|
|
7195
|
+
console.log(` ${import_chalk32.default.dim("checksum")} ${out.sha256.slice(0, 16)}\u2026`);
|
|
7062
7196
|
console.log();
|
|
7063
7197
|
if (out.visibility === "public") {
|
|
7064
|
-
console.log(
|
|
7198
|
+
console.log(import_chalk32.default.dim(` Anyone can now run: ${import_chalk32.default.cyan(`npx apiblaze install ${out.name}`)}`));
|
|
7065
7199
|
} else {
|
|
7066
|
-
console.log(
|
|
7200
|
+
console.log(import_chalk32.default.dim(" Private \u2014 only members of this team can see or install it."));
|
|
7067
7201
|
}
|
|
7068
|
-
console.log(
|
|
7202
|
+
console.log(import_chalk32.default.dim(` Pull it back with: ${import_chalk32.default.cyan(`npx apiblaze withdraw ${out.name}@${out.revision}`)}`));
|
|
7069
7203
|
console.log();
|
|
7070
7204
|
}
|
|
7071
7205
|
async function prepare(caller, projectId, apiVersion, name, tenant2) {
|
|
@@ -7078,23 +7212,23 @@ async function prepare(caller, projectId, apiVersion, name, tenant2) {
|
|
|
7078
7212
|
}
|
|
7079
7213
|
function printFinding(f) {
|
|
7080
7214
|
const preview = (f.preview ?? "").replace(/\s+/g, " ").trim();
|
|
7081
|
-
console.log(` ${
|
|
7082
|
-
console.log(` ${
|
|
7215
|
+
console.log(` ${import_chalk32.default.bold(f.path)}`);
|
|
7216
|
+
console.log(` ${import_chalk32.default.yellow(preview.padEnd(38))}${import_chalk32.default.dim(f.why)}`);
|
|
7083
7217
|
}
|
|
7084
7218
|
function printEnvelopeViolations(violations) {
|
|
7085
7219
|
console.log();
|
|
7086
|
-
console.error(
|
|
7220
|
+
console.error(import_chalk32.default.red("This proxy has transform rules a recipe cannot carry."));
|
|
7087
7221
|
console.log();
|
|
7088
7222
|
for (const v of violations) {
|
|
7089
|
-
console.log(` ${
|
|
7223
|
+
console.log(` ${import_chalk32.default.bold(v.rule)} ${import_chalk32.default.dim(`(${v.kind}s ${v.field})`)}`);
|
|
7090
7224
|
console.log(` ${v.why}`);
|
|
7091
7225
|
}
|
|
7092
7226
|
console.log();
|
|
7093
7227
|
console.log("A recipe runs in a stranger's account, after apiblaze has attached their end user's");
|
|
7094
7228
|
console.log("real third-party token, so two rules are absolute:");
|
|
7095
|
-
console.log(` ${
|
|
7229
|
+
console.log(` ${import_chalk32.default.dim("\u2022")} a rule may never READ Authorization, Cookie, or the third-party token headers \u2014`);
|
|
7096
7230
|
console.log(" those hold a live credential that works at the provider without apiblaze;");
|
|
7097
|
-
console.log(` ${
|
|
7231
|
+
console.log(` ${import_chalk32.default.dim("\u2022")} a rule may never WRITE an identity header (x-end-user-id and friends) \u2014`);
|
|
7098
7232
|
console.log(" those tell the installer's own backend who is calling.");
|
|
7099
7233
|
console.log();
|
|
7100
7234
|
console.log("Writing Authorization from a question or a fixed value is fine \u2014 that is the");
|
|
@@ -7112,7 +7246,7 @@ async function askPromotion(path9) {
|
|
|
7112
7246
|
{ type: "input", name: "id", message: " id:", default: suggestedId }
|
|
7113
7247
|
]);
|
|
7114
7248
|
const id = String(answers.id || suggestedId).toLowerCase().replace(/[^a-z0-9_]/g, "_");
|
|
7115
|
-
console.log(
|
|
7249
|
+
console.log(import_chalk32.default.dim(` \u2192 replaced with {{${id}}}`));
|
|
7116
7250
|
return {
|
|
7117
7251
|
path: path9,
|
|
7118
7252
|
id,
|
|
@@ -7131,7 +7265,7 @@ async function confirm(message, interactive) {
|
|
|
7131
7265
|
async function runRecipeWithdraw(nameArg, opts) {
|
|
7132
7266
|
const ref = parseRecipeRef(nameArg);
|
|
7133
7267
|
if (ref.revision === void 0) {
|
|
7134
|
-
console.error(
|
|
7268
|
+
console.error(import_chalk32.default.red(`Name the revision to withdraw, e.g. ${nameArg}@3. Revisions are withdrawn one at a time.`));
|
|
7135
7269
|
process.exit(1);
|
|
7136
7270
|
}
|
|
7137
7271
|
const interactive = !!process.stdin.isTTY && !opts.json;
|
|
@@ -7151,11 +7285,11 @@ async function runRecipeWithdraw(nameArg, opts) {
|
|
|
7151
7285
|
const { default: inquirer3 } = await import("inquirer");
|
|
7152
7286
|
const { typed } = await inquirer3.prompt([{ type: "input", name: "typed", message: `type the recipe name to confirm (${ref.name}):` }]);
|
|
7153
7287
|
if (String(typed ?? "").trim() !== ref.name) {
|
|
7154
|
-
console.log(
|
|
7288
|
+
console.log(import_chalk32.default.yellow("Cancelled \u2014 nothing was withdrawn."));
|
|
7155
7289
|
return;
|
|
7156
7290
|
}
|
|
7157
7291
|
} else {
|
|
7158
|
-
console.error(
|
|
7292
|
+
console.error(import_chalk32.default.red("Withdrawing needs a typed confirmation and there is no terminal to ask on."));
|
|
7159
7293
|
process.exit(1);
|
|
7160
7294
|
}
|
|
7161
7295
|
const spinner = !opts.json ? (0, import_ora11.default)("Withdrawing...").start() : null;
|
|
@@ -7184,33 +7318,33 @@ async function runRecipeWithdraw(nameArg, opts) {
|
|
|
7184
7318
|
}
|
|
7185
7319
|
|
|
7186
7320
|
// src/commands/logs.ts
|
|
7187
|
-
var
|
|
7321
|
+
var import_chalk34 = __toESM(require("chalk"));
|
|
7188
7322
|
init_admin();
|
|
7189
7323
|
init_auth();
|
|
7190
7324
|
init_resolve();
|
|
7191
7325
|
|
|
7192
7326
|
// src/lib/log-view.ts
|
|
7193
|
-
var
|
|
7327
|
+
var import_chalk33 = __toESM(require("chalk"));
|
|
7194
7328
|
var readline2 = __toESM(require("readline"));
|
|
7195
7329
|
function statusColor(status) {
|
|
7196
|
-
if (status < 300) return
|
|
7197
|
-
if (status < 400) return
|
|
7198
|
-
if (status < 500) return
|
|
7199
|
-
return
|
|
7330
|
+
if (status < 300) return import_chalk33.default.green;
|
|
7331
|
+
if (status < 400) return import_chalk33.default.blue;
|
|
7332
|
+
if (status < 500) return import_chalk33.default.yellow;
|
|
7333
|
+
return import_chalk33.default.red;
|
|
7200
7334
|
}
|
|
7201
7335
|
function methodColor(method) {
|
|
7202
7336
|
switch ((method || "").toUpperCase()) {
|
|
7203
7337
|
case "GET":
|
|
7204
|
-
return
|
|
7338
|
+
return import_chalk33.default.green;
|
|
7205
7339
|
case "POST":
|
|
7206
|
-
return
|
|
7340
|
+
return import_chalk33.default.blue;
|
|
7207
7341
|
case "PUT":
|
|
7208
7342
|
case "PATCH":
|
|
7209
|
-
return
|
|
7343
|
+
return import_chalk33.default.yellow;
|
|
7210
7344
|
case "DELETE":
|
|
7211
|
-
return
|
|
7345
|
+
return import_chalk33.default.red;
|
|
7212
7346
|
default:
|
|
7213
|
-
return
|
|
7347
|
+
return import_chalk33.default.white;
|
|
7214
7348
|
}
|
|
7215
7349
|
}
|
|
7216
7350
|
function clock(ts) {
|
|
@@ -7222,12 +7356,12 @@ function routeCell(route) {
|
|
|
7222
7356
|
return (r.length > ROUTE_W ? `\u2026${r.slice(-(ROUTE_W - 1))}` : r).padEnd(ROUTE_W);
|
|
7223
7357
|
}
|
|
7224
7358
|
function formatRow(r) {
|
|
7225
|
-
const time =
|
|
7359
|
+
const time = import_chalk33.default.dim(clock(r.ts));
|
|
7226
7360
|
const method = methodColor(r.method)(String(r.method || "\u2014").padEnd(6));
|
|
7227
7361
|
const route = routeCell(String(r.route || "\u2014"));
|
|
7228
7362
|
const status = statusColor(r.status)(String(r.status ?? "\u2014").padStart(3));
|
|
7229
|
-
const ms =
|
|
7230
|
-
const step = r.error_step ?
|
|
7363
|
+
const ms = import_chalk33.default.dim(`${r.duration_ms}ms`.padStart(8));
|
|
7364
|
+
const step = r.error_step ? import_chalk33.default.dim(` ${r.error_step}`) : "";
|
|
7231
7365
|
return `${time} ${method} ${route} ${status} ${ms}${step}`;
|
|
7232
7366
|
}
|
|
7233
7367
|
function printRow(r, json) {
|
|
@@ -7242,15 +7376,15 @@ var WindowNotices = class {
|
|
|
7242
7376
|
note(res) {
|
|
7243
7377
|
if (res.history_unavailable && !this.saidUnavailable) {
|
|
7244
7378
|
this.saidUnavailable = true;
|
|
7245
|
-
console.error(
|
|
7379
|
+
console.error(import_chalk33.default.yellow("\u26A0 log history is unreachable right now \u2014 showing the live buffer only, older requests exist but cannot be read."));
|
|
7246
7380
|
}
|
|
7247
7381
|
if ((res.history_markers?.length ?? 0) > 0 && !this.saidGap) {
|
|
7248
7382
|
this.saidGap = true;
|
|
7249
|
-
console.error(
|
|
7383
|
+
console.error(import_chalk33.default.yellow("\u26A0 this range includes a volume-ceiling gap \u2014 some rows were dropped at intake and are gone; counts are incomplete."));
|
|
7250
7384
|
}
|
|
7251
7385
|
if ((res.dropped_this_hour ?? 0) > 0 && !this.saidDropped) {
|
|
7252
7386
|
this.saidDropped = true;
|
|
7253
|
-
console.error(
|
|
7387
|
+
console.error(import_chalk33.default.yellow(`\u26A0 volume ceiling \u2014 ${res.dropped_this_hour} rows dropped this hour; errors keep logging.`));
|
|
7254
7388
|
}
|
|
7255
7389
|
}
|
|
7256
7390
|
};
|
|
@@ -7309,13 +7443,13 @@ async function runTailSession(opts) {
|
|
|
7309
7443
|
if (!held.length && !heldRowsDropped && !heldNotesDropped) return;
|
|
7310
7444
|
const rows = held.filter((h) => h.kind === "row").length;
|
|
7311
7445
|
const total = rows + heldRowsDropped;
|
|
7312
|
-
if (total) console.log(
|
|
7446
|
+
if (total) console.log(import_chalk33.default.dim(`\u2500\u2500\u2500 ${total} request${total === 1 ? "" : "s"} arrived while paused \u2500\u2500\u2500`));
|
|
7313
7447
|
for (const h of held) {
|
|
7314
7448
|
if (h.kind === "row") printRow(h.row, opts.json);
|
|
7315
7449
|
else console.error(h.msg);
|
|
7316
7450
|
}
|
|
7317
7451
|
if (heldRowsDropped || heldNotesDropped) {
|
|
7318
|
-
console.log(
|
|
7452
|
+
console.log(import_chalk33.default.dim(`\u2500\u2500\u2500 ${heldRowsDropped} older one${heldRowsDropped === 1 ? "" : "s"} not shown (pause buffer full) \u2014 browse them with \`logs list\` \u2500\u2500\u2500`));
|
|
7319
7453
|
}
|
|
7320
7454
|
held.length = 0;
|
|
7321
7455
|
heldRowsDropped = 0;
|
|
@@ -7329,7 +7463,7 @@ async function runTailSession(opts) {
|
|
|
7329
7463
|
activeSocket?.close();
|
|
7330
7464
|
} catch {
|
|
7331
7465
|
}
|
|
7332
|
-
if (!opts.json) console.log(
|
|
7466
|
+
if (!opts.json) console.log(import_chalk33.default.dim("\nStopped."));
|
|
7333
7467
|
process.exit(0);
|
|
7334
7468
|
}
|
|
7335
7469
|
function onKeypress(_s, key) {
|
|
@@ -7357,17 +7491,17 @@ async function runTailSession(opts) {
|
|
|
7357
7491
|
async function openInspector() {
|
|
7358
7492
|
if (paused) return;
|
|
7359
7493
|
if (recent.length === 0) {
|
|
7360
|
-
console.log(
|
|
7494
|
+
console.log(import_chalk33.default.dim(" nothing captured yet \u2014 waiting for a request\u2026"));
|
|
7361
7495
|
return;
|
|
7362
7496
|
}
|
|
7363
7497
|
paused = true;
|
|
7364
7498
|
unbindKeys();
|
|
7365
7499
|
try {
|
|
7366
7500
|
const { default: inquirer3 } = await import("inquirer");
|
|
7367
|
-
console.log(
|
|
7501
|
+
console.log(import_chalk33.default.dim("\n\u2500\u2500\u2500 paused \xB7 still capturing in the background \u2500\u2500\u2500"));
|
|
7368
7502
|
for (; ; ) {
|
|
7369
7503
|
const choices = recent.slice(-TAIL_INSPECT_CHOICES).reverse().map((r) => ({ name: formatRow(r), value: r.request_id }));
|
|
7370
|
-
choices.push({ name:
|
|
7504
|
+
choices.push({ name: import_chalk33.default.dim("\u2039resume tail\u203A"), value: "__resume__" });
|
|
7371
7505
|
const { picked } = await inquirer3.prompt([{
|
|
7372
7506
|
type: "list",
|
|
7373
7507
|
name: "picked",
|
|
@@ -7378,12 +7512,12 @@ async function runTailSession(opts) {
|
|
|
7378
7512
|
if (picked === "__resume__") break;
|
|
7379
7513
|
const row = recent.find((r) => r.request_id === picked);
|
|
7380
7514
|
if (row) printDetail(row, opts.detail);
|
|
7381
|
-
else console.log(
|
|
7515
|
+
else console.log(import_chalk33.default.dim(" that request has scrolled out of the tail buffer \u2014 find it with `logs list`.\n"));
|
|
7382
7516
|
}
|
|
7383
7517
|
} finally {
|
|
7384
7518
|
paused = false;
|
|
7385
7519
|
flushHeld();
|
|
7386
|
-
console.log(
|
|
7520
|
+
console.log(import_chalk33.default.dim("\u2500\u2500\u2500 resumed \u2500\u2500\u2500"));
|
|
7387
7521
|
bindKeys();
|
|
7388
7522
|
}
|
|
7389
7523
|
}
|
|
@@ -7393,12 +7527,12 @@ async function runTailSession(opts) {
|
|
|
7393
7527
|
if (reconnects >= MAX_RECONNECTS) {
|
|
7394
7528
|
paused = false;
|
|
7395
7529
|
flushHeld();
|
|
7396
|
-
console.error(
|
|
7530
|
+
console.error(import_chalk33.default.red(`Connection lost \u2014 giving up after repeated reconnects${lastFailure ? ` (last error: ${lastFailure})` : ""}.`));
|
|
7397
7531
|
process.exit(1);
|
|
7398
7532
|
}
|
|
7399
7533
|
const delay = Math.min(1e3 * 2 ** reconnects, 15e3);
|
|
7400
7534
|
reconnects++;
|
|
7401
|
-
diag(
|
|
7535
|
+
diag(import_chalk33.default.dim(`disconnected${lastFailure ? ` (${lastFailure})` : ""} \u2014 reconnecting in ${Math.round(delay / 1e3)}s\u2026`));
|
|
7402
7536
|
setTimeout(() => {
|
|
7403
7537
|
if (!closed) void connect();
|
|
7404
7538
|
}, delay);
|
|
@@ -7409,7 +7543,7 @@ async function runTailSession(opts) {
|
|
|
7409
7543
|
url = await opts.mintTicket();
|
|
7410
7544
|
} catch (err) {
|
|
7411
7545
|
if (!everConnected) {
|
|
7412
|
-
console.error(
|
|
7546
|
+
console.error(import_chalk33.default.red(`Could not start tail: ${err.message}`));
|
|
7413
7547
|
process.exit(1);
|
|
7414
7548
|
}
|
|
7415
7549
|
lastFailure = `ticket mint failed: ${err.message}`;
|
|
@@ -7422,7 +7556,7 @@ async function runTailSession(opts) {
|
|
|
7422
7556
|
} catch (err) {
|
|
7423
7557
|
lastFailure = `bad tail URL: ${err.message}`;
|
|
7424
7558
|
if (!everConnected) {
|
|
7425
|
-
console.error(
|
|
7559
|
+
console.error(import_chalk33.default.red(`Could not start tail: ${lastFailure}`));
|
|
7426
7560
|
process.exit(1);
|
|
7427
7561
|
}
|
|
7428
7562
|
scheduleReconnect();
|
|
@@ -7437,9 +7571,9 @@ async function runTailSession(opts) {
|
|
|
7437
7571
|
lastInbound = Date.now();
|
|
7438
7572
|
lastFailure = "";
|
|
7439
7573
|
if (isReconnect) {
|
|
7440
|
-
diag(
|
|
7574
|
+
diag(import_chalk33.default.dim("reconnected \u2014 requests during the gap were not replayed (browse them with `logs list`)."));
|
|
7441
7575
|
} else {
|
|
7442
|
-
diag(
|
|
7576
|
+
diag(import_chalk33.default.dim(interactive ? "[Enter] inspect a request \xB7 [Ctrl+C] stop\n" : "Ctrl+C to stop."));
|
|
7443
7577
|
}
|
|
7444
7578
|
bindKeys();
|
|
7445
7579
|
pingTimer = setInterval(() => {
|
|
@@ -7466,7 +7600,7 @@ async function runTailSession(opts) {
|
|
|
7466
7600
|
return;
|
|
7467
7601
|
}
|
|
7468
7602
|
if (frame?.type === "ceiling") {
|
|
7469
|
-
diag(
|
|
7603
|
+
diag(import_chalk33.default.yellow(
|
|
7470
7604
|
`\u26A0 volume ceiling \u2014 ${Number(frame.dropped_this_hour) || 0} rows dropped this hour; errors keep streaming.`
|
|
7471
7605
|
));
|
|
7472
7606
|
return;
|
|
@@ -7546,10 +7680,10 @@ async function fetchPage(fetchWindow3, params, notices) {
|
|
|
7546
7680
|
return { rows, nextCursor: res.next_cursor ?? void 0 };
|
|
7547
7681
|
}
|
|
7548
7682
|
if (hop >= MAX_EMPTY_HOPS) {
|
|
7549
|
-
console.error(
|
|
7683
|
+
console.error(import_chalk33.default.yellow("\u26A0 stopped after scanning a long empty span \u2014 older rows may still exist."));
|
|
7550
7684
|
return { rows: [], nextCursor: res.next_cursor, fuseTripped: true };
|
|
7551
7685
|
}
|
|
7552
|
-
if (hop === 0) console.error(
|
|
7686
|
+
if (hop === 0) console.error(import_chalk33.default.dim("searching older history\u2026"));
|
|
7553
7687
|
cursor = res.next_cursor;
|
|
7554
7688
|
}
|
|
7555
7689
|
}
|
|
@@ -7589,18 +7723,18 @@ async function runPlainList(opts, notices) {
|
|
|
7589
7723
|
}
|
|
7590
7724
|
}
|
|
7591
7725
|
if (rows.length === 0) {
|
|
7592
|
-
console.log(
|
|
7726
|
+
console.log(import_chalk33.default.dim(fuseTripped ? "Nothing found in the scanned span \u2014 older requests may still exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
|
|
7593
7727
|
return;
|
|
7594
7728
|
}
|
|
7595
7729
|
const now = Date.now();
|
|
7596
7730
|
for (const d of groupIntoDays(rows)) {
|
|
7597
|
-
console.log(
|
|
7731
|
+
console.log(import_chalk33.default.bold(dayLabel(d.dayMs, now)));
|
|
7598
7732
|
for (const r of d.rows) console.log(` ${formatRow(r)}`);
|
|
7599
7733
|
console.log("");
|
|
7600
7734
|
}
|
|
7601
7735
|
const errs = rows.filter((r) => r.status >= 400).length;
|
|
7602
7736
|
const tail = fuseTripped ? " \xB7 stopped early (long empty span) \u2014 older requests may still exist" : more ? " \xB7 showing the most recent \u2014 `--json` streams the rest" : "";
|
|
7603
|
-
console.log(
|
|
7737
|
+
console.log(import_chalk33.default.dim(
|
|
7604
7738
|
`${rows.length} request${rows.length === 1 ? "" : "s"} \xB7 ${errs} error${errs === 1 ? "" : "s"}${tail}`
|
|
7605
7739
|
));
|
|
7606
7740
|
}
|
|
@@ -7619,7 +7753,7 @@ async function runHistoryBrowser(opts) {
|
|
|
7619
7753
|
for (const r of page.rows) console.log(JSON.stringify(r));
|
|
7620
7754
|
any = any || page.rows.length > 0;
|
|
7621
7755
|
if (page.fuseTripped || !page.nextCursor) {
|
|
7622
|
-
if (!any && !page.fuseTripped) console.error(
|
|
7756
|
+
if (!any && !page.fuseTripped) console.error(import_chalk33.default.dim(opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
|
|
7623
7757
|
return;
|
|
7624
7758
|
}
|
|
7625
7759
|
cursor2 = page.nextCursor;
|
|
@@ -7640,7 +7774,7 @@ async function runHistoryBrowser(opts) {
|
|
|
7640
7774
|
scanRows = first.rows;
|
|
7641
7775
|
scanCursor = first.nextCursor;
|
|
7642
7776
|
if (scanRows.length === 0) {
|
|
7643
|
-
console.log(
|
|
7777
|
+
console.log(import_chalk33.default.dim(first.fuseTripped ? "Nothing found in the scanned span \u2014 older rows may exist." : opts.errorsOnly ? "No errors logged yet." : "No requests logged yet."));
|
|
7644
7778
|
return;
|
|
7645
7779
|
}
|
|
7646
7780
|
}
|
|
@@ -7651,10 +7785,10 @@ async function runHistoryBrowser(opts) {
|
|
|
7651
7785
|
const now2 = Date.now();
|
|
7652
7786
|
const oldestKey = days[days.length - 1]?.key;
|
|
7653
7787
|
const choices = days.map((d) => ({
|
|
7654
|
-
name: `${dayLabel(d.dayMs, now2).padEnd(12)} ${String(d.rows.length).padStart(4)}${(scanCursor !== void 0 || scanFloorUnknown) && d.key === oldestKey ? "+" : ""} requests${d.errors ?
|
|
7788
|
+
name: `${dayLabel(d.dayMs, now2).padEnd(12)} ${String(d.rows.length).padStart(4)}${(scanCursor !== void 0 || scanFloorUnknown) && d.key === oldestKey ? "+" : ""} requests${d.errors ? import_chalk33.default.red(` ${d.errors} errors`) : ""}`,
|
|
7655
7789
|
value: d.key
|
|
7656
7790
|
}));
|
|
7657
|
-
if (scanCursor) choices.push({ name:
|
|
7791
|
+
if (scanCursor) choices.push({ name: import_chalk33.default.dim("\u2026 older days"), value: "__older__" });
|
|
7658
7792
|
const { chosenDay } = await inquirer3.prompt([{
|
|
7659
7793
|
type: "list",
|
|
7660
7794
|
name: "chosenDay",
|
|
@@ -7674,7 +7808,7 @@ async function runHistoryBrowser(opts) {
|
|
|
7674
7808
|
scanCursor = void 0;
|
|
7675
7809
|
} else {
|
|
7676
7810
|
scanCursor = more.nextCursor;
|
|
7677
|
-
if (more.rows.length === 0 && !scanCursor) console.log(
|
|
7811
|
+
if (more.rows.length === 0 && !scanCursor) console.log(import_chalk33.default.dim("That was everything \u2014 no older requests."));
|
|
7678
7812
|
}
|
|
7679
7813
|
continue;
|
|
7680
7814
|
}
|
|
@@ -7696,11 +7830,11 @@ async function runHistoryBrowser(opts) {
|
|
|
7696
7830
|
cursor
|
|
7697
7831
|
}, notices);
|
|
7698
7832
|
if (page.rows.length === 0 && pageRows.length === 0) {
|
|
7699
|
-
console.log(
|
|
7833
|
+
console.log(import_chalk33.default.dim(page.fuseTripped ? "Stopped scanning this day (long empty span) \u2014 older rows in it may exist." : "No requests for this day."));
|
|
7700
7834
|
return;
|
|
7701
7835
|
}
|
|
7702
7836
|
if (page.rows.length === 0) {
|
|
7703
|
-
console.log(
|
|
7837
|
+
console.log(import_chalk33.default.dim(page.fuseTripped ? "Stopped scanning further into this day (long empty span) \u2014 older rows in it may exist." : "That was everything for this day."));
|
|
7704
7838
|
moreCursor = void 0;
|
|
7705
7839
|
} else {
|
|
7706
7840
|
pageRows = page.rows;
|
|
@@ -7711,8 +7845,8 @@ async function runHistoryBrowser(opts) {
|
|
|
7711
7845
|
name: formatRow(r),
|
|
7712
7846
|
value: r.request_id
|
|
7713
7847
|
}));
|
|
7714
|
-
if (moreCursor) choices.push({ name:
|
|
7715
|
-
choices.push({ name:
|
|
7848
|
+
if (moreCursor) choices.push({ name: import_chalk33.default.dim("\u2026 load more"), value: "__more__" });
|
|
7849
|
+
choices.push({ name: import_chalk33.default.dim("quit"), value: "__quit__" });
|
|
7716
7850
|
for (; ; ) {
|
|
7717
7851
|
const { picked } = await inquirer3.prompt([{
|
|
7718
7852
|
type: "list",
|
|
@@ -7762,19 +7896,19 @@ function wrapCells(items, width) {
|
|
|
7762
7896
|
${PANE_INDENT}`);
|
|
7763
7897
|
}
|
|
7764
7898
|
function renderHeaders(h) {
|
|
7765
|
-
if (!h) return
|
|
7899
|
+
if (!h) return import_chalk33.default.dim("\u2014");
|
|
7766
7900
|
const width = process.stdout.columns || 100;
|
|
7767
7901
|
if (h.values) {
|
|
7768
7902
|
const e = Object.entries(h.values);
|
|
7769
|
-
if (!e.length) return
|
|
7903
|
+
if (!e.length) return import_chalk33.default.dim("none");
|
|
7770
7904
|
const rank = (k) => {
|
|
7771
7905
|
const i = HEADER_PRIORITY.indexOf(k.toLowerCase());
|
|
7772
7906
|
return i === -1 ? NOISE_HEADER.test(k) ? 999 : 500 : i;
|
|
7773
7907
|
};
|
|
7774
|
-
return e.sort((a, b) => rank(a[0]) - rank(b[0])).map(([k, v]) => `${
|
|
7908
|
+
return e.sort((a, b) => rank(a[0]) - rank(b[0])).map(([k, v]) => `${import_chalk33.default.dim(k + ":")} ${v}`).join(`
|
|
7775
7909
|
${PANE_INDENT}`);
|
|
7776
7910
|
}
|
|
7777
|
-
if (!h.names?.length) return
|
|
7911
|
+
if (!h.names?.length) return import_chalk33.default.dim("none");
|
|
7778
7912
|
const names = [...h.names];
|
|
7779
7913
|
const noise = names.filter((n) => NOISE_HEADER.test(n));
|
|
7780
7914
|
const shown = names.filter((n) => !NOISE_HEADER.test(n)).sort((a, b) => {
|
|
@@ -7782,70 +7916,70 @@ ${PANE_INDENT}`);
|
|
|
7782
7916
|
const ib = HEADER_PRIORITY.indexOf(b.toLowerCase());
|
|
7783
7917
|
return (ia === -1 ? 500 : ia) - (ib === -1 ? 500 : ib) || a.localeCompare(b);
|
|
7784
7918
|
});
|
|
7785
|
-
const body = shown.length ? wrapCells(shown, width) :
|
|
7919
|
+
const body = shown.length ? wrapCells(shown, width) : import_chalk33.default.dim("(all forwarding headers)");
|
|
7786
7920
|
const tail = noise.length ? `
|
|
7787
|
-
${PANE_INDENT}${
|
|
7788
|
-
return `${body}${tail} ${
|
|
7921
|
+
${PANE_INDENT}${import_chalk33.default.dim(`+ ${noise.length} forwarding/client-hint header${noise.length === 1 ? "" : "s"} (cf-*, sec-*)`)}` : "";
|
|
7922
|
+
return `${body}${tail} ${import_chalk33.default.dim("(names only)")}`;
|
|
7789
7923
|
}
|
|
7790
7924
|
function renderBody(b) {
|
|
7791
|
-
if (!b) return
|
|
7925
|
+
if (!b) return import_chalk33.default.dim("\u2014");
|
|
7792
7926
|
const meta = [b.content_type, b.size != null ? `${b.size}B` : null, b.truncated ? "truncated" : null].filter(Boolean).join(" \xB7 ");
|
|
7793
|
-
if (b.not_captured) return
|
|
7927
|
+
if (b.not_captured) return import_chalk33.default.dim(`not captured (${b.not_captured})${meta ? " \xB7 " + meta : ""}`);
|
|
7794
7928
|
const isShape = b.value === void 0 && b.shape !== void 0;
|
|
7795
7929
|
const content = b.value !== void 0 ? b.value : b.shape;
|
|
7796
7930
|
if (content === null || content === void 0 || content === "" || content === "empty") {
|
|
7797
|
-
return
|
|
7931
|
+
return import_chalk33.default.dim(`empty${meta ? " \xB7 " + meta : ""}`);
|
|
7798
7932
|
}
|
|
7799
7933
|
const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
7800
|
-
const head = isShape ?
|
|
7934
|
+
const head = isShape ? import_chalk33.default.dim("shape only (values not captured)\n ") : "";
|
|
7801
7935
|
return head + text.split("\n").join("\n ");
|
|
7802
7936
|
}
|
|
7803
7937
|
function pane(title, tone, view, empty) {
|
|
7804
7938
|
console.log(` ${tone(title)}`);
|
|
7805
7939
|
if (empty !== void 0) {
|
|
7806
|
-
console.log(` ${
|
|
7940
|
+
console.log(` ${import_chalk33.default.dim(empty)}`);
|
|
7807
7941
|
return;
|
|
7808
7942
|
}
|
|
7809
7943
|
const v = view ?? {};
|
|
7810
|
-
if (v.url) console.log(` ${
|
|
7944
|
+
if (v.url) console.log(` ${import_chalk33.default.dim("target")} ${v.url}`);
|
|
7811
7945
|
if (v.status != null) {
|
|
7812
|
-
console.log(` ${
|
|
7946
|
+
console.log(` ${import_chalk33.default.dim("status")} ${statusColor(v.status)(String(v.status))}${v.status_text ? import_chalk33.default.dim(" " + v.status_text) : ""}`);
|
|
7813
7947
|
}
|
|
7814
|
-
if (v.raw_path) console.log(` ${
|
|
7948
|
+
if (v.raw_path) console.log(` ${import_chalk33.default.dim("path")} ${v.raw_path}`);
|
|
7815
7949
|
if (v.query && Object.keys(v.query).length) {
|
|
7816
|
-
console.log(` ${
|
|
7950
|
+
console.log(` ${import_chalk33.default.dim("query")} ${Object.entries(v.query).map(([k, q]) => `${k}=${q}`).join(" ")}`);
|
|
7817
7951
|
}
|
|
7818
|
-
if (v.jwt !== void 0) console.log(` ${
|
|
7819
|
-
console.log(` ${
|
|
7820
|
-
console.log(` ${
|
|
7952
|
+
if (v.jwt !== void 0) console.log(` ${import_chalk33.default.dim("jwt")} ${JSON.stringify(v.jwt)}`);
|
|
7953
|
+
console.log(` ${import_chalk33.default.dim("headers")} ${renderHeaders(v.headers)}`);
|
|
7954
|
+
console.log(` ${import_chalk33.default.dim("body")} ${renderBody(v.body)}`);
|
|
7821
7955
|
}
|
|
7822
7956
|
function printDetail(r, mode = "producer") {
|
|
7823
7957
|
const v = r.views;
|
|
7824
7958
|
console.log("");
|
|
7825
|
-
console.log(
|
|
7959
|
+
console.log(import_chalk33.default.bold(`${r.method} ${r.route}`) + " " + statusColor(r.status)(String(r.status)) + import_chalk33.default.dim(` ${r.duration_ms}ms`));
|
|
7826
7960
|
const cost = typeof r.cost_cents === "number" && r.cost_cents > 0 ? ` \xB7 ${r.cost_cents}\xA2` : "";
|
|
7827
|
-
console.log(
|
|
7961
|
+
console.log(import_chalk33.default.dim(` request_id ${r.request_id}${r.environment ? ` \xB7 env ${r.environment}` : ""}${r.consumer_id ? ` \xB7 consumer ${r.consumer_id}` : ""}${cost}`));
|
|
7828
7962
|
console.log("");
|
|
7829
7963
|
if (!v) {
|
|
7830
|
-
console.log(
|
|
7964
|
+
console.log(import_chalk33.default.dim(" No view detail captured for this request.\n"));
|
|
7831
7965
|
return;
|
|
7832
7966
|
}
|
|
7833
|
-
pane("Request (before) \u2014 client \u2192 APIblaze",
|
|
7967
|
+
pane("Request (before) \u2014 client \u2192 APIblaze", import_chalk33.default.cyan, v.request);
|
|
7834
7968
|
if (mode === "producer") {
|
|
7835
7969
|
pane(
|
|
7836
7970
|
"Request (after) \u2014 APIblaze \u2192 upstream",
|
|
7837
|
-
|
|
7971
|
+
import_chalk33.default.cyan,
|
|
7838
7972
|
v.forwarded_request,
|
|
7839
7973
|
v.forwarded_request ? void 0 : "Request did not reach an upstream."
|
|
7840
7974
|
);
|
|
7841
7975
|
pane(
|
|
7842
7976
|
"Response (before) \u2014 upstream \u2192 APIblaze",
|
|
7843
|
-
|
|
7977
|
+
import_chalk33.default.magenta,
|
|
7844
7978
|
v.upstream_response,
|
|
7845
7979
|
v.upstream_response ? void 0 : "No upstream response."
|
|
7846
7980
|
);
|
|
7847
7981
|
}
|
|
7848
|
-
pane("Response (after) \u2014 APIblaze \u2192 client",
|
|
7982
|
+
pane("Response (after) \u2014 APIblaze \u2192 client", import_chalk33.default.magenta, v.response);
|
|
7849
7983
|
console.log("");
|
|
7850
7984
|
}
|
|
7851
7985
|
|
|
@@ -7894,7 +8028,7 @@ async function resolve(projectArg, versionArg, opts) {
|
|
|
7894
8028
|
return { projectId, projectName: match.projectName, version: version2, tenant: tenant2 };
|
|
7895
8029
|
}
|
|
7896
8030
|
function otherPlaneHint() {
|
|
7897
|
-
if (loadConsumer()) console.log(
|
|
8031
|
+
if (loadConsumer()) console.log(import_chalk34.default.dim(" \u2039consumer view: apiblaze consumer logs\u203A"));
|
|
7898
8032
|
}
|
|
7899
8033
|
function fetchWindow(projectId, version2, tenant2) {
|
|
7900
8034
|
return (params) => {
|
|
@@ -7913,8 +8047,8 @@ function fetchWindow(projectId, version2, tenant2) {
|
|
|
7913
8047
|
async function runLogsTail(projectArg, versionArg, opts) {
|
|
7914
8048
|
const { projectId, projectName, version: version2, tenant: tenant2 } = await resolve(projectArg, versionArg, opts);
|
|
7915
8049
|
if (!opts.json) {
|
|
7916
|
-
console.log(
|
|
7917
|
-
console.log(
|
|
8050
|
+
console.log(import_chalk34.default.bold("API Producer logs") + import_chalk34.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
|
|
8051
|
+
console.log(import_chalk34.default.dim("every caller's requests, with cost and upstream detail"));
|
|
7918
8052
|
otherPlaneHint();
|
|
7919
8053
|
}
|
|
7920
8054
|
await runTailSession({
|
|
@@ -7935,8 +8069,8 @@ async function runLogsTail(projectArg, versionArg, opts) {
|
|
|
7935
8069
|
async function runLogsList(projectArg, versionArg, opts) {
|
|
7936
8070
|
const { projectId, projectName, version: version2, tenant: tenant2 } = await resolve(projectArg, versionArg, opts);
|
|
7937
8071
|
if (!opts.json) {
|
|
7938
|
-
console.log(
|
|
7939
|
-
console.log(
|
|
8072
|
+
console.log(import_chalk34.default.bold("API Producer logs") + import_chalk34.default.dim(` \xB7 ${projectName}@${version2} \xB7 tenant ${tenant2}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
|
|
8073
|
+
console.log(import_chalk34.default.dim("every caller's requests, with cost and upstream detail"));
|
|
7940
8074
|
otherPlaneHint();
|
|
7941
8075
|
console.log("");
|
|
7942
8076
|
}
|
|
@@ -7950,15 +8084,15 @@ async function runLogsList(projectArg, versionArg, opts) {
|
|
|
7950
8084
|
}
|
|
7951
8085
|
|
|
7952
8086
|
// src/commands/consumer-logs.ts
|
|
7953
|
-
var
|
|
8087
|
+
var import_chalk35 = __toESM(require("chalk"));
|
|
7954
8088
|
init_auth();
|
|
7955
8089
|
var CONSUMER_LOGS_BASE = process.env.APIBLAZE_CONSUMER_LOGS_BASE || "https://logs.apiblaze.com/consumer";
|
|
7956
8090
|
function requireConsumer() {
|
|
7957
8091
|
const c = loadConsumer();
|
|
7958
8092
|
if (!c) {
|
|
7959
|
-
console.error(
|
|
8093
|
+
console.error(import_chalk35.default.red("Not logged in as an API Consumer. Run `apiblaze consumer login` first."));
|
|
7960
8094
|
if (loadCredentials()) {
|
|
7961
|
-
console.error(
|
|
8095
|
+
console.error(import_chalk35.default.dim("You're signed in as an API Producer \u2014 for a proxy's full logs run `apiblaze logs <project>`."));
|
|
7962
8096
|
}
|
|
7963
8097
|
process.exit(1);
|
|
7964
8098
|
}
|
|
@@ -7989,7 +8123,7 @@ async function consumerLogsFetch(session, suffix, init) {
|
|
|
7989
8123
|
return data;
|
|
7990
8124
|
}
|
|
7991
8125
|
function otherPlaneHint2() {
|
|
7992
|
-
if (loadCredentials()) console.log(
|
|
8126
|
+
if (loadCredentials()) console.log(import_chalk35.default.dim(" \u2039producer view: apiblaze logs <project>\u203A"));
|
|
7993
8127
|
}
|
|
7994
8128
|
function fetchWindow2(session, project) {
|
|
7995
8129
|
return (params) => {
|
|
@@ -8005,8 +8139,8 @@ function fetchWindow2(session, project) {
|
|
|
8005
8139
|
async function runConsumerLogsTail(opts) {
|
|
8006
8140
|
const session = requireConsumer();
|
|
8007
8141
|
if (!opts.json) {
|
|
8008
|
-
console.log(
|
|
8009
|
-
console.log(
|
|
8142
|
+
console.log(import_chalk35.default.bold("API Consumer logs") + import_chalk35.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
|
|
8143
|
+
console.log(import_chalk35.default.dim("cost and upstream details are producer-only and are not sent"));
|
|
8010
8144
|
otherPlaneHint2();
|
|
8011
8145
|
}
|
|
8012
8146
|
await runTailSession({
|
|
@@ -8024,8 +8158,8 @@ async function runConsumerLogsTail(opts) {
|
|
|
8024
8158
|
async function runConsumerLogsList(opts) {
|
|
8025
8159
|
const session = requireConsumer();
|
|
8026
8160
|
if (!opts.json) {
|
|
8027
|
-
console.log(
|
|
8028
|
-
console.log(
|
|
8161
|
+
console.log(import_chalk35.default.bold("API Consumer logs") + import_chalk35.default.dim(` \xB7 your own requests on ${session.creds.tenant}${opts.project ? ` \xB7 ${opts.project}` : ""}${opts.errorsOnly ? " \xB7 errors only" : ""}`));
|
|
8162
|
+
console.log(import_chalk35.default.dim("cost and upstream details are producer-only and are not sent"));
|
|
8029
8163
|
otherPlaneHint2();
|
|
8030
8164
|
console.log("");
|
|
8031
8165
|
}
|
|
@@ -8039,7 +8173,7 @@ async function runConsumerLogsList(opts) {
|
|
|
8039
8173
|
}
|
|
8040
8174
|
|
|
8041
8175
|
// src/commands/config.ts
|
|
8042
|
-
var
|
|
8176
|
+
var import_chalk36 = __toESM(require("chalk"));
|
|
8043
8177
|
var import_ora12 = __toESM(require("ora"));
|
|
8044
8178
|
init_admin();
|
|
8045
8179
|
init_resolve();
|
|
@@ -8063,7 +8197,7 @@ async function patchConfig(project, opts, body, summary) {
|
|
|
8063
8197
|
}
|
|
8064
8198
|
async function runTargetSet(project, opts) {
|
|
8065
8199
|
if (!opts.url) {
|
|
8066
|
-
console.error(
|
|
8200
|
+
console.error(import_chalk36.default.red("--url is required."));
|
|
8067
8201
|
process.exit(1);
|
|
8068
8202
|
}
|
|
8069
8203
|
const body = opts.env ? { environments: { [opts.env]: { target: opts.url } } } : { target_url: opts.url };
|
|
@@ -8076,40 +8210,40 @@ async function runThrottleSet(project, opts) {
|
|
|
8076
8210
|
if (opts.quota !== void 0) throttling.proxyQuota = Number(opts.quota);
|
|
8077
8211
|
if (opts.period !== void 0) {
|
|
8078
8212
|
if (!["daily", "weekly", "monthly"].includes(opts.period)) {
|
|
8079
|
-
console.error(
|
|
8213
|
+
console.error(import_chalk36.default.red("--period must be daily, weekly, or monthly."));
|
|
8080
8214
|
process.exit(1);
|
|
8081
8215
|
}
|
|
8082
8216
|
throttling.quotaPeriod = opts.period;
|
|
8083
8217
|
}
|
|
8084
8218
|
if (Object.keys(throttling).length === 0) {
|
|
8085
|
-
console.error(
|
|
8219
|
+
console.error(import_chalk36.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
|
|
8086
8220
|
process.exit(1);
|
|
8087
8221
|
}
|
|
8088
8222
|
await patchConfig(project, opts, { throttling }, `Update throttling ${JSON.stringify(throttling)}`);
|
|
8089
8223
|
}
|
|
8090
8224
|
async function runRename(project, opts) {
|
|
8091
8225
|
if (!opts.displayName) {
|
|
8092
|
-
console.error(
|
|
8226
|
+
console.error(import_chalk36.default.red("--display-name is required."));
|
|
8093
8227
|
process.exit(1);
|
|
8094
8228
|
}
|
|
8095
8229
|
await patchConfig(project, opts, { display_name: opts.displayName }, `Rename \u2192 "${opts.displayName}"`);
|
|
8096
8230
|
}
|
|
8097
8231
|
|
|
8098
8232
|
// src/commands/config-browse.ts
|
|
8099
|
-
var
|
|
8233
|
+
var import_chalk45 = __toESM(require("chalk"));
|
|
8100
8234
|
var import_ora20 = __toESM(require("ora"));
|
|
8101
8235
|
init_admin();
|
|
8102
8236
|
init_auth();
|
|
8103
8237
|
init_resolve();
|
|
8104
8238
|
|
|
8105
8239
|
// src/commands/domain.ts
|
|
8106
|
-
var
|
|
8240
|
+
var import_chalk37 = __toESM(require("chalk"));
|
|
8107
8241
|
var import_ora13 = __toESM(require("ora"));
|
|
8108
8242
|
init_admin();
|
|
8109
8243
|
init_resolve();
|
|
8110
8244
|
async function runDomainAdd(project, opts) {
|
|
8111
8245
|
if (!opts.domain) {
|
|
8112
|
-
console.error(
|
|
8246
|
+
console.error(import_chalk37.default.red("--domain is required."));
|
|
8113
8247
|
process.exit(1);
|
|
8114
8248
|
}
|
|
8115
8249
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8128,9 +8262,9 @@ async function runDomainAdd(project, opts) {
|
|
|
8128
8262
|
console.log(JSON.stringify(out));
|
|
8129
8263
|
return;
|
|
8130
8264
|
}
|
|
8131
|
-
if (out?.cnameRecord) console.log(` ${
|
|
8132
|
-
if (out?.dcv) console.log(` ${
|
|
8133
|
-
if (out?.id) console.log(
|
|
8265
|
+
if (out?.cnameRecord) console.log(` ${import_chalk37.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
|
|
8266
|
+
if (out?.dcv) console.log(` ${import_chalk37.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
|
|
8267
|
+
if (out?.id) console.log(import_chalk37.default.dim(` domain id: ${out.id}`));
|
|
8134
8268
|
} catch (err) {
|
|
8135
8269
|
spinner.fail("Domain registration failed.");
|
|
8136
8270
|
throw err;
|
|
@@ -8150,14 +8284,14 @@ async function runDomainList(project, opts) {
|
|
|
8150
8284
|
return;
|
|
8151
8285
|
}
|
|
8152
8286
|
if (!domains.length) {
|
|
8153
|
-
console.log(
|
|
8287
|
+
console.log(import_chalk37.default.yellow("No custom domains."));
|
|
8154
8288
|
return;
|
|
8155
8289
|
}
|
|
8156
|
-
for (const d of domains) console.log(` ${
|
|
8290
|
+
for (const d of domains) console.log(` ${import_chalk37.default.bold(d.hostname)} ${import_chalk37.default.dim(d.status ?? "")} ${import_chalk37.default.dim(d.id ?? "")}`);
|
|
8157
8291
|
}
|
|
8158
8292
|
async function runDomainStatus(project, opts) {
|
|
8159
8293
|
if (!opts.id) {
|
|
8160
|
-
console.error(
|
|
8294
|
+
console.error(import_chalk37.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
|
|
8161
8295
|
process.exit(1);
|
|
8162
8296
|
}
|
|
8163
8297
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8167,11 +8301,11 @@ async function runDomainStatus(project, opts) {
|
|
|
8167
8301
|
path: `/projects/${proj2.projectId}/domains/${encodeURIComponent(opts.id)}/status`,
|
|
8168
8302
|
summary: `Check custom-domain status`
|
|
8169
8303
|
});
|
|
8170
|
-
console.log(opts.json ? JSON.stringify(out) : ` ${
|
|
8304
|
+
console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk37.default.bold(out?.hostname ?? opts.id)}: ${import_chalk37.default.cyan(out?.status ?? "unknown")}`);
|
|
8171
8305
|
}
|
|
8172
8306
|
async function runDomainRemove(project, opts) {
|
|
8173
8307
|
if (!opts.id) {
|
|
8174
|
-
console.error(
|
|
8308
|
+
console.error(import_chalk37.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
|
|
8175
8309
|
process.exit(1);
|
|
8176
8310
|
}
|
|
8177
8311
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8209,7 +8343,7 @@ async function runDomainSetBase(project, opts) {
|
|
|
8209
8343
|
}
|
|
8210
8344
|
|
|
8211
8345
|
// src/commands/tenant.ts
|
|
8212
|
-
var
|
|
8346
|
+
var import_chalk40 = __toESM(require("chalk"));
|
|
8213
8347
|
var import_ora16 = __toESM(require("ora"));
|
|
8214
8348
|
init_admin();
|
|
8215
8349
|
init_resolve();
|
|
@@ -8218,20 +8352,20 @@ init_tenant_pick();
|
|
|
8218
8352
|
async function runTenantUse(query, opts) {
|
|
8219
8353
|
const creds = loadCredentials();
|
|
8220
8354
|
if (!creds) {
|
|
8221
|
-
console.error(
|
|
8355
|
+
console.error(import_chalk40.default.red("Not logged in. Run `apiblaze login` first."));
|
|
8222
8356
|
process.exit(1);
|
|
8223
8357
|
}
|
|
8224
8358
|
if (opts.clear) {
|
|
8225
8359
|
delete creds.activeTenant;
|
|
8226
8360
|
saveCredentials(creds);
|
|
8227
|
-
console.log(
|
|
8361
|
+
console.log(import_chalk40.default.green("Tenant scope cleared."));
|
|
8228
8362
|
return;
|
|
8229
8363
|
}
|
|
8230
8364
|
const { teamId } = await resolveTeam(opts.team);
|
|
8231
8365
|
const slug = await pickTenant(teamId, { message: "Scope future commands to which tenant?", initialQuery: query });
|
|
8232
8366
|
if (!slug) process.exit(1);
|
|
8233
8367
|
saveCredentials({ ...creds, activeTenant: slug });
|
|
8234
|
-
console.log(
|
|
8368
|
+
console.log(import_chalk40.default.green(`Tenant scope set to ${import_chalk40.default.bold(slug)}.`) + import_chalk40.default.dim(" (clear with `apiblaze tenant use --clear`)"));
|
|
8235
8369
|
}
|
|
8236
8370
|
async function runTenantList(opts) {
|
|
8237
8371
|
const { teamId, teamName } = await resolveTeam(opts.team);
|
|
@@ -8248,22 +8382,22 @@ async function runTenantList(opts) {
|
|
|
8248
8382
|
return;
|
|
8249
8383
|
}
|
|
8250
8384
|
if (!tenants.length) {
|
|
8251
|
-
console.log(
|
|
8385
|
+
console.log(import_chalk40.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
|
|
8252
8386
|
return;
|
|
8253
8387
|
}
|
|
8254
8388
|
for (const t of tenants) {
|
|
8255
8389
|
const name = typeof t === "string" ? t : t.tenant_name;
|
|
8256
|
-
const display = typeof t === "string" ? "" :
|
|
8257
|
-
console.log(` ${
|
|
8390
|
+
const display = typeof t === "string" ? "" : import_chalk40.default.dim(` ${t.display_name ?? ""}`);
|
|
8391
|
+
console.log(` ${import_chalk40.default.bold(name)}${display}`);
|
|
8258
8392
|
}
|
|
8259
8393
|
const total = out?.total ?? tenants.length;
|
|
8260
8394
|
if (total > tenants.length) {
|
|
8261
|
-
console.log(
|
|
8395
|
+
console.log(import_chalk40.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
|
|
8262
8396
|
}
|
|
8263
8397
|
}
|
|
8264
8398
|
async function runTenantCreate(opts) {
|
|
8265
8399
|
if (!opts.name) {
|
|
8266
|
-
console.error(
|
|
8400
|
+
console.error(import_chalk40.default.red("--name (display name) is required."));
|
|
8267
8401
|
process.exit(1);
|
|
8268
8402
|
}
|
|
8269
8403
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8275,7 +8409,7 @@ async function runTenantCreate(opts) {
|
|
|
8275
8409
|
body: { display_name: opts.name, ...opts.slug ? { tenant_name: opts.slug } : {} },
|
|
8276
8410
|
summary: `Create tenant "${opts.name}"`
|
|
8277
8411
|
});
|
|
8278
|
-
spinner.succeed(`Created tenant ${
|
|
8412
|
+
spinner.succeed(`Created tenant ${import_chalk40.default.bold(out?.tenant_name ?? opts.name)}.`);
|
|
8279
8413
|
if (opts.json) console.log(JSON.stringify(out));
|
|
8280
8414
|
} catch (err) {
|
|
8281
8415
|
spinner.fail("Tenant create failed.");
|
|
@@ -8284,7 +8418,7 @@ async function runTenantCreate(opts) {
|
|
|
8284
8418
|
}
|
|
8285
8419
|
async function runTenantAttach(project, opts) {
|
|
8286
8420
|
if (!opts.tenant) {
|
|
8287
|
-
console.error(
|
|
8421
|
+
console.error(import_chalk40.default.red("--tenant <slug> is required."));
|
|
8288
8422
|
process.exit(1);
|
|
8289
8423
|
}
|
|
8290
8424
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8312,7 +8446,7 @@ async function runTenantDelete(slug, opts) {
|
|
|
8312
8446
|
{ type: "confirm", name: "confirm", message: `Permanently delete tenant "${slug}" and everything under it? This cannot be undone.`, default: false }
|
|
8313
8447
|
]);
|
|
8314
8448
|
if (!confirm2) {
|
|
8315
|
-
console.log(
|
|
8449
|
+
console.log(import_chalk40.default.dim("Aborted."));
|
|
8316
8450
|
return;
|
|
8317
8451
|
}
|
|
8318
8452
|
}
|
|
@@ -8331,7 +8465,7 @@ async function runTenantDelete(slug, opts) {
|
|
|
8331
8465
|
}
|
|
8332
8466
|
async function runTenantCors(opts) {
|
|
8333
8467
|
if (!opts.tenant) {
|
|
8334
|
-
console.error(
|
|
8468
|
+
console.error(import_chalk40.default.red("--tenant <slug> is required."));
|
|
8335
8469
|
process.exit(1);
|
|
8336
8470
|
}
|
|
8337
8471
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8353,7 +8487,7 @@ async function runTenantCors(opts) {
|
|
|
8353
8487
|
}
|
|
8354
8488
|
|
|
8355
8489
|
// src/commands/tenant-drill.ts
|
|
8356
|
-
var
|
|
8490
|
+
var import_chalk41 = __toESM(require("chalk"));
|
|
8357
8491
|
var import_ora17 = __toESM(require("ora"));
|
|
8358
8492
|
var import_crypto = require("crypto");
|
|
8359
8493
|
init_admin();
|
|
@@ -8384,15 +8518,15 @@ async function validScopedTenant(teamId, query) {
|
|
|
8384
8518
|
const next = { ...creds };
|
|
8385
8519
|
delete next.activeTenant;
|
|
8386
8520
|
saveCredentials2(next);
|
|
8387
|
-
console.log(
|
|
8521
|
+
console.log(import_chalk41.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
|
|
8388
8522
|
return void 0;
|
|
8389
8523
|
}
|
|
8390
8524
|
async function tenantHome(teamId, tenant2) {
|
|
8391
8525
|
const { default: inquirer3 } = await import("inquirer");
|
|
8392
8526
|
const base2 = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
|
|
8393
|
-
console.log(
|
|
8527
|
+
console.log(import_chalk41.default.bold(`
|
|
8394
8528
|
Tenant ${tenant2}`));
|
|
8395
|
-
console.log(
|
|
8529
|
+
console.log(import_chalk41.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
|
|
8396
8530
|
for (; ; ) {
|
|
8397
8531
|
const spinner = (0, import_ora17.default)("Reading tenant state...").start();
|
|
8398
8532
|
const [iam, cors, emails, issuers, opaque, clients] = await Promise.all([
|
|
@@ -8408,18 +8542,18 @@ Tenant ${tenant2}`));
|
|
|
8408
8542
|
const nClients = Array.isArray(clients) ? clients.length : 0;
|
|
8409
8543
|
const nOpaque = opaque?.opaque?.endpoint ? 1 : 0;
|
|
8410
8544
|
const nLogin = nClients + nIssuers + nOpaque;
|
|
8411
|
-
const onOff = (b) => b ?
|
|
8545
|
+
const onOff = (b) => b ? import_chalk41.default.green("on") : import_chalk41.default.dim("off");
|
|
8412
8546
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
8413
8547
|
type: "list",
|
|
8414
8548
|
name: "pick",
|
|
8415
8549
|
message: `Tenant ${tenant2}:`,
|
|
8416
8550
|
pageSize: 12,
|
|
8417
8551
|
choices: [
|
|
8418
|
-
{ name: `Login methods (${nLogin}) ${
|
|
8419
|
-
{ name: `Users & groups: ${onOff(iam?.iam_enabled)} ${
|
|
8420
|
-
{ name: `Portal admins (${nEmails}) ${
|
|
8421
|
-
new inquirer3.Separator(
|
|
8422
|
-
{ name: `CORS: ${cors?.cors ?
|
|
8552
|
+
{ name: `Login methods (${nLogin}) ${import_chalk41.default.dim("how your consumers sign in")}`, value: "login" },
|
|
8553
|
+
{ name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk41.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
|
|
8554
|
+
{ name: `Portal admins (${nEmails}) ${import_chalk41.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
|
|
8555
|
+
new inquirer3.Separator(import_chalk41.default.dim(" Settings")),
|
|
8556
|
+
{ name: `CORS: ${cors?.cors ? import_chalk41.default.cyan(JSON.stringify(cors.cors)) : import_chalk41.default.dim("(unset)")} ${import_chalk41.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
|
|
8423
8557
|
{ name: "\u2190 Back", value: "back" }
|
|
8424
8558
|
]
|
|
8425
8559
|
}]);
|
|
@@ -8432,7 +8566,7 @@ Tenant ${tenant2}`));
|
|
|
8432
8566
|
case "iam": {
|
|
8433
8567
|
const { v } = await inquirer3.prompt([{ type: "confirm", name: "v", message: "Enable Users & groups?", default: !!iam?.iam_enabled }]);
|
|
8434
8568
|
await admin({ method: "PATCH", path: `${base2}/iam`, body: { enabled: v }, summary: `IAM enforcement \u2192 ${v ? "on" : "off"}` });
|
|
8435
|
-
console.log(
|
|
8569
|
+
console.log(import_chalk41.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
|
|
8436
8570
|
break;
|
|
8437
8571
|
}
|
|
8438
8572
|
case "cors": {
|
|
@@ -8445,11 +8579,11 @@ Tenant ${tenant2}`));
|
|
|
8445
8579
|
if (v === "") break;
|
|
8446
8580
|
const parsed = v === "null" ? null : safeJson(v);
|
|
8447
8581
|
if (parsed === void 0) {
|
|
8448
|
-
console.log(
|
|
8582
|
+
console.log(import_chalk41.default.yellow(" Not valid JSON \u2014 unchanged."));
|
|
8449
8583
|
break;
|
|
8450
8584
|
}
|
|
8451
8585
|
await admin({ method: "PUT", path: `${base2}/cors`, body: { cors: parsed }, summary: "Set tenant CORS" });
|
|
8452
|
-
console.log(
|
|
8586
|
+
console.log(import_chalk41.default.green(" CORS updated."));
|
|
8453
8587
|
break;
|
|
8454
8588
|
}
|
|
8455
8589
|
case "emails":
|
|
@@ -8473,15 +8607,15 @@ async function loginMethodsMenu(teamId, tenant2, base2) {
|
|
|
8473
8607
|
const choices = [];
|
|
8474
8608
|
for (const c of appClients) {
|
|
8475
8609
|
const nP = (c.providers ?? []).length || c.providers_count || 0;
|
|
8476
|
-
choices.push({ name: `${
|
|
8610
|
+
choices.push({ name: `${import_chalk41.default.cyan("APIblaze-hosted")} ${import_chalk41.default.bold(c.name ?? c.clientId)} ${import_chalk41.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk41.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
|
|
8477
8611
|
}
|
|
8478
8612
|
for (const i of issuers) {
|
|
8479
|
-
choices.push({ name: `${
|
|
8613
|
+
choices.push({ name: `${import_chalk41.default.cyan("Your own \u2014 JWT ")} ${import_chalk41.default.bold(i.iss)} ${import_chalk41.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
|
|
8480
8614
|
}
|
|
8481
8615
|
if (opaque?.endpoint) {
|
|
8482
|
-
choices.push({ name: `${
|
|
8616
|
+
choices.push({ name: `${import_chalk41.default.cyan("Your own \u2014 opaque")} ${import_chalk41.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
|
|
8483
8617
|
}
|
|
8484
|
-
if (!choices.length) console.log(
|
|
8618
|
+
if (!choices.length) console.log(import_chalk41.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
|
|
8485
8619
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
8486
8620
|
type: "list",
|
|
8487
8621
|
name: "pick",
|
|
@@ -8521,9 +8655,9 @@ async function addLoginMethod(teamId, tenant2, base2) {
|
|
|
8521
8655
|
message: "How do people log in?",
|
|
8522
8656
|
pageSize: 8,
|
|
8523
8657
|
choices: [
|
|
8524
|
-
{ name: `APIblaze hosted login page ${
|
|
8525
|
-
{ name: `Your own hosted login \u2014 JWT ${
|
|
8526
|
-
{ name: `Your own login \u2014 opaque token ${
|
|
8658
|
+
{ name: `APIblaze hosted login page ${import_chalk41.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
|
|
8659
|
+
{ name: `Your own hosted login \u2014 JWT ${import_chalk41.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
|
|
8660
|
+
{ name: `Your own login \u2014 opaque token ${import_chalk41.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
|
|
8527
8661
|
{ name: "\u2190 Back", value: null }
|
|
8528
8662
|
]
|
|
8529
8663
|
}]);
|
|
@@ -8547,8 +8681,8 @@ function safeJson(s) {
|
|
|
8547
8681
|
async function emailsMenu(base2, emails) {
|
|
8548
8682
|
const { default: inquirer3 } = await import("inquirer");
|
|
8549
8683
|
console.log();
|
|
8550
|
-
if (!emails.length) console.log(
|
|
8551
|
-
for (const e of emails) console.log(` ${
|
|
8684
|
+
if (!emails.length) console.log(import_chalk41.default.dim(" No consumer-admin emails."));
|
|
8685
|
+
for (const e of emails) console.log(` ${import_chalk41.default.bold(e.email ?? e)} ${import_chalk41.default.dim(e.status ?? "")}`);
|
|
8552
8686
|
const { act } = await inquirer3.prompt([{
|
|
8553
8687
|
type: "list",
|
|
8554
8688
|
name: "act",
|
|
@@ -8563,7 +8697,7 @@ async function emailsMenu(base2, emails) {
|
|
|
8563
8697
|
if (act === "add") {
|
|
8564
8698
|
const { email } = await inquirer3.prompt([{ type: "input", name: "email", message: "Email:", validate: (s) => /.+@.+\..+/.test(s) || "not an email" }]);
|
|
8565
8699
|
await admin({ method: "POST", path: `${base2}/admin-emails`, body: { email }, summary: `Add consumer-admin ${email}` });
|
|
8566
|
-
console.log(
|
|
8700
|
+
console.log(import_chalk41.default.green(` ${email} added.`));
|
|
8567
8701
|
} else {
|
|
8568
8702
|
const { e } = await inquirer3.prompt([{
|
|
8569
8703
|
type: "list",
|
|
@@ -8573,7 +8707,7 @@ async function emailsMenu(base2, emails) {
|
|
|
8573
8707
|
}]);
|
|
8574
8708
|
if (!e) return;
|
|
8575
8709
|
await admin({ method: "DELETE", path: `${base2}/admin-emails/${encodeURIComponent(e)}`, summary: `Remove consumer-admin ${e}` });
|
|
8576
|
-
console.log(
|
|
8710
|
+
console.log(import_chalk41.default.green(` ${e} removed.`));
|
|
8577
8711
|
}
|
|
8578
8712
|
}
|
|
8579
8713
|
async function addIssuer(base2) {
|
|
@@ -8594,19 +8728,19 @@ async function addIssuer(base2) {
|
|
|
8594
8728
|
body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
|
|
8595
8729
|
summary: `Add external issuer ${a.iss.trim()}`
|
|
8596
8730
|
});
|
|
8597
|
-
console.log(
|
|
8731
|
+
console.log(import_chalk41.default.green(" JWT login method saved."));
|
|
8598
8732
|
}
|
|
8599
8733
|
async function issuerHome(base2, issuer) {
|
|
8600
8734
|
const { default: inquirer3 } = await import("inquirer");
|
|
8601
8735
|
console.log(`
|
|
8602
|
-
${
|
|
8736
|
+
${import_chalk41.default.bold(issuer.iss)} ${import_chalk41.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
|
|
8603
8737
|
const { act } = await inquirer3.prompt([{
|
|
8604
8738
|
type: "list",
|
|
8605
8739
|
name: "act",
|
|
8606
8740
|
message: "This JWT login method:",
|
|
8607
8741
|
choices: [
|
|
8608
8742
|
{ name: "Replace it (re-enter details)", value: "edit" },
|
|
8609
|
-
{ name:
|
|
8743
|
+
{ name: import_chalk41.default.red("Delete it"), value: "rm" },
|
|
8610
8744
|
{ name: "\u2190 Back", value: "back" }
|
|
8611
8745
|
]
|
|
8612
8746
|
}]);
|
|
@@ -8622,7 +8756,7 @@ async function issuerHome(base2, issuer) {
|
|
|
8622
8756
|
path: `${base2}/external-issuers?iss=${encodeURIComponent(issuer.iss)}&aud=${encodeURIComponent(issuer.aud)}`,
|
|
8623
8757
|
summary: `Delete issuer ${issuer.iss}`
|
|
8624
8758
|
});
|
|
8625
|
-
console.log(
|
|
8759
|
+
console.log(import_chalk41.default.green(" Deleted."));
|
|
8626
8760
|
}
|
|
8627
8761
|
async function setOpaque(base2, cur) {
|
|
8628
8762
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -8631,19 +8765,19 @@ async function setOpaque(base2, cur) {
|
|
|
8631
8765
|
{ type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
|
|
8632
8766
|
]);
|
|
8633
8767
|
await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
|
|
8634
|
-
console.log(
|
|
8768
|
+
console.log(import_chalk41.default.green(" Opaque login method set."));
|
|
8635
8769
|
}
|
|
8636
8770
|
async function opaqueHome(base2, cur) {
|
|
8637
8771
|
const { default: inquirer3 } = await import("inquirer");
|
|
8638
8772
|
console.log(`
|
|
8639
|
-
${
|
|
8773
|
+
${import_chalk41.default.bold(cur.endpoint)} ${import_chalk41.default.dim(cur.method ?? "GET")}`);
|
|
8640
8774
|
const { act } = await inquirer3.prompt([{
|
|
8641
8775
|
type: "list",
|
|
8642
8776
|
name: "act",
|
|
8643
8777
|
message: "This opaque login method:",
|
|
8644
8778
|
choices: [
|
|
8645
8779
|
{ name: "Replace it", value: "edit" },
|
|
8646
|
-
{ name:
|
|
8780
|
+
{ name: import_chalk41.default.red("Delete it"), value: "rm" },
|
|
8647
8781
|
{ name: "\u2190 Back", value: "back" }
|
|
8648
8782
|
]
|
|
8649
8783
|
}]);
|
|
@@ -8653,7 +8787,7 @@ async function opaqueHome(base2, cur) {
|
|
|
8653
8787
|
return;
|
|
8654
8788
|
}
|
|
8655
8789
|
await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
|
|
8656
|
-
console.log(
|
|
8790
|
+
console.log(import_chalk41.default.green(" Deleted."));
|
|
8657
8791
|
}
|
|
8658
8792
|
async function clientHome(base2, summary) {
|
|
8659
8793
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -8672,13 +8806,13 @@ async function clientHome(base2, summary) {
|
|
|
8672
8806
|
message: `${c.name ?? id}:`,
|
|
8673
8807
|
pageSize: 12,
|
|
8674
8808
|
choices: [
|
|
8675
|
-
{ name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${
|
|
8676
|
-
{ name: `Callback URLs: ${cb.length ?
|
|
8677
|
-
{ name: `Scopes: ${scopes.length ?
|
|
8809
|
+
{ name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk41.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
|
|
8810
|
+
{ name: `Callback URLs: ${cb.length ? import_chalk41.default.cyan(cb.join(", ")) : import_chalk41.default.dim("(none)")}`, value: "callbacks" },
|
|
8811
|
+
{ name: `Scopes: ${scopes.length ? import_chalk41.default.cyan(scopes.join(" ")) : import_chalk41.default.dim("(defaults)")}`, value: "scopes" },
|
|
8678
8812
|
{ name: `Token expiries: access ${c.accessTokenExpiry ?? 3600}s \xB7 id ${c.idTokenExpiry ?? 3600}s \xB7 refresh ${c.refreshTokenExpiry ?? 2592e3}s`, value: "expiries" },
|
|
8679
8813
|
{ name: "Reveal client secret", value: "secret" },
|
|
8680
8814
|
{ name: "Rotate client secret", value: "rotate" },
|
|
8681
|
-
{ name:
|
|
8815
|
+
{ name: import_chalk41.default.red("Delete this app client"), value: "delete" },
|
|
8682
8816
|
{ name: "\u2190 Back", value: "back" }
|
|
8683
8817
|
]
|
|
8684
8818
|
}]);
|
|
@@ -8691,13 +8825,13 @@ async function clientHome(base2, summary) {
|
|
|
8691
8825
|
case "callbacks": {
|
|
8692
8826
|
const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Callback URLs (comma-separated):", default: cb.join(", ") }]);
|
|
8693
8827
|
await admin({ method: "PATCH", path: cBase, body: { authorizedCallbackUrls: parseList(v) }, summary: "Update callback URLs" });
|
|
8694
|
-
console.log(
|
|
8828
|
+
console.log(import_chalk41.default.green(" Callbacks updated."));
|
|
8695
8829
|
break;
|
|
8696
8830
|
}
|
|
8697
8831
|
case "scopes": {
|
|
8698
8832
|
const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Scopes (space/comma-separated):", default: scopes.join(" ") }]);
|
|
8699
8833
|
await admin({ method: "PATCH", path: cBase, body: { scopes: v.split(/[\s,]+/).filter(Boolean) }, summary: "Update scopes" });
|
|
8700
|
-
console.log(
|
|
8834
|
+
console.log(import_chalk41.default.green(" Scopes updated."));
|
|
8701
8835
|
break;
|
|
8702
8836
|
}
|
|
8703
8837
|
case "expiries": {
|
|
@@ -8712,14 +8846,14 @@ async function clientHome(base2, summary) {
|
|
|
8712
8846
|
body: { accessTokenExpiry: Number(a.access), idTokenExpiry: Number(a.id), refreshTokenExpiry: Number(a.refresh) },
|
|
8713
8847
|
summary: "Update token expiries"
|
|
8714
8848
|
});
|
|
8715
|
-
console.log(
|
|
8849
|
+
console.log(import_chalk41.default.green(" Expiries updated."));
|
|
8716
8850
|
break;
|
|
8717
8851
|
}
|
|
8718
8852
|
case "secret": {
|
|
8719
8853
|
const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: "Print the client secret to this terminal?", default: false }]);
|
|
8720
8854
|
if (!sure) break;
|
|
8721
8855
|
const s = await admin({ method: "GET", path: `${cBase}/secret`, summary: "Reveal client secret" });
|
|
8722
|
-
console.log(` ${
|
|
8856
|
+
console.log(` ${import_chalk41.default.bold("client_secret")}: ${import_chalk41.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
|
|
8723
8857
|
break;
|
|
8724
8858
|
}
|
|
8725
8859
|
case "rotate": {
|
|
@@ -8727,14 +8861,14 @@ async function clientHome(base2, summary) {
|
|
|
8727
8861
|
if (!sure) break;
|
|
8728
8862
|
const fresh = randomSecret();
|
|
8729
8863
|
await admin({ method: "PATCH", path: cBase, body: { clientSecret: fresh }, summary: "Rotate client secret" });
|
|
8730
|
-
console.log(` New ${
|
|
8864
|
+
console.log(` New ${import_chalk41.default.bold("client_secret")}: ${import_chalk41.default.green(fresh)} ${import_chalk41.default.dim("(store it now)")}`);
|
|
8731
8865
|
break;
|
|
8732
8866
|
}
|
|
8733
8867
|
case "delete": {
|
|
8734
8868
|
const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: `Delete app client "${c.name ?? id}"? Consumers logged in through it will lose access.`, default: false }]);
|
|
8735
8869
|
if (!sure) break;
|
|
8736
8870
|
await admin({ method: "DELETE", path: cBase, summary: `Delete app client ${id}` });
|
|
8737
|
-
console.log(
|
|
8871
|
+
console.log(import_chalk41.default.green(" App client deleted."));
|
|
8738
8872
|
return;
|
|
8739
8873
|
}
|
|
8740
8874
|
}
|
|
@@ -8761,9 +8895,9 @@ async function providersMenu(cBase, clientLabel) {
|
|
|
8761
8895
|
const providers = Array.isArray(raw) ? raw : [];
|
|
8762
8896
|
console.log();
|
|
8763
8897
|
for (const p of providers) {
|
|
8764
|
-
console.log(` ${
|
|
8898
|
+
console.log(` ${import_chalk41.default.bold(p.type)} ${import_chalk41.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
|
|
8765
8899
|
}
|
|
8766
|
-
if (!providers.length) console.log(
|
|
8900
|
+
if (!providers.length) console.log(import_chalk41.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
|
|
8767
8901
|
const { act } = await inquirer3.prompt([{
|
|
8768
8902
|
type: "list",
|
|
8769
8903
|
name: "act",
|
|
@@ -8821,23 +8955,23 @@ async function providersMenu(cBase, clientLabel) {
|
|
|
8821
8955
|
body.targetServerToken = routing;
|
|
8822
8956
|
}
|
|
8823
8957
|
await admin({ method: "POST", path: `${cBase}/providers`, body, summary: `Add ${type} login provider` });
|
|
8824
|
-
console.log(
|
|
8958
|
+
console.log(import_chalk41.default.green(` ${type} provider added.`));
|
|
8825
8959
|
} else {
|
|
8826
8960
|
const { p } = await inquirer3.prompt([{
|
|
8827
8961
|
type: "list",
|
|
8828
8962
|
name: "p",
|
|
8829
8963
|
message: act === "rm" ? "Remove which provider?" : "Reveal which secret?",
|
|
8830
|
-
choices: [...providers.map((x) => ({ name: `${x.type} ${
|
|
8964
|
+
choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk41.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
|
|
8831
8965
|
}]);
|
|
8832
8966
|
if (!p) continue;
|
|
8833
8967
|
if (act === "rm") {
|
|
8834
8968
|
const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: `Remove the ${p.type} provider? Consumers using it can no longer sign in.`, default: false }]);
|
|
8835
8969
|
if (!sure) continue;
|
|
8836
8970
|
await admin({ method: "DELETE", path: `${cBase}/providers/${encodeURIComponent(p.id)}`, summary: `Remove ${p.type} provider` });
|
|
8837
|
-
console.log(
|
|
8971
|
+
console.log(import_chalk41.default.green(` ${p.type} removed.`));
|
|
8838
8972
|
} else {
|
|
8839
8973
|
const s = await admin({ method: "GET", path: `${cBase}/providers/${encodeURIComponent(p.id)}/secret`, summary: `Reveal ${p.type} provider secret` });
|
|
8840
|
-
console.log(` ${
|
|
8974
|
+
console.log(` ${import_chalk41.default.bold("client_secret")}: ${import_chalk41.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
|
|
8841
8975
|
}
|
|
8842
8976
|
}
|
|
8843
8977
|
}
|
|
@@ -8845,7 +8979,7 @@ async function providersMenu(cBase, clientLabel) {
|
|
|
8845
8979
|
|
|
8846
8980
|
// src/commands/spec.ts
|
|
8847
8981
|
var fs11 = __toESM(require("fs"));
|
|
8848
|
-
var
|
|
8982
|
+
var import_chalk42 = __toESM(require("chalk"));
|
|
8849
8983
|
var import_ora18 = __toESM(require("ora"));
|
|
8850
8984
|
init_admin();
|
|
8851
8985
|
init_api();
|
|
@@ -8862,14 +8996,14 @@ async function runSpecGet(project, opts) {
|
|
|
8862
8996
|
}
|
|
8863
8997
|
async function runSpecSet(project, opts) {
|
|
8864
8998
|
if (!opts.file) {
|
|
8865
|
-
console.error(
|
|
8999
|
+
console.error(import_chalk42.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
|
|
8866
9000
|
process.exit(1);
|
|
8867
9001
|
}
|
|
8868
9002
|
let specContent;
|
|
8869
9003
|
try {
|
|
8870
9004
|
specContent = fs11.readFileSync(opts.file, "utf-8");
|
|
8871
9005
|
} catch {
|
|
8872
|
-
console.error(
|
|
9006
|
+
console.error(import_chalk42.default.red(`Cannot read file: ${opts.file}`));
|
|
8873
9007
|
process.exit(1);
|
|
8874
9008
|
}
|
|
8875
9009
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8898,23 +9032,23 @@ async function runSpecSet(project, opts) {
|
|
|
8898
9032
|
function printSpecChangeReport(report, projectName) {
|
|
8899
9033
|
const r = report.routes;
|
|
8900
9034
|
if (r) {
|
|
8901
|
-
for (const a of r.added) console.log(
|
|
8902
|
-
for (const d of r.removed) console.log(
|
|
8903
|
-
for (const rn of r.renamed ?? []) console.log(
|
|
8904
|
-
for (const m of r.modified ?? []) console.log(
|
|
9035
|
+
for (const a of r.added) console.log(import_chalk42.default.green(` + ${a}`));
|
|
9036
|
+
for (const d of r.removed) console.log(import_chalk42.default.red(` \u2212 ${d}`));
|
|
9037
|
+
for (const rn of r.renamed ?? []) console.log(import_chalk42.default.yellow(` ~ ${rn.from} \u2192 ${rn.to}`));
|
|
9038
|
+
for (const m of r.modified ?? []) console.log(import_chalk42.default.dim(` \xB1 ${m} (params/schema changed)`));
|
|
8905
9039
|
}
|
|
8906
|
-
if (report.applied?.mcp_regenerated) console.log(
|
|
8907
|
-
if (report.applied?.candidates_cleared) console.log(
|
|
9040
|
+
if (report.applied?.mcp_regenerated) console.log(import_chalk42.default.dim(" MCP catalogue regenerated."));
|
|
9041
|
+
if (report.applied?.candidates_cleared) console.log(import_chalk42.default.dim(` ${report.applied.candidates_cleared} route candidate(s) now documented \u2014 cleared.`));
|
|
8908
9042
|
for (const item of report.attention ?? []) {
|
|
8909
|
-
console.log(
|
|
9043
|
+
console.log(import_chalk42.default.yellow(` \u26A0 ${item.detail}`));
|
|
8910
9044
|
if (item.suggestion?.carry_from && item.suggestion.carry_to) {
|
|
8911
|
-
console.log(
|
|
9045
|
+
console.log(import_chalk42.default.dim(` Fix: apiblaze spec carry ${projectName} --method ${item.suggestion.method} --from "${item.suggestion.carry_from}" --to "${item.suggestion.carry_to}"`));
|
|
8912
9046
|
}
|
|
8913
9047
|
}
|
|
8914
9048
|
}
|
|
8915
9049
|
async function runSpecCarry(project, opts) {
|
|
8916
9050
|
if (!opts.method || !opts.from || !opts.to) {
|
|
8917
|
-
console.error(
|
|
9051
|
+
console.error(import_chalk42.default.red("--method, --from and --to are required."));
|
|
8918
9052
|
process.exit(1);
|
|
8919
9053
|
}
|
|
8920
9054
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8936,7 +9070,7 @@ async function runSpecCarry(project, opts) {
|
|
|
8936
9070
|
}
|
|
8937
9071
|
async function runSpecDeleteRule(project, opts) {
|
|
8938
9072
|
if (!opts.method || !opts.route) {
|
|
8939
|
-
console.error(
|
|
9073
|
+
console.error(import_chalk42.default.red("--method and --route are required."));
|
|
8940
9074
|
process.exit(1);
|
|
8941
9075
|
}
|
|
8942
9076
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -8956,14 +9090,14 @@ async function runSpecDeleteRule(project, opts) {
|
|
|
8956
9090
|
}
|
|
8957
9091
|
|
|
8958
9092
|
// src/commands/agent.ts
|
|
8959
|
-
var
|
|
9093
|
+
var import_chalk44 = __toESM(require("chalk"));
|
|
8960
9094
|
var import_ora19 = __toESM(require("ora"));
|
|
8961
9095
|
init_auth();
|
|
8962
9096
|
init_admin();
|
|
8963
9097
|
init_resolve();
|
|
8964
9098
|
|
|
8965
9099
|
// src/lib/tools.ts
|
|
8966
|
-
var
|
|
9100
|
+
var import_chalk43 = __toESM(require("chalk"));
|
|
8967
9101
|
init_admin();
|
|
8968
9102
|
init_api();
|
|
8969
9103
|
init_resolve();
|
|
@@ -8983,15 +9117,15 @@ var TOOLS = [
|
|
|
8983
9117
|
const key = keys.dev ?? Object.values(keys)[0];
|
|
8984
9118
|
const url = `https://${a.name}.abz.run/${version2}/dev`;
|
|
8985
9119
|
const tryIt = buildTryItCurl(url, auth, key);
|
|
8986
|
-
const lines = [` ${
|
|
8987
|
-
if (res.devPortal) lines.push(` ${
|
|
9120
|
+
const lines = [` ${import_chalk43.default.dim("Proxy URL:")} ${import_chalk43.default.bold(url)}`];
|
|
9121
|
+
if (res.devPortal) lines.push(` ${import_chalk43.default.dim("Dev portal:")} ${res.devPortal}`);
|
|
8988
9122
|
const envs = Object.keys(keys);
|
|
8989
9123
|
if (envs.length) {
|
|
8990
|
-
lines.push("", ` ${
|
|
9124
|
+
lines.push("", ` ${import_chalk43.default.bold("API keys")} ${import_chalk43.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
|
|
8991
9125
|
const w = Math.max(...envs.map((e) => e.length));
|
|
8992
|
-
for (const env of envs) lines.push(` ${
|
|
9126
|
+
for (const env of envs) lines.push(` ${import_chalk43.default.cyan(env.padEnd(w))} ${import_chalk43.default.green(keys[env])}`);
|
|
8993
9127
|
}
|
|
8994
|
-
if (tryIt) lines.push("", ` ${
|
|
9128
|
+
if (tryIt) lines.push("", ` ${import_chalk43.default.dim("Try it:")}`, ` ${import_chalk43.default.cyan(tryIt)}`);
|
|
8995
9129
|
return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
|
|
8996
9130
|
}
|
|
8997
9131
|
},
|
|
@@ -9147,17 +9281,17 @@ function truncate(value, max = 1500) {
|
|
|
9147
9281
|
}
|
|
9148
9282
|
function printCost(resp) {
|
|
9149
9283
|
const line = formatBilling(resp.billing);
|
|
9150
|
-
if (line) console.log(
|
|
9284
|
+
if (line) console.log(import_chalk44.default.magenta(` ${line}`) + import_chalk44.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
|
|
9151
9285
|
}
|
|
9152
9286
|
async function runAgent(opts) {
|
|
9153
9287
|
requireAuth();
|
|
9154
9288
|
const { teamId, teamName } = await resolveTeam(opts.team);
|
|
9155
9289
|
const { default: inquirer3 } = await import("inquirer");
|
|
9156
|
-
console.log(
|
|
9157
|
-
console.log(
|
|
9290
|
+
console.log(import_chalk44.default.bold("APIblaze agent") + import_chalk44.default.dim(` \xB7 team ${teamName ?? teamId}`));
|
|
9291
|
+
console.log(import_chalk44.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
|
|
9158
9292
|
const history = [];
|
|
9159
9293
|
while (true) {
|
|
9160
|
-
const { input } = await inquirer3.prompt([{ type: "input", name: "input", message:
|
|
9294
|
+
const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk44.default.cyan("you") + " \u203A" }]);
|
|
9161
9295
|
const text = (input ?? "").trim();
|
|
9162
9296
|
if (!text) continue;
|
|
9163
9297
|
if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
|
|
@@ -9171,14 +9305,14 @@ async function runAgent(opts) {
|
|
|
9171
9305
|
} catch (err) {
|
|
9172
9306
|
spinner.stop();
|
|
9173
9307
|
if (err instanceof ApiError && err.status === 402) {
|
|
9174
|
-
console.log(
|
|
9308
|
+
console.log(import_chalk44.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
|
|
9175
9309
|
break;
|
|
9176
9310
|
}
|
|
9177
9311
|
throw err;
|
|
9178
9312
|
}
|
|
9179
9313
|
history.push({ role: "assistant", content: resp.raw });
|
|
9180
9314
|
printCost(resp);
|
|
9181
|
-
if (resp.reply) console.log(
|
|
9315
|
+
if (resp.reply) console.log(import_chalk44.default.green("agent") + " \u203A " + resp.reply);
|
|
9182
9316
|
if (!resp.action) break;
|
|
9183
9317
|
const tool = findTool(resp.action.tool);
|
|
9184
9318
|
if (!tool) {
|
|
@@ -9203,11 +9337,11 @@ async function runAgent(opts) {
|
|
|
9203
9337
|
}
|
|
9204
9338
|
renderTrace();
|
|
9205
9339
|
if (step === MAX_TOOL_STEPS - 1) {
|
|
9206
|
-
console.log(
|
|
9340
|
+
console.log(import_chalk44.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
|
|
9207
9341
|
}
|
|
9208
9342
|
}
|
|
9209
9343
|
}
|
|
9210
|
-
console.log(
|
|
9344
|
+
console.log(import_chalk44.default.dim("\nBye."));
|
|
9211
9345
|
}
|
|
9212
9346
|
|
|
9213
9347
|
// src/commands/config-browse.ts
|
|
@@ -9502,11 +9636,11 @@ function dig(blob, dotted) {
|
|
|
9502
9636
|
}
|
|
9503
9637
|
var readSetting = (s, cfg) => s.read ? s.read(cfg) : dig(cfg, s.key);
|
|
9504
9638
|
function show(v) {
|
|
9505
|
-
if (v === void 0) return
|
|
9506
|
-
if (v === null) return
|
|
9507
|
-
if (typeof v === "object") return
|
|
9508
|
-
if (typeof v === "boolean") return v ?
|
|
9509
|
-
return
|
|
9639
|
+
if (v === void 0) return import_chalk45.default.dim("(unset)");
|
|
9640
|
+
if (v === null) return import_chalk45.default.dim("null");
|
|
9641
|
+
if (typeof v === "object") return import_chalk45.default.cyan(JSON.stringify(v));
|
|
9642
|
+
if (typeof v === "boolean") return v ? import_chalk45.default.green("on") : import_chalk45.default.red("off");
|
|
9643
|
+
return import_chalk45.default.cyan(String(v));
|
|
9510
9644
|
}
|
|
9511
9645
|
function parseValue(raw) {
|
|
9512
9646
|
if (raw === "true") return true;
|
|
@@ -9548,10 +9682,10 @@ async function patchSetting(proj2, s, value, cfg) {
|
|
|
9548
9682
|
}
|
|
9549
9683
|
}
|
|
9550
9684
|
var loginFirst = (what) => {
|
|
9551
|
-
console.log(
|
|
9685
|
+
console.log(import_chalk45.default.yellow(`
|
|
9552
9686
|
Log in first to ${what}.`));
|
|
9553
|
-
console.log(
|
|
9554
|
-
console.log(
|
|
9687
|
+
console.log(import_chalk45.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
|
|
9688
|
+
console.log(import_chalk45.default.dim(" anonymously and want to bring it into your account.\n"));
|
|
9555
9689
|
};
|
|
9556
9690
|
async function runConfig(project, key, value, opts) {
|
|
9557
9691
|
const creds = loadCredentials();
|
|
@@ -9568,9 +9702,9 @@ async function runConfig(project, key, value, opts) {
|
|
|
9568
9702
|
}
|
|
9569
9703
|
const setting = SETTINGS.find((s) => s.key === key);
|
|
9570
9704
|
if (!setting) {
|
|
9571
|
-
console.error(
|
|
9572
|
-
console.error(
|
|
9573
|
-
console.error(
|
|
9705
|
+
console.error(import_chalk45.default.red(`Unknown setting "${key}".`));
|
|
9706
|
+
console.error(import_chalk45.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
|
|
9707
|
+
console.error(import_chalk45.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
|
|
9574
9708
|
process.exit(1);
|
|
9575
9709
|
}
|
|
9576
9710
|
if (value === void 0) {
|
|
@@ -9585,7 +9719,7 @@ async function pickProject(teamId) {
|
|
|
9585
9719
|
const { getProjects: getProjects2 } = await Promise.resolve().then(() => (init_api(), api_exports));
|
|
9586
9720
|
const projects = await getProjects2(teamId).catch(() => []);
|
|
9587
9721
|
if (!projects.length) {
|
|
9588
|
-
console.error(
|
|
9722
|
+
console.error(import_chalk45.default.red("No projects in this team. Create one: `npx apiblaze create`."));
|
|
9589
9723
|
process.exit(1);
|
|
9590
9724
|
}
|
|
9591
9725
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -9593,7 +9727,7 @@ async function pickProject(teamId) {
|
|
|
9593
9727
|
type: "list",
|
|
9594
9728
|
name: "picked",
|
|
9595
9729
|
message: "Which project?",
|
|
9596
|
-
choices: projects.map((p) => ({ name: `${p.projectName} ${
|
|
9730
|
+
choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk45.default.dim("v" + p.apiVersion)}`, value: p }))
|
|
9597
9731
|
}]);
|
|
9598
9732
|
return { projectId: picked.projectId, projectName: picked.projectName, apiVersion: picked.apiVersion, teamId, tenant: picked.tenant };
|
|
9599
9733
|
}
|
|
@@ -9604,25 +9738,25 @@ function printAll(proj2, cfg, json) {
|
|
|
9604
9738
|
console.log(JSON.stringify(out, null, 2));
|
|
9605
9739
|
return;
|
|
9606
9740
|
}
|
|
9607
|
-
console.log(
|
|
9741
|
+
console.log(import_chalk45.default.bold(`
|
|
9608
9742
|
${proj2.projectName} v${proj2.apiVersion} \u2014 settings
|
|
9609
9743
|
`));
|
|
9610
9744
|
for (const group2 of SETTING_GROUPS) {
|
|
9611
|
-
console.log(
|
|
9745
|
+
console.log(import_chalk45.default.bold(group2));
|
|
9612
9746
|
for (const s of SETTINGS.filter((x) => x.group === group2)) {
|
|
9613
|
-
console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${
|
|
9747
|
+
console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk45.default.dim(s.desc)}`);
|
|
9614
9748
|
}
|
|
9615
9749
|
console.log();
|
|
9616
9750
|
}
|
|
9617
|
-
console.log(
|
|
9751
|
+
console.log(import_chalk45.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
|
|
9618
9752
|
}
|
|
9619
9753
|
async function discoveryMenu(project) {
|
|
9620
9754
|
const { default: inquirer3 } = await import("inquirer");
|
|
9621
|
-
console.log(
|
|
9755
|
+
console.log(import_chalk45.default.bold(`
|
|
9622
9756
|
APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
|
|
9623
9757
|
`));
|
|
9624
|
-
console.log(
|
|
9625
|
-
console.log(
|
|
9758
|
+
console.log(import_chalk45.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
|
|
9759
|
+
console.log(import_chalk45.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
|
|
9626
9760
|
for (; ; ) {
|
|
9627
9761
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
9628
9762
|
type: "list",
|
|
@@ -9630,13 +9764,13 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
|
|
|
9630
9764
|
message: "Explore:",
|
|
9631
9765
|
pageSize: 20,
|
|
9632
9766
|
choices: [
|
|
9633
|
-
new inquirer3.Separator(
|
|
9767
|
+
new inquirer3.Separator(import_chalk45.default.bold("\u2014 Settings \u2014")),
|
|
9634
9768
|
...SETTING_GROUPS.map((g) => ({
|
|
9635
|
-
name: `${g} ${
|
|
9769
|
+
name: `${g} ${import_chalk45.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
|
|
9636
9770
|
value: { kind: "settings", g }
|
|
9637
9771
|
})),
|
|
9638
|
-
new inquirer3.Separator(
|
|
9639
|
-
...FEATURES.map((f) => ({ name: `${f.label} ${
|
|
9772
|
+
new inquirer3.Separator(import_chalk45.default.bold("\u2014 Features \u2014")),
|
|
9773
|
+
...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk45.default.dim(f.desc)}`, value: { kind: "feature", f } })),
|
|
9640
9774
|
new inquirer3.Separator(),
|
|
9641
9775
|
{ name: "Exit", value: { kind: "exit" } }
|
|
9642
9776
|
]
|
|
@@ -9645,24 +9779,24 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
|
|
|
9645
9779
|
if (pick2.kind === "settings") {
|
|
9646
9780
|
console.log();
|
|
9647
9781
|
for (const s of SETTINGS.filter((x) => x.group === pick2.g)) {
|
|
9648
|
-
console.log(` ${
|
|
9649
|
-
console.log(` ${
|
|
9782
|
+
console.log(` ${import_chalk45.default.bold(s.label.padEnd(28))} ${import_chalk45.default.dim(s.desc)}`);
|
|
9783
|
+
console.log(` ${import_chalk45.default.dim(" key: " + s.key)}`);
|
|
9650
9784
|
}
|
|
9651
9785
|
loginFirst("view or change these settings");
|
|
9652
9786
|
} else {
|
|
9653
9787
|
const f = pick2.f;
|
|
9654
9788
|
console.log(`
|
|
9655
|
-
${
|
|
9789
|
+
${import_chalk45.default.bold(f.label)} \u2014 ${f.desc}`);
|
|
9656
9790
|
loginFirst(`use ${f.label.toLowerCase()}`);
|
|
9657
9791
|
}
|
|
9658
9792
|
}
|
|
9659
9793
|
}
|
|
9660
9794
|
async function navigator(proj2, cfg, opts) {
|
|
9661
9795
|
const { default: inquirer3 } = await import("inquirer");
|
|
9662
|
-
console.log(
|
|
9796
|
+
console.log(import_chalk45.default.bold(`
|
|
9663
9797
|
${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
|
|
9664
9798
|
`));
|
|
9665
|
-
console.log(
|
|
9799
|
+
console.log(import_chalk45.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
|
|
9666
9800
|
let blob = cfg;
|
|
9667
9801
|
for (; ; ) {
|
|
9668
9802
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
@@ -9671,10 +9805,10 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
|
|
|
9671
9805
|
message: "Where to?",
|
|
9672
9806
|
pageSize: 20,
|
|
9673
9807
|
choices: [
|
|
9674
|
-
new inquirer3.Separator(
|
|
9808
|
+
new inquirer3.Separator(import_chalk45.default.bold("\u2014 Settings \u2014")),
|
|
9675
9809
|
...SETTING_GROUPS.map((g) => ({ name: g, value: { kind: "settings", g } })),
|
|
9676
|
-
new inquirer3.Separator(
|
|
9677
|
-
...FEATURES.map((f) => ({ name: `${f.label} ${
|
|
9810
|
+
new inquirer3.Separator(import_chalk45.default.bold("\u2014 Features \u2014")),
|
|
9811
|
+
...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk45.default.dim(f.desc)}`, value: { kind: f.go } })),
|
|
9678
9812
|
new inquirer3.Separator(),
|
|
9679
9813
|
{ name: "Show all settings", value: { kind: "list" } },
|
|
9680
9814
|
{ name: "Exit", value: { kind: "exit" } }
|
|
@@ -9714,7 +9848,7 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
|
|
|
9714
9848
|
}
|
|
9715
9849
|
}
|
|
9716
9850
|
} catch (err) {
|
|
9717
|
-
console.error(
|
|
9851
|
+
console.error(import_chalk45.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
9718
9852
|
}
|
|
9719
9853
|
}
|
|
9720
9854
|
}
|
|
@@ -9728,7 +9862,7 @@ async function settingsGroup(proj2, cfg, group2) {
|
|
|
9728
9862
|
message: group2 + ":",
|
|
9729
9863
|
pageSize: 16,
|
|
9730
9864
|
choices: [
|
|
9731
|
-
...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${
|
|
9865
|
+
...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk45.default.dim(s2.desc)}`, value: s2 })),
|
|
9732
9866
|
new inquirer3.Separator(),
|
|
9733
9867
|
{ name: "\u2190 Back", value: null }
|
|
9734
9868
|
]
|
|
@@ -9746,7 +9880,7 @@ async function settingsGroup(proj2, cfg, group2) {
|
|
|
9746
9880
|
} else if (s.type === "number") {
|
|
9747
9881
|
const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: `${s.label} (number):`, default: readSetting(s, cfg) }]);
|
|
9748
9882
|
if (v === "" || Number.isNaN(Number(v))) {
|
|
9749
|
-
console.log(
|
|
9883
|
+
console.log(import_chalk45.default.yellow(" Not a number \u2014 unchanged."));
|
|
9750
9884
|
continue;
|
|
9751
9885
|
}
|
|
9752
9886
|
value = Number(v);
|
|
@@ -9827,7 +9961,7 @@ async function buildCondition(phase) {
|
|
|
9827
9961
|
const items = [];
|
|
9828
9962
|
for (; ; ) {
|
|
9829
9963
|
const a = await inquirer3.prompt([
|
|
9830
|
-
{ type: "input", name: "source", message: `Condition field ${
|
|
9964
|
+
{ type: "input", name: "source", message: `Condition field ${import_chalk45.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
|
|
9831
9965
|
{ type: "list", name: "operator", message: "Operator:", choices: [
|
|
9832
9966
|
"eq",
|
|
9833
9967
|
"neq",
|
|
@@ -9858,7 +9992,7 @@ async function buildCondition(phase) {
|
|
|
9858
9992
|
function showCondition(cond) {
|
|
9859
9993
|
if (!Array.isArray(cond) || !cond.length) return "";
|
|
9860
9994
|
const s = cond.map((c) => `${c.source} ${c.operator}${c.value !== void 0 ? ` "${c.value}"` : ""}${c.logicOp ? ` ${c.logicOp}` : ""}`).join(" ");
|
|
9861
|
-
return
|
|
9995
|
+
return import_chalk45.default.dim(` when ${s}`);
|
|
9862
9996
|
}
|
|
9863
9997
|
async function transformsMenu(proj2) {
|
|
9864
9998
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -9867,12 +10001,12 @@ async function transformsMenu(proj2) {
|
|
|
9867
10001
|
const out = await admin({ method: "GET", path: base2, summary: "List transform rules" });
|
|
9868
10002
|
const rules = out?.rules ?? [];
|
|
9869
10003
|
console.log();
|
|
9870
|
-
if (!rules.length) console.log(
|
|
10004
|
+
if (!rules.length) console.log(import_chalk45.default.dim(" No transform rules yet."));
|
|
9871
10005
|
for (const r of rules) {
|
|
9872
10006
|
const a = r.action ?? {};
|
|
9873
10007
|
const fns = [...a.source_fns ?? [], ...a.dest_fns ?? []].map((f) => f.fn);
|
|
9874
|
-
const what = a.type === "hardcode" ? `${a.destination} = "${a.value}"` : a.type === "remove" ? `remove ${a.field}` : `${a.source} \u2192 ${a.destination}${a.lookup ? " (mapped)" : ""}${fns.length ?
|
|
9875
|
-
console.log(` ${r.enabled ?
|
|
10008
|
+
const what = a.type === "hardcode" ? `${a.destination} = "${a.value}"` : a.type === "remove" ? `remove ${a.field}` : `${a.source} \u2192 ${a.destination}${a.lookup ? " (mapped)" : ""}${fns.length ? import_chalk45.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
|
|
10009
|
+
console.log(` ${r.enabled ? import_chalk45.default.green("\u25CF") : import_chalk45.default.dim("\u25CB")} ${import_chalk45.default.bold(r.name)} ${import_chalk45.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
|
|
9876
10010
|
}
|
|
9877
10011
|
const { act } = await inquirer3.prompt([{
|
|
9878
10012
|
type: "list",
|
|
@@ -9884,7 +10018,7 @@ async function transformsMenu(proj2) {
|
|
|
9884
10018
|
{ name: "Enable/disable a rule", value: "toggle" },
|
|
9885
10019
|
{ name: "Delete a rule", value: "delete" }
|
|
9886
10020
|
] : [],
|
|
9887
|
-
{ name:
|
|
10021
|
+
{ name: import_chalk45.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
|
|
9888
10022
|
{ name: "\u2190 Back", value: "back" }
|
|
9889
10023
|
]
|
|
9890
10024
|
}]);
|
|
@@ -9897,11 +10031,11 @@ async function transformsMenu(proj2) {
|
|
|
9897
10031
|
}]);
|
|
9898
10032
|
const body = parseValue(raw);
|
|
9899
10033
|
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
9900
|
-
console.log(
|
|
10034
|
+
console.log(import_chalk45.default.yellow(" Not a JSON object \u2014 skipped."));
|
|
9901
10035
|
continue;
|
|
9902
10036
|
}
|
|
9903
10037
|
await admin({ method: "POST", path: base2, body, summary: "Create transform rule (raw JSON)" });
|
|
9904
|
-
console.log(
|
|
10038
|
+
console.log(import_chalk45.default.green(" Rule created."));
|
|
9905
10039
|
continue;
|
|
9906
10040
|
}
|
|
9907
10041
|
if (act === "add") {
|
|
@@ -9917,7 +10051,7 @@ async function transformsMenu(proj2) {
|
|
|
9917
10051
|
{ name: "Remove a field", value: "remove" }
|
|
9918
10052
|
] }
|
|
9919
10053
|
]);
|
|
9920
|
-
const fieldHint =
|
|
10054
|
+
const fieldHint = import_chalk45.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
|
|
9921
10055
|
let action2;
|
|
9922
10056
|
if (ans.kind === "hardcode") {
|
|
9923
10057
|
const a = await inquirer3.prompt([
|
|
@@ -9964,16 +10098,16 @@ async function transformsMenu(proj2) {
|
|
|
9964
10098
|
type: "list",
|
|
9965
10099
|
name: "rule",
|
|
9966
10100
|
message: act === "toggle" ? "Which rule?" : "Delete which rule?",
|
|
9967
|
-
choices: [...rules.map((r) => ({ name: `${r.name} ${
|
|
10101
|
+
choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk45.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
|
|
9968
10102
|
}]);
|
|
9969
10103
|
if (!rule) continue;
|
|
9970
10104
|
if (act === "toggle") {
|
|
9971
10105
|
const flipped = { ...rule, enabled: rule.enabled === false };
|
|
9972
10106
|
await admin({ method: "PUT", path: `${base2}/${rule.id}`, body: flipped, summary: `${flipped.enabled ? "Enable" : "Disable"} transform "${rule.name}"` });
|
|
9973
|
-
console.log(
|
|
10107
|
+
console.log(import_chalk45.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
|
|
9974
10108
|
} else {
|
|
9975
10109
|
await admin({ method: "DELETE", path: `${base2}/${rule.id}`, summary: `Delete transform "${rule.name}"` });
|
|
9976
|
-
console.log(
|
|
10110
|
+
console.log(import_chalk45.default.green(` ${rule.name} deleted.`));
|
|
9977
10111
|
}
|
|
9978
10112
|
}
|
|
9979
10113
|
}
|
|
@@ -9985,9 +10119,9 @@ async function mappingsMenu(proj2) {
|
|
|
9985
10119
|
const out = await admin({ method: "GET", path: base2, summary: "List mapping tables" });
|
|
9986
10120
|
const tables = out?.mappings ?? out?.tables ?? [];
|
|
9987
10121
|
console.log();
|
|
9988
|
-
if (!tables.length) console.log(
|
|
10122
|
+
if (!tables.length) console.log(import_chalk45.default.dim(" No mapping tables yet."));
|
|
9989
10123
|
for (const t of tables) {
|
|
9990
|
-
console.log(` ${
|
|
10124
|
+
console.log(` ${import_chalk45.default.bold(t.name)} ${import_chalk45.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
|
|
9991
10125
|
}
|
|
9992
10126
|
const { act } = await inquirer3.prompt([{
|
|
9993
10127
|
type: "list",
|
|
@@ -10007,11 +10141,11 @@ async function mappingsMenu(proj2) {
|
|
|
10007
10141
|
]);
|
|
10008
10142
|
const entries2 = parseValue(a.entries);
|
|
10009
10143
|
if (!Array.isArray(entries2)) {
|
|
10010
|
-
console.log(
|
|
10144
|
+
console.log(import_chalk45.default.yellow(" Entries must be a JSON array \u2014 not created."));
|
|
10011
10145
|
continue;
|
|
10012
10146
|
}
|
|
10013
10147
|
await admin({ method: "POST", path: base2, body: { name: a.name, entries: entries2 }, summary: `Create mapping table "${a.name}"` });
|
|
10014
|
-
console.log(
|
|
10148
|
+
console.log(import_chalk45.default.green(` Table "${a.name}" created.`));
|
|
10015
10149
|
} else {
|
|
10016
10150
|
const { table } = await inquirer3.prompt([{
|
|
10017
10151
|
type: "list",
|
|
@@ -10021,7 +10155,7 @@ async function mappingsMenu(proj2) {
|
|
|
10021
10155
|
}]);
|
|
10022
10156
|
if (!table) continue;
|
|
10023
10157
|
await admin({ method: "DELETE", path: `${base2}/${table.id}`, summary: `Delete mapping table "${table.name}"` });
|
|
10024
|
-
console.log(
|
|
10158
|
+
console.log(import_chalk45.default.green(` ${table.name} deleted.`));
|
|
10025
10159
|
}
|
|
10026
10160
|
}
|
|
10027
10161
|
}
|
|
@@ -10032,14 +10166,14 @@ async function tenantsMenu(proj2, opts) {
|
|
|
10032
10166
|
const out = await admin({ method: "GET", path: base2, summary: "List attached tenants" });
|
|
10033
10167
|
const tenants = out?.tenants ?? [];
|
|
10034
10168
|
console.log();
|
|
10035
|
-
if (!tenants.length) console.log(
|
|
10036
|
-
for (const t of tenants) console.log(` ${
|
|
10169
|
+
if (!tenants.length) console.log(import_chalk45.default.dim(" No tenants attached (consumers use the default tenant)."));
|
|
10170
|
+
for (const t of tenants) console.log(` ${import_chalk45.default.bold(t.tenant_name ?? t.name)} ${import_chalk45.default.dim(t.display_name ?? "")}`);
|
|
10037
10171
|
const { act } = await inquirer3.prompt([{
|
|
10038
10172
|
type: "list",
|
|
10039
10173
|
name: "act",
|
|
10040
10174
|
message: "Tenants:",
|
|
10041
10175
|
choices: [
|
|
10042
|
-
{ name: `Manage a tenant\u2026 ${
|
|
10176
|
+
{ name: `Manage a tenant\u2026 ${import_chalk45.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
|
|
10043
10177
|
{ name: "Attach a tenant to this project", value: "attach" },
|
|
10044
10178
|
...tenants.length ? [{ name: "Detach a tenant from this project", value: "detach" }] : [],
|
|
10045
10179
|
{ name: "\u2190 Back", value: "back" }
|
|
@@ -10062,7 +10196,7 @@ async function tenantsMenu(proj2, opts) {
|
|
|
10062
10196
|
}]);
|
|
10063
10197
|
if (!t) continue;
|
|
10064
10198
|
await admin({ method: "DELETE", path: `${base2}/${encodeURIComponent(t.tenant_name ?? t.name)}`, summary: `Detach tenant ${t.tenant_name ?? t.name}` });
|
|
10065
|
-
console.log(
|
|
10199
|
+
console.log(import_chalk45.default.green(` Detached ${t.tenant_name ?? t.name}.`));
|
|
10066
10200
|
}
|
|
10067
10201
|
}
|
|
10068
10202
|
}
|
|
@@ -10105,7 +10239,7 @@ async function specMenu(proj2, opts) {
|
|
|
10105
10239
|
choices: [
|
|
10106
10240
|
{ name: "Print the stored spec", value: "get" },
|
|
10107
10241
|
{ name: "Refresh the spec from its source", value: "refresh" },
|
|
10108
|
-
{ name:
|
|
10242
|
+
{ name: import_chalk45.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
|
|
10109
10243
|
{ name: "\u2190 Back", value: "back" }
|
|
10110
10244
|
]
|
|
10111
10245
|
}]);
|
|
@@ -10113,7 +10247,7 @@ async function specMenu(proj2, opts) {
|
|
|
10113
10247
|
if (act === "get") await runSpecGet(proj2.projectName, { team: opts.team, apiversion: proj2.apiVersion });
|
|
10114
10248
|
else if (act === "refresh") {
|
|
10115
10249
|
await admin({ method: "POST", path: `/projects/${proj2.projectId}/${proj2.apiVersion}/refresh-spec`, summary: "Refresh spec from source" });
|
|
10116
|
-
console.log(
|
|
10250
|
+
console.log(import_chalk45.default.green(" Spec refresh triggered."));
|
|
10117
10251
|
} else await runOpenapi(proj2.projectName, proj2.apiVersion);
|
|
10118
10252
|
}
|
|
10119
10253
|
async function agentsMenu(proj2, opts) {
|
|
@@ -10138,7 +10272,7 @@ async function agentsMenu(proj2, opts) {
|
|
|
10138
10272
|
}
|
|
10139
10273
|
|
|
10140
10274
|
// src/commands/group.ts
|
|
10141
|
-
var
|
|
10275
|
+
var import_chalk46 = __toESM(require("chalk"));
|
|
10142
10276
|
var import_ora21 = __toESM(require("ora"));
|
|
10143
10277
|
init_auth();
|
|
10144
10278
|
init_admin();
|
|
@@ -10232,7 +10366,7 @@ async function userByRefOrCreate(t, ref) {
|
|
|
10232
10366
|
if (!ref.includes("@")) throw e;
|
|
10233
10367
|
const created = await t.call("/v1/admin/users", "POST", { email: ref.trim().toLowerCase() });
|
|
10234
10368
|
if (!created?.abz_sub) throw e;
|
|
10235
|
-
console.log(
|
|
10369
|
+
console.log(import_chalk46.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
|
|
10236
10370
|
return { abz_sub: created.abz_sub, email: created.email ?? ref, display_name: null };
|
|
10237
10371
|
}
|
|
10238
10372
|
}
|
|
@@ -10240,11 +10374,11 @@ async function runGroupList(opts) {
|
|
|
10240
10374
|
const t = await resolveTransport(opts);
|
|
10241
10375
|
const groups = await listGroups(t);
|
|
10242
10376
|
if (opts.json) return void console.log(JSON.stringify(groups));
|
|
10243
|
-
if (!groups.length) return void console.log(
|
|
10244
|
-
console.log(
|
|
10377
|
+
if (!groups.length) return void console.log(import_chalk46.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
|
|
10378
|
+
console.log(import_chalk46.default.dim(`Tenant ${t.tenant}:`));
|
|
10245
10379
|
for (const g of groups) {
|
|
10246
|
-
const sealed = g.name === "apiblaze_admins" ?
|
|
10247
|
-
console.log(` ${
|
|
10380
|
+
const sealed = g.name === "apiblaze_admins" ? import_chalk46.default.dim(" (admins \u2014 managed by allowlist)") : "";
|
|
10381
|
+
console.log(` ${import_chalk46.default.bold(g.name)} ${import_chalk46.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
|
|
10248
10382
|
}
|
|
10249
10383
|
}
|
|
10250
10384
|
async function runGroupCreate(name, opts) {
|
|
@@ -10272,7 +10406,7 @@ async function runGroupCreate(name, opts) {
|
|
|
10272
10406
|
const spinner = (0, import_ora21.default)(`Creating group ${name}...`).start();
|
|
10273
10407
|
try {
|
|
10274
10408
|
await t.call("/v1/admin/groups", "POST", { name, admins: [adminSub] });
|
|
10275
|
-
spinner.succeed(`Group ${
|
|
10409
|
+
spinner.succeed(`Group ${import_chalk46.default.bold(name)} created in ${t.tenant}.`);
|
|
10276
10410
|
} catch (e) {
|
|
10277
10411
|
spinner.fail("Create failed.");
|
|
10278
10412
|
throw e;
|
|
@@ -10284,7 +10418,7 @@ async function runGroupDelete(name, opts) {
|
|
|
10284
10418
|
const spinner = (0, import_ora21.default)(`Deleting group ${name}...`).start();
|
|
10285
10419
|
try {
|
|
10286
10420
|
await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}`, "DELETE");
|
|
10287
|
-
spinner.succeed(`Group ${
|
|
10421
|
+
spinner.succeed(`Group ${import_chalk46.default.bold(name)} deleted.`);
|
|
10288
10422
|
} catch (e) {
|
|
10289
10423
|
spinner.fail("Delete failed.");
|
|
10290
10424
|
throw e;
|
|
@@ -10297,11 +10431,11 @@ async function runGroupMembers(name, opts) {
|
|
|
10297
10431
|
const subs = await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/subgroups`);
|
|
10298
10432
|
if (opts.json) return void console.log(JSON.stringify({ ...detail, subgroups: subs?.subgroups ?? [] }));
|
|
10299
10433
|
const members = detail?.members ?? [];
|
|
10300
|
-
console.log(
|
|
10301
|
-
for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ?
|
|
10302
|
-
if (!members.length) console.log(
|
|
10434
|
+
console.log(import_chalk46.default.bold(`${g.name}`) + import_chalk46.default.dim(` (${t.tenant})`));
|
|
10435
|
+
for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk46.default.cyan("group-admin") : import_chalk46.default.dim("member")}`);
|
|
10436
|
+
if (!members.length) console.log(import_chalk46.default.dim(" no members"));
|
|
10303
10437
|
const sg = subs?.subgroups ?? [];
|
|
10304
|
-
if (sg.length) console.log(
|
|
10438
|
+
if (sg.length) console.log(import_chalk46.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
|
|
10305
10439
|
}
|
|
10306
10440
|
async function runGroupAddUser(userRef, groupName, opts) {
|
|
10307
10441
|
const t = await resolveTransport(opts);
|
|
@@ -10311,7 +10445,7 @@ async function runGroupAddUser(userRef, groupName, opts) {
|
|
|
10311
10445
|
const spinner = (0, import_ora21.default)(`Adding ${label2(u)} to ${g.name}...`).start();
|
|
10312
10446
|
try {
|
|
10313
10447
|
await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members`, "POST", { abz_sub: u.abz_sub, role });
|
|
10314
|
-
spinner.succeed(`${
|
|
10448
|
+
spinner.succeed(`${import_chalk46.default.bold(label2(u))} added to ${import_chalk46.default.bold(g.name)} as ${role}.`);
|
|
10315
10449
|
} catch (e) {
|
|
10316
10450
|
spinner.fail("Add failed.");
|
|
10317
10451
|
throw e;
|
|
@@ -10323,7 +10457,7 @@ async function runGroupRemoveUser(userRef, groupName, opts) {
|
|
|
10323
10457
|
const spinner = (0, import_ora21.default)(`Removing ${label2(u)} from ${g.name}...`).start();
|
|
10324
10458
|
try {
|
|
10325
10459
|
await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members/_?abz_sub=${encodeURIComponent(u.abz_sub)}`, "DELETE");
|
|
10326
|
-
spinner.succeed(`${
|
|
10460
|
+
spinner.succeed(`${import_chalk46.default.bold(label2(u))} removed from ${import_chalk46.default.bold(g.name)}.`);
|
|
10327
10461
|
} catch (e) {
|
|
10328
10462
|
spinner.fail("Remove failed.");
|
|
10329
10463
|
throw e;
|
|
@@ -10335,7 +10469,7 @@ async function runGroupAddGroup(childName, parentName, opts) {
|
|
|
10335
10469
|
const spinner = (0, import_ora21.default)(`Nesting ${child.name} under ${parent.name}...`).start();
|
|
10336
10470
|
try {
|
|
10337
10471
|
await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups`, "POST", { child_group_id: child.id });
|
|
10338
|
-
spinner.succeed(`${
|
|
10472
|
+
spinner.succeed(`${import_chalk46.default.bold(child.name)} is now a subgroup of ${import_chalk46.default.bold(parent.name)}.`);
|
|
10339
10473
|
} catch (e) {
|
|
10340
10474
|
spinner.fail("Nest failed.");
|
|
10341
10475
|
throw e;
|
|
@@ -10347,7 +10481,7 @@ async function runGroupRemoveGroup(childName, parentName, opts) {
|
|
|
10347
10481
|
const spinner = (0, import_ora21.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
|
|
10348
10482
|
try {
|
|
10349
10483
|
await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups/${encodeURIComponent(child.id)}`, "DELETE");
|
|
10350
|
-
spinner.succeed(`${
|
|
10484
|
+
spinner.succeed(`${import_chalk46.default.bold(child.name)} un-nested from ${import_chalk46.default.bold(parent.name)}.`);
|
|
10351
10485
|
} catch (e) {
|
|
10352
10486
|
spinner.fail("Un-nest failed.");
|
|
10353
10487
|
throw e;
|
|
@@ -10358,18 +10492,18 @@ async function runGroupUsers(opts) {
|
|
|
10358
10492
|
const users = await listUsers(t);
|
|
10359
10493
|
const observed = await t.call("/v1/admin/observed-identities").catch(() => ({ identities: [] }));
|
|
10360
10494
|
if (opts.json) return void console.log(JSON.stringify({ users, observed: observed?.identities ?? [] }));
|
|
10361
|
-
console.log(
|
|
10362
|
-
for (const u of users) console.log(` ${label2(u)} ${
|
|
10363
|
-
if (!users.length) console.log(
|
|
10495
|
+
console.log(import_chalk46.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
|
|
10496
|
+
for (const u of users) console.log(` ${label2(u)} ${import_chalk46.default.dim(u.abz_sub)}`);
|
|
10497
|
+
if (!users.length) console.log(import_chalk46.default.dim(" no users yet"));
|
|
10364
10498
|
const fresh = (observed?.identities ?? []).filter((o) => !o.provisioned);
|
|
10365
10499
|
if (fresh.length) {
|
|
10366
|
-
console.log(
|
|
10367
|
-
for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${
|
|
10500
|
+
console.log(import_chalk46.default.dim("Seen in traffic (not yet users):"));
|
|
10501
|
+
for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk46.default.dim(o.source_label ?? "")}`);
|
|
10368
10502
|
}
|
|
10369
10503
|
}
|
|
10370
10504
|
|
|
10371
10505
|
// src/commands/key.ts
|
|
10372
|
-
var
|
|
10506
|
+
var import_chalk47 = __toESM(require("chalk"));
|
|
10373
10507
|
var import_ora22 = __toESM(require("ora"));
|
|
10374
10508
|
init_caller();
|
|
10375
10509
|
async function runApikeysMenu(opts) {
|
|
@@ -10399,11 +10533,11 @@ async function runKeyList(opts) {
|
|
|
10399
10533
|
return;
|
|
10400
10534
|
}
|
|
10401
10535
|
if (!keys.length) {
|
|
10402
|
-
console.log(
|
|
10536
|
+
console.log(import_chalk47.default.yellow("No developer keys."));
|
|
10403
10537
|
return;
|
|
10404
10538
|
}
|
|
10405
10539
|
for (const k of keys) {
|
|
10406
|
-
console.log(` ${
|
|
10540
|
+
console.log(` ${import_chalk47.default.bold(k.key_id ?? k.id)} ${import_chalk47.default.dim(k.description ?? "")} ${import_chalk47.default.dim(k.expires_at ?? "no expiry")}`);
|
|
10407
10541
|
}
|
|
10408
10542
|
}
|
|
10409
10543
|
async function runKeyMint(opts) {
|
|
@@ -10425,9 +10559,9 @@ async function runKeyMint(opts) {
|
|
|
10425
10559
|
console.log(JSON.stringify(out));
|
|
10426
10560
|
return;
|
|
10427
10561
|
}
|
|
10428
|
-
console.log(` ${
|
|
10429
|
-
console.log(` ${
|
|
10430
|
-
if (out?.expires_at) console.log(` ${
|
|
10562
|
+
console.log(` ${import_chalk47.default.bold("key_id")}: ${out?.key_id}`);
|
|
10563
|
+
console.log(` ${import_chalk47.default.bold("key")}: ${import_chalk47.default.green(out?.key)} ${import_chalk47.default.dim("(shown once \u2014 store it now)")}`);
|
|
10564
|
+
if (out?.expires_at) console.log(` ${import_chalk47.default.dim("expires:")} ${out.expires_at}`);
|
|
10431
10565
|
} catch (err) {
|
|
10432
10566
|
spinner.fail("Mint failed.");
|
|
10433
10567
|
throw err;
|
|
@@ -10454,7 +10588,7 @@ async function runKeyRevoke(keyId, opts) {
|
|
|
10454
10588
|
init_iam();
|
|
10455
10589
|
|
|
10456
10590
|
// src/commands/admins.ts
|
|
10457
|
-
var
|
|
10591
|
+
var import_chalk48 = __toESM(require("chalk"));
|
|
10458
10592
|
var import_ora23 = __toESM(require("ora"));
|
|
10459
10593
|
init_caller();
|
|
10460
10594
|
function requireTenant(opts) {
|
|
@@ -10482,13 +10616,13 @@ async function runAdminsList(opts) {
|
|
|
10482
10616
|
return;
|
|
10483
10617
|
}
|
|
10484
10618
|
if (!admins2.length) {
|
|
10485
|
-
console.log(
|
|
10619
|
+
console.log(import_chalk48.default.yellow(`No tenant admins for ${tenant2} yet.`));
|
|
10486
10620
|
return;
|
|
10487
10621
|
}
|
|
10488
10622
|
for (const a of admins2) {
|
|
10489
10623
|
const email = typeof a === "string" ? a : a.email;
|
|
10490
10624
|
const flags = [a.active === false ? "pending" : null, a.pinned ? "pinned" : null].filter(Boolean).join(", ");
|
|
10491
|
-
console.log(` ${
|
|
10625
|
+
console.log(` ${import_chalk48.default.bold(email)}${flags ? import_chalk48.default.dim(` (${flags})`) : ""}`);
|
|
10492
10626
|
}
|
|
10493
10627
|
}
|
|
10494
10628
|
async function runAdminsAdd(email, opts) {
|
|
@@ -10503,9 +10637,9 @@ async function runAdminsAdd(email, opts) {
|
|
|
10503
10637
|
body: { email },
|
|
10504
10638
|
summary: `Add ${email} to tenant ${tenant2} admins`
|
|
10505
10639
|
});
|
|
10506
|
-
spinner?.succeed(`${
|
|
10640
|
+
spinner?.succeed(`${import_chalk48.default.bold(email)} is now a tenant admin of ${import_chalk48.default.bold(tenant2)}.`);
|
|
10507
10641
|
if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
|
|
10508
|
-
else console.log(
|
|
10642
|
+
else console.log(import_chalk48.default.dim(" Reload the Users & Groups widget \u2014 access flips from \u201Cpending\u201D to ready."));
|
|
10509
10643
|
} catch (err) {
|
|
10510
10644
|
spinner?.fail("Add failed.");
|
|
10511
10645
|
throw err;
|
|
@@ -10522,7 +10656,7 @@ async function runAdminsRemove(email, opts) {
|
|
|
10522
10656
|
path: `${base(teamId, tenant2)}/${encodeURIComponent(email)}`,
|
|
10523
10657
|
summary: `Remove ${email} from tenant ${tenant2} admins`
|
|
10524
10658
|
});
|
|
10525
|
-
spinner?.succeed(`Removed ${
|
|
10659
|
+
spinner?.succeed(`Removed ${import_chalk48.default.bold(email)} from the tenant admins of ${import_chalk48.default.bold(tenant2)}.`);
|
|
10526
10660
|
} catch (err) {
|
|
10527
10661
|
spinner?.fail("Remove failed.");
|
|
10528
10662
|
throw err;
|
|
@@ -10530,7 +10664,7 @@ async function runAdminsRemove(email, opts) {
|
|
|
10530
10664
|
}
|
|
10531
10665
|
|
|
10532
10666
|
// src/commands/preapprove.ts
|
|
10533
|
-
var
|
|
10667
|
+
var import_chalk49 = __toESM(require("chalk"));
|
|
10534
10668
|
var import_ora24 = __toESM(require("ora"));
|
|
10535
10669
|
async function runPreapprove(who, opts) {
|
|
10536
10670
|
const tenant2 = await resolveProducerTenant(opts.tenant);
|
|
@@ -10538,14 +10672,14 @@ async function runPreapprove(who, opts) {
|
|
|
10538
10672
|
const rules = await listPreapprovalRules(tenant2);
|
|
10539
10673
|
if (opts.json) return void console.log(JSON.stringify(rules, null, 2));
|
|
10540
10674
|
if (!rules.length) {
|
|
10541
|
-
console.log(
|
|
10542
|
-
console.log(
|
|
10675
|
+
console.log(import_chalk49.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
|
|
10676
|
+
console.log(import_chalk49.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
|
|
10543
10677
|
return;
|
|
10544
10678
|
}
|
|
10545
|
-
console.log(
|
|
10679
|
+
console.log(import_chalk49.default.dim(`Pre-approved for ${import_chalk49.default.bold(tenant2)}:`));
|
|
10546
10680
|
for (const r of rules) {
|
|
10547
|
-
const tag = r.kind === "domain" ?
|
|
10548
|
-
const grp = r.groups?.length ?
|
|
10681
|
+
const tag = r.kind === "domain" ? import_chalk49.default.cyan("@" + r.value + " (whole domain)") : r.value;
|
|
10682
|
+
const grp = r.groups?.length ? import_chalk49.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
|
|
10549
10683
|
console.log(` ${tag}${grp}`);
|
|
10550
10684
|
}
|
|
10551
10685
|
return;
|
|
@@ -10556,17 +10690,17 @@ async function runPreapprove(who, opts) {
|
|
|
10556
10690
|
if (opts.remove) {
|
|
10557
10691
|
const spinner2 = (0, import_ora24.default)(`Removing ${who} from ${tenant2}\u2026`).start();
|
|
10558
10692
|
const { removed, value } = await removePreapprovalRule(tenant2, who);
|
|
10559
|
-
if (removed) spinner2.succeed(`${
|
|
10560
|
-
else spinner2.warn(`No pre-approval rule for ${
|
|
10693
|
+
if (removed) spinner2.succeed(`${import_chalk49.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
|
|
10694
|
+
else spinner2.warn(`No pre-approval rule for ${import_chalk49.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
|
|
10561
10695
|
return;
|
|
10562
10696
|
}
|
|
10563
10697
|
const spinner = (0, import_ora24.default)(`Pre-approving ${who} for ${tenant2}\u2026`).start();
|
|
10564
10698
|
try {
|
|
10565
10699
|
const { kind, value } = await addPreapprovalRule(tenant2, who, opts.group);
|
|
10566
10700
|
const what = kind === "domain" ? `Anyone @${value}` : value;
|
|
10567
|
-
spinner.succeed(`${
|
|
10568
|
-
if (opts.group?.length) console.log(
|
|
10569
|
-
console.log(
|
|
10701
|
+
spinner.succeed(`${import_chalk49.default.bold(what)} can now sign in to ${import_chalk49.default.bold(tenant2)}.`);
|
|
10702
|
+
if (opts.group?.length) console.log(import_chalk49.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
|
|
10703
|
+
console.log(import_chalk49.default.dim(` See the full list: apiblaze preapprove --list`));
|
|
10570
10704
|
} catch (err) {
|
|
10571
10705
|
spinner.fail("Could not add the rule.");
|
|
10572
10706
|
throw err;
|
|
@@ -10574,7 +10708,7 @@ async function runPreapprove(who, opts) {
|
|
|
10574
10708
|
}
|
|
10575
10709
|
|
|
10576
10710
|
// src/commands/consumer.ts
|
|
10577
|
-
var
|
|
10711
|
+
var import_chalk50 = __toESM(require("chalk"));
|
|
10578
10712
|
var import_ora25 = __toESM(require("ora"));
|
|
10579
10713
|
init_admin();
|
|
10580
10714
|
init_resolve();
|
|
@@ -10596,7 +10730,7 @@ async function consumerFetch(creds, suffix, init) {
|
|
|
10596
10730
|
function requireConsumer2() {
|
|
10597
10731
|
const c = loadConsumer();
|
|
10598
10732
|
if (!c) {
|
|
10599
|
-
console.error(
|
|
10733
|
+
console.error(import_chalk50.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
|
|
10600
10734
|
process.exit(1);
|
|
10601
10735
|
}
|
|
10602
10736
|
return c;
|
|
@@ -10607,7 +10741,7 @@ async function runConsumerLogin(opts) {
|
|
|
10607
10741
|
let clientId = opts.client;
|
|
10608
10742
|
if (clientId) {
|
|
10609
10743
|
if (!tenant2) {
|
|
10610
|
-
console.error(
|
|
10744
|
+
console.error(import_chalk50.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
|
|
10611
10745
|
process.exit(1);
|
|
10612
10746
|
}
|
|
10613
10747
|
} else {
|
|
@@ -10625,18 +10759,18 @@ async function runConsumerLogin(opts) {
|
|
|
10625
10759
|
const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
|
|
10626
10760
|
const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
|
|
10627
10761
|
if (!pick2) {
|
|
10628
|
-
console.error(
|
|
10762
|
+
console.error(import_chalk50.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
|
|
10629
10763
|
process.exit(1);
|
|
10630
10764
|
}
|
|
10631
10765
|
clientId = pick2.client_id ?? pick2.clientId;
|
|
10632
10766
|
}
|
|
10633
|
-
console.log(`${
|
|
10767
|
+
console.log(`${import_chalk50.default.cyan("\u2192")} Logging in to ${import_chalk50.default.bold(tenant2)} as a consumer...`);
|
|
10634
10768
|
const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
|
|
10635
10769
|
console.log(`
|
|
10636
|
-
Open: ${
|
|
10637
|
-
console.log(` Code: ${
|
|
10770
|
+
Open: ${import_chalk50.default.underline(verificationUri)}`);
|
|
10771
|
+
console.log(` Code: ${import_chalk50.default.bold(userCode)}
|
|
10638
10772
|
`);
|
|
10639
|
-
console.log(
|
|
10773
|
+
console.log(import_chalk50.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
|
|
10640
10774
|
});
|
|
10641
10775
|
const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
|
|
10642
10776
|
const creds = {
|
|
@@ -10651,7 +10785,7 @@ async function runConsumerLogin(opts) {
|
|
|
10651
10785
|
obtainedAt: Date.now()
|
|
10652
10786
|
};
|
|
10653
10787
|
saveConsumer(creds);
|
|
10654
|
-
console.log(
|
|
10788
|
+
console.log(import_chalk50.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
|
|
10655
10789
|
}
|
|
10656
10790
|
async function runConsumerTokens(opts) {
|
|
10657
10791
|
const creds = requireConsumer2();
|
|
@@ -10664,18 +10798,18 @@ async function runConsumerTokens(opts) {
|
|
|
10664
10798
|
console.log(JSON.stringify({ tenant: fresh.tenant, access_token: fresh.accessToken, refresh_token: fresh.refreshToken, id_token: fresh.idToken, expires_at: new Date(fresh.expiresAt).toISOString() }, null, 2));
|
|
10665
10799
|
return;
|
|
10666
10800
|
}
|
|
10667
|
-
console.log(`${
|
|
10801
|
+
console.log(`${import_chalk50.default.cyan("Consumer")} ${import_chalk50.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk50.default.bold(fresh.tenant)}
|
|
10668
10802
|
`);
|
|
10669
|
-
console.log(`${
|
|
10803
|
+
console.log(`${import_chalk50.default.bold("access_token")} ${import_chalk50.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
|
|
10670
10804
|
${fresh.accessToken}
|
|
10671
10805
|
`);
|
|
10672
|
-
if (fresh.idToken) console.log(`${
|
|
10806
|
+
if (fresh.idToken) console.log(`${import_chalk50.default.bold("id_token")} ${import_chalk50.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
|
|
10673
10807
|
${fresh.idToken}
|
|
10674
10808
|
`);
|
|
10675
|
-
if (fresh.refreshToken) console.log(`${
|
|
10809
|
+
if (fresh.refreshToken) console.log(`${import_chalk50.default.bold("refresh_token")}
|
|
10676
10810
|
${fresh.refreshToken}
|
|
10677
10811
|
`);
|
|
10678
|
-
console.log(
|
|
10812
|
+
console.log(import_chalk50.default.dim("These are your own tokens \u2014 keep them secret."));
|
|
10679
10813
|
}
|
|
10680
10814
|
async function runConsumerApikeys(opts) {
|
|
10681
10815
|
const creds = requireConsumer2();
|
|
@@ -10685,8 +10819,8 @@ async function runConsumerApikeys(opts) {
|
|
|
10685
10819
|
const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
|
|
10686
10820
|
spinner.stop();
|
|
10687
10821
|
if (list.status >= 400) {
|
|
10688
|
-
console.error(
|
|
10689
|
-
if (list.status === 401) console.error(
|
|
10822
|
+
console.error(import_chalk50.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
|
|
10823
|
+
if (list.status === 401) console.error(import_chalk50.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
|
|
10690
10824
|
process.exit(1);
|
|
10691
10825
|
}
|
|
10692
10826
|
const keys = list.data?.keys ?? [];
|
|
@@ -10694,16 +10828,16 @@ async function runConsumerApikeys(opts) {
|
|
|
10694
10828
|
if (opts.json) {
|
|
10695
10829
|
console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
|
|
10696
10830
|
} else if (!keys.length) {
|
|
10697
|
-
console.log(
|
|
10831
|
+
console.log(import_chalk50.default.yellow("No API keys yet."));
|
|
10698
10832
|
} else {
|
|
10699
10833
|
for (const k of keys) {
|
|
10700
10834
|
const clear = revealMap[k.environment]?.key;
|
|
10701
|
-
const shown = clear ?
|
|
10702
|
-
const exp = k.expires_at ?
|
|
10703
|
-
console.log(` ${
|
|
10835
|
+
const shown = clear ? import_chalk50.default.green(clear) : import_chalk50.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
|
|
10836
|
+
const exp = k.expires_at ? import_chalk50.default.dim(`exp ${k.expires_at}`) : import_chalk50.default.dim("no expiry");
|
|
10837
|
+
console.log(` ${import_chalk50.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk50.default.dim(k.description ?? "")}`);
|
|
10704
10838
|
}
|
|
10705
10839
|
if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
|
|
10706
|
-
console.log(
|
|
10840
|
+
console.log(import_chalk50.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
|
|
10707
10841
|
}
|
|
10708
10842
|
}
|
|
10709
10843
|
if (opts.json) return;
|
|
@@ -10725,12 +10859,12 @@ async function runConsumerApikeys(opts) {
|
|
|
10725
10859
|
}
|
|
10726
10860
|
s2.succeed("Key created.");
|
|
10727
10861
|
const key = created.data?.key ?? created.data?.fullKey;
|
|
10728
|
-
if (key) console.log(` ${
|
|
10729
|
-
else console.log(
|
|
10862
|
+
if (key) console.log(` ${import_chalk50.default.green(key)} ${import_chalk50.default.dim("(shown once \u2014 store it now)")}`);
|
|
10863
|
+
else console.log(import_chalk50.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
|
|
10730
10864
|
}
|
|
10731
10865
|
|
|
10732
10866
|
// src/commands/sidecar.ts
|
|
10733
|
-
var
|
|
10867
|
+
var import_chalk51 = __toESM(require("chalk"));
|
|
10734
10868
|
var import_ora26 = __toESM(require("ora"));
|
|
10735
10869
|
var fs12 = __toESM(require("fs"));
|
|
10736
10870
|
var path8 = __toESM(require("path"));
|
|
@@ -10773,7 +10907,7 @@ function upsertEnvLocal(root, token) {
|
|
|
10773
10907
|
}
|
|
10774
10908
|
function installSidecarPackage(root) {
|
|
10775
10909
|
if (fs12.existsSync(path8.join(root, "node_modules", "apiblaze", "package.json"))) {
|
|
10776
|
-
console.log(` ${
|
|
10910
|
+
console.log(` ${import_chalk51.default.green("\u2713")} apiblaze package already installed`);
|
|
10777
10911
|
return;
|
|
10778
10912
|
}
|
|
10779
10913
|
const has = (f) => fs12.existsSync(path8.join(root, f));
|
|
@@ -10784,7 +10918,7 @@ function installSidecarPackage(root) {
|
|
|
10784
10918
|
execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
|
|
10785
10919
|
spinner.succeed("Installed apiblaze (the sidecar runtime).");
|
|
10786
10920
|
} catch {
|
|
10787
|
-
spinner.warn(`Couldn't auto-install \u2014 run ${
|
|
10921
|
+
spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk51.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk51.default.cyan("npm run dev")}.`);
|
|
10788
10922
|
}
|
|
10789
10923
|
}
|
|
10790
10924
|
function readEnvKey(root) {
|
|
@@ -10935,29 +11069,29 @@ async function runAnonymousInit(root, router, opts) {
|
|
|
10935
11069
|
if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
|
|
10936
11070
|
const envState = upsertEnvLocal(root, out.token);
|
|
10937
11071
|
ensureGitignored(root);
|
|
10938
|
-
console.log(` ${
|
|
10939
|
-
console.log(` ${
|
|
11072
|
+
console.log(` ${import_chalk51.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
|
|
11073
|
+
console.log(` ${import_chalk51.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
|
|
10940
11074
|
installSidecarPackage(root);
|
|
10941
11075
|
let inspectorPath = null;
|
|
10942
11076
|
if (!opts.noInspector) {
|
|
10943
11077
|
inspectorPath = generateInspector(root, router);
|
|
10944
|
-
if (inspectorPath) console.log(` ${
|
|
11078
|
+
if (inspectorPath) console.log(` ${import_chalk51.default.green("\u2713")} inspector at ${inspectorPath}`);
|
|
10945
11079
|
}
|
|
10946
11080
|
console.log("");
|
|
10947
|
-
console.log(
|
|
10948
|
-
console.log(` 1. ${
|
|
11081
|
+
console.log(import_chalk51.default.bold("Done (no account needed). What happens next:"));
|
|
11082
|
+
console.log(` 1. ${import_chalk51.default.cyan("npm run dev")} and use your app.`);
|
|
10949
11083
|
console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
|
|
10950
|
-
console.log(` ${
|
|
11084
|
+
console.log(` ${import_chalk51.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
|
|
10951
11085
|
console.log("");
|
|
10952
|
-
console.log(
|
|
10953
|
-
console.log(` ${
|
|
10954
|
-
console.log(
|
|
11086
|
+
console.log(import_chalk51.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
|
|
11087
|
+
console.log(` ${import_chalk51.default.cyan("apiblaze login")} then ${import_chalk51.default.cyan("apiblaze claim")} ${import_chalk51.default.dim("(no code needed here)")}`);
|
|
11088
|
+
console.log(import_chalk51.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
|
|
10955
11089
|
}
|
|
10956
11090
|
async function runSidecar(opts) {
|
|
10957
11091
|
const root = path8.resolve(opts.dir ?? process.cwd());
|
|
10958
11092
|
const detected2 = detectNextProject(root);
|
|
10959
11093
|
if (!detected2.found) {
|
|
10960
|
-
console.log(
|
|
11094
|
+
console.log(import_chalk51.default.yellow(`No Next.js project detected in ${root}.`));
|
|
10961
11095
|
console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
|
|
10962
11096
|
return;
|
|
10963
11097
|
}
|
|
@@ -10968,10 +11102,10 @@ async function runSidecar(opts) {
|
|
|
10968
11102
|
if (!loadCredentials()) {
|
|
10969
11103
|
upsertEnvLocal(root, readEnvKey(root));
|
|
10970
11104
|
ensureGitignored(root);
|
|
10971
|
-
console.log(` ${
|
|
10972
|
-
console.log(` ${
|
|
11105
|
+
console.log(` ${import_chalk51.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
|
|
11106
|
+
console.log(` ${import_chalk51.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
|
|
10973
11107
|
installSidecarPackage(root);
|
|
10974
|
-
console.log(
|
|
11108
|
+
console.log(import_chalk51.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
|
|
10975
11109
|
return;
|
|
10976
11110
|
}
|
|
10977
11111
|
const { teamId, teamName } = await resolveTeam(opts.team);
|
|
@@ -10994,38 +11128,38 @@ async function runSidecar(opts) {
|
|
|
10994
11128
|
throw err;
|
|
10995
11129
|
}
|
|
10996
11130
|
} else {
|
|
10997
|
-
console.log(
|
|
11131
|
+
console.log(import_chalk51.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
|
|
10998
11132
|
}
|
|
10999
11133
|
const envState = upsertEnvLocal(root, token);
|
|
11000
11134
|
ensureGitignored(root);
|
|
11001
|
-
console.log(` ${
|
|
11135
|
+
console.log(` ${import_chalk51.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
|
|
11002
11136
|
const wireState = wireInstrumentation(root);
|
|
11003
|
-
console.log(` ${
|
|
11137
|
+
console.log(` ${import_chalk51.default.green("\u2713")} instrumentation.ts ${wireState}`);
|
|
11004
11138
|
installSidecarPackage(root);
|
|
11005
11139
|
let inspectorPath = null;
|
|
11006
11140
|
if (!opts.noInspector) {
|
|
11007
11141
|
inspectorPath = generateInspector(root, detected2.router);
|
|
11008
|
-
if (inspectorPath) console.log(` ${
|
|
11142
|
+
if (inspectorPath) console.log(` ${import_chalk51.default.green("\u2713")} inspector at ${inspectorPath}`);
|
|
11009
11143
|
}
|
|
11010
11144
|
console.log("");
|
|
11011
|
-
console.log(
|
|
11012
|
-
console.log(` 1. ${
|
|
11013
|
-
console.log(` 2. The origins your app calls appear as ${
|
|
11014
|
-
console.log(` 3. Approve the ones to route: ${
|
|
11145
|
+
console.log(import_chalk51.default.bold("Done. What happens next:"));
|
|
11146
|
+
console.log(` 1. ${import_chalk51.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
|
|
11147
|
+
console.log(` 2. The origins your app calls appear as ${import_chalk51.default.bold("candidates")} \u2014 list them: ${import_chalk51.default.cyan("apiblaze sidecar")}`);
|
|
11148
|
+
console.log(` 3. Approve the ones to route: ${import_chalk51.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
|
|
11015
11149
|
console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
|
|
11016
|
-
if (inspectorPath) console.log(` \u2022 Try it now: open ${
|
|
11017
|
-
if (switchingTeam) console.log(
|
|
11150
|
+
if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk51.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path8.dirname(inspectorPath)} before shipping)`);
|
|
11151
|
+
if (switchingTeam) console.log(import_chalk51.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
|
|
11018
11152
|
console.log("");
|
|
11019
|
-
console.log(
|
|
11020
|
-
console.log(
|
|
11021
|
-
console.log(
|
|
11153
|
+
console.log(import_chalk51.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
|
|
11154
|
+
console.log(import_chalk51.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
|
|
11155
|
+
console.log(import_chalk51.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
|
|
11022
11156
|
console.log("");
|
|
11023
|
-
console.log(
|
|
11024
|
-
console.log(
|
|
11157
|
+
console.log(import_chalk51.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
|
|
11158
|
+
console.log(import_chalk51.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
|
|
11025
11159
|
}
|
|
11026
11160
|
|
|
11027
11161
|
// src/commands/origins.ts
|
|
11028
|
-
var
|
|
11162
|
+
var import_chalk52 = __toESM(require("chalk"));
|
|
11029
11163
|
var import_ora27 = __toESM(require("ora"));
|
|
11030
11164
|
init_admin();
|
|
11031
11165
|
init_resolve();
|
|
@@ -11036,7 +11170,7 @@ async function runOriginsList(opts) {
|
|
|
11036
11170
|
if (!loadCredentials()) {
|
|
11037
11171
|
const cred = loadAnonCred();
|
|
11038
11172
|
if (!cred) {
|
|
11039
|
-
console.log(
|
|
11173
|
+
console.log(import_chalk52.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
|
|
11040
11174
|
return;
|
|
11041
11175
|
}
|
|
11042
11176
|
out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
|
|
@@ -11054,27 +11188,27 @@ async function runOriginsList(opts) {
|
|
|
11054
11188
|
}
|
|
11055
11189
|
const routed = out.routed ?? [];
|
|
11056
11190
|
const candidates = out.candidates ?? [];
|
|
11057
|
-
console.log(
|
|
11191
|
+
console.log(import_chalk52.default.bold(`
|
|
11058
11192
|
Routed through APIblaze (${routed.length})`));
|
|
11059
|
-
if (!routed.length) console.log(
|
|
11060
|
-
for (const r of routed) console.log(` ${
|
|
11061
|
-
console.log(
|
|
11193
|
+
if (!routed.length) console.log(import_chalk52.default.dim(" none yet"));
|
|
11194
|
+
for (const r of routed) console.log(` ${import_chalk52.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk52.default.dim(`\u2192 ${r.project_id}`)}`);
|
|
11195
|
+
console.log(import_chalk52.default.bold(`
|
|
11062
11196
|
Candidates \u2014 going direct, not yet approved (${candidates.length})`));
|
|
11063
|
-
if (!candidates.length) console.log(
|
|
11197
|
+
if (!candidates.length) console.log(import_chalk52.default.dim(" none \u2014 run your app to discover the origins it calls"));
|
|
11064
11198
|
for (const c of candidates) {
|
|
11065
|
-
console.log(` ${
|
|
11199
|
+
console.log(` ${import_chalk52.default.yellow("\u25CB")} ${c.origin} ${import_chalk52.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
|
|
11066
11200
|
}
|
|
11067
11201
|
if (candidates.length) {
|
|
11068
|
-
console.log(
|
|
11202
|
+
console.log(import_chalk52.default.dim(`
|
|
11069
11203
|
Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
|
|
11070
|
-
console.log(
|
|
11204
|
+
console.log(import_chalk52.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
|
|
11071
11205
|
}
|
|
11072
11206
|
}
|
|
11073
11207
|
async function runOriginsApprove(origin, opts) {
|
|
11074
11208
|
if (!loadCredentials()) {
|
|
11075
11209
|
const cred = loadAnonCred();
|
|
11076
11210
|
if (!cred) {
|
|
11077
|
-
console.error(
|
|
11211
|
+
console.error(import_chalk52.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
|
|
11078
11212
|
process.exit(1);
|
|
11079
11213
|
}
|
|
11080
11214
|
const spinner2 = (0, import_ora27.default)(`Approving ${origin} (anonymous)...`).start();
|
|
@@ -11127,13 +11261,13 @@ async function runOriginsRemove(origin, opts) {
|
|
|
11127
11261
|
}
|
|
11128
11262
|
|
|
11129
11263
|
// src/commands/op.ts
|
|
11130
|
-
var
|
|
11264
|
+
var import_chalk54 = __toESM(require("chalk"));
|
|
11131
11265
|
init_auth();
|
|
11132
11266
|
init_trace();
|
|
11133
11267
|
init_types();
|
|
11134
11268
|
|
|
11135
11269
|
// src/commands/op-billing.ts
|
|
11136
|
-
var
|
|
11270
|
+
var import_chalk53 = __toESM(require("chalk"));
|
|
11137
11271
|
init_admin();
|
|
11138
11272
|
var SANDBOX = {
|
|
11139
11273
|
teamId: "team_1782844865835_zujrf",
|
|
@@ -11192,7 +11326,7 @@ async function rowsForRays(project, version2, tenant2, rays) {
|
|
|
11192
11326
|
}
|
|
11193
11327
|
function printDoors(data) {
|
|
11194
11328
|
const checks = [];
|
|
11195
|
-
console.log(
|
|
11329
|
+
console.log(import_chalk53.default.bold("\n Doors \u2014 is every way in metered?\n"));
|
|
11196
11330
|
const doors = data?.doors ?? [];
|
|
11197
11331
|
const metered = doors.filter((d) => d.verdict === "metered");
|
|
11198
11332
|
const allowed = doors.filter((d) => d.verdict === "allowed-free");
|
|
@@ -11201,29 +11335,29 @@ function printDoors(data) {
|
|
|
11201
11335
|
const errs = data?.errors ?? [];
|
|
11202
11336
|
const routeAuditBroke = errs.some((e) => e.startsWith("zone "));
|
|
11203
11337
|
const devAuditBroke = errs.some((e) => e.startsWith("workers.dev audit"));
|
|
11204
|
-
console.log(
|
|
11205
|
-
for (const d of metered) console.log(
|
|
11206
|
-
console.log(
|
|
11338
|
+
console.log(import_chalk53.default.dim(` ${metered.length} route(s) behind main-proxy (metered)`));
|
|
11339
|
+
for (const d of metered) console.log(import_chalk53.default.green(` \u2713 ${d.pattern}`));
|
|
11340
|
+
console.log(import_chalk53.default.dim(`
|
|
11207
11341
|
${allowed.length} route(s) free ON PURPOSE`));
|
|
11208
11342
|
for (const d of allowed) {
|
|
11209
|
-
console.log(
|
|
11210
|
-
console.log(
|
|
11343
|
+
console.log(import_chalk53.default.cyan(` \u2022 ${d.pattern}`) + import_chalk53.default.dim(` \u2192 ${d.script}`));
|
|
11344
|
+
console.log(import_chalk53.default.dim(` ${d.why}`));
|
|
11211
11345
|
}
|
|
11212
11346
|
if (known.length) {
|
|
11213
|
-
console.log(
|
|
11347
|
+
console.log(import_chalk53.default.yellow(`
|
|
11214
11348
|
${known.length} route(s) KNOWN OPEN \u2014 unmetered, not yet closed`));
|
|
11215
11349
|
for (const d of known) {
|
|
11216
|
-
console.log(
|
|
11217
|
-
console.log(
|
|
11350
|
+
console.log(import_chalk53.default.yellow(` ! ${d.pattern}`) + import_chalk53.default.dim(` \u2192 ${d.script}`));
|
|
11351
|
+
console.log(import_chalk53.default.dim(` ${d.why}`));
|
|
11218
11352
|
}
|
|
11219
11353
|
checks.push({ name: "no known-open doors", status: "KNOWN", detail: `${known.length} unmetered route(s) still open \u2014 see above` });
|
|
11220
11354
|
}
|
|
11221
11355
|
if (stray.length) {
|
|
11222
|
-
console.log(
|
|
11356
|
+
console.log(import_chalk53.default.red(`
|
|
11223
11357
|
${stray.length} STRAY route(s) \u2014 not main-proxy, not on the allowlist`));
|
|
11224
11358
|
for (const d of stray) {
|
|
11225
|
-
console.log(
|
|
11226
|
-
console.log(
|
|
11359
|
+
console.log(import_chalk53.default.red(` \u2717 ${d.pattern}`) + import_chalk53.default.dim(` \u2192 ${d.script}`));
|
|
11360
|
+
console.log(import_chalk53.default.dim(` ${d.why}`));
|
|
11227
11361
|
}
|
|
11228
11362
|
checks.push({ name: "no stray routes", status: "FAIL", detail: `${stray.length}: ${stray.map((s) => s.pattern).join(", ")}` });
|
|
11229
11363
|
} else if (routeAuditBroke) {
|
|
@@ -11234,22 +11368,22 @@ function printDoors(data) {
|
|
|
11234
11368
|
const wd = data?.workers_dev ?? {};
|
|
11235
11369
|
const open = wd.enabled ?? [];
|
|
11236
11370
|
if (open.length) {
|
|
11237
|
-
console.log(
|
|
11371
|
+
console.log(import_chalk53.default.red(`
|
|
11238
11372
|
${open.length} of ${wd.total} worker(s) reachable on *.workers.dev`));
|
|
11239
|
-
for (const s of open) console.log(
|
|
11240
|
-
console.log(
|
|
11373
|
+
for (const s of open) console.log(import_chalk53.default.red(` \u2717 ${s.script}.workers.dev`) + import_chalk53.default.dim(` (enabled=${s.enabled} previews=${s.previews})`));
|
|
11374
|
+
console.log(import_chalk53.default.dim(" A workers.dev hostname bypasses every CF route, WAF rule and the credit gate."));
|
|
11241
11375
|
checks.push({ name: "no workers.dev doors", status: "FAIL", detail: `${open.length} script(s) publicly reachable: ${open.map((s) => s.script).join(", ")}` });
|
|
11242
11376
|
} else if (devAuditBroke || !wd.total) {
|
|
11243
11377
|
checks.push({ name: "no workers.dev doors", status: "SKIP", detail: "script enumeration failed \u2014 NOT a pass, no subdomain was ever read. Needs a CF token with Workers Scripts:Read." });
|
|
11244
11378
|
} else {
|
|
11245
|
-
console.log(
|
|
11379
|
+
console.log(import_chalk53.default.green(`
|
|
11246
11380
|
\u2713 0 of ${wd.total} workers reachable on *.workers.dev`));
|
|
11247
11381
|
checks.push({ name: "no workers.dev doors", status: "PASS", detail: `all ${wd.total} scripts have workers.dev + previews disabled` });
|
|
11248
11382
|
}
|
|
11249
|
-
if (data?.how_to_fix) console.log(
|
|
11250
|
-
${data.reason}`) +
|
|
11383
|
+
if (data?.how_to_fix) console.log(import_chalk53.default.yellow(`
|
|
11384
|
+
${data.reason}`) + import_chalk53.default.dim(`
|
|
11251
11385
|
${data.how_to_fix}`));
|
|
11252
|
-
else for (const e of errs) console.log(
|
|
11386
|
+
else for (const e of errs) console.log(import_chalk53.default.red(`
|
|
11253
11387
|
audit error: ${e}`));
|
|
11254
11388
|
if (errs.length) {
|
|
11255
11389
|
checks.push({ name: "audit completeness", status: "FAIL", detail: `${errs.length} part(s) of the audit could not run \u2014 coverage is INCOMPLETE, and the checks they would have covered are SKIP above` });
|
|
@@ -11259,9 +11393,9 @@ function printDoors(data) {
|
|
|
11259
11393
|
async function runMeter(readLedger, opts) {
|
|
11260
11394
|
const checks = [];
|
|
11261
11395
|
const N = Math.max(1, Math.min(10, opts.count ?? 3));
|
|
11262
|
-
console.log(
|
|
11396
|
+
console.log(import_chalk53.default.bold("\n Meter \u2014 is 1 request charged exactly 1 request?\n"));
|
|
11263
11397
|
const snap = await readLedger();
|
|
11264
|
-
console.log(
|
|
11398
|
+
console.log(import_chalk53.default.dim(` wallet ${snap.billing_account_id} \xB7 band count ${snap.band_count} \xB7 next request ${snap.next_request_cents}\xA2
|
|
11265
11399
|
`));
|
|
11266
11400
|
const url = `https://${dpHost}/${SANDBOX.version}/${SANDBOX.environment}/`;
|
|
11267
11401
|
const headers = opts.key ? { "X-API-Key": opts.key } : {};
|
|
@@ -11343,22 +11477,22 @@ async function runMeter(readLedger, opts) {
|
|
|
11343
11477
|
return checks;
|
|
11344
11478
|
}
|
|
11345
11479
|
function printChecks(checks) {
|
|
11346
|
-
console.log(
|
|
11347
|
-
const mark = { PASS:
|
|
11480
|
+
console.log(import_chalk53.default.bold("\n Results\n"));
|
|
11481
|
+
const mark = { PASS: import_chalk53.default.green(" PASS"), FAIL: import_chalk53.default.red(" FAIL"), SKIP: import_chalk53.default.dim(" SKIP"), KNOWN: import_chalk53.default.yellow(" KNOWN") };
|
|
11348
11482
|
for (const ch of checks) {
|
|
11349
|
-
console.log(` ${mark[ch.status]} ${
|
|
11350
|
-
console.log(
|
|
11483
|
+
console.log(` ${mark[ch.status]} ${import_chalk53.default.bold(ch.name)}`);
|
|
11484
|
+
console.log(import_chalk53.default.dim(` ${ch.detail}`));
|
|
11351
11485
|
}
|
|
11352
11486
|
const fails = checks.filter((c) => c.status === "FAIL").length;
|
|
11353
11487
|
const skips = checks.filter((c) => c.status === "SKIP").length;
|
|
11354
11488
|
const known = checks.filter((c) => c.status === "KNOWN").length;
|
|
11355
11489
|
console.log("");
|
|
11356
11490
|
const passes = checks.filter((c) => c.status === "PASS").length;
|
|
11357
|
-
if (fails) console.log(
|
|
11358
|
-
else if (passes) console.log(
|
|
11359
|
-
else console.log(
|
|
11360
|
-
if (known) console.log(
|
|
11361
|
-
if (skips) console.log(
|
|
11491
|
+
if (fails) console.log(import_chalk53.default.red(` ${fails} check(s) FAILED.`));
|
|
11492
|
+
else if (passes) console.log(import_chalk53.default.green(` ${passes} check(s) passed, 0 failed.`));
|
|
11493
|
+
else console.log(import_chalk53.default.yellow(" NOTHING WAS VERIFIED \u2014 every check was skipped."));
|
|
11494
|
+
if (known) console.log(import_chalk53.default.yellow(` ${known} known-open issue(s) still outstanding.`));
|
|
11495
|
+
if (skips) console.log(import_chalk53.default.dim(` ${skips} check(s) NOT RUN (see SKIP above) \u2014 those invariants are unverified.`));
|
|
11362
11496
|
console.log("");
|
|
11363
11497
|
}
|
|
11364
11498
|
|
|
@@ -11405,93 +11539,93 @@ var OP_COMMANDS = [
|
|
|
11405
11539
|
function renderOpCommands() {
|
|
11406
11540
|
const width = Math.max(...OP_COMMANDS.map((c) => c.cmd.length)) + 10;
|
|
11407
11541
|
const lines = OP_COMMANDS.map((c) => {
|
|
11408
|
-
const left = ` ${
|
|
11542
|
+
const left = ` ${import_chalk54.default.cyan(`apiblaze ${c.cmd}`)}`;
|
|
11409
11543
|
const pad = " ".repeat(Math.max(1, width - c.cmd.length));
|
|
11410
|
-
return `${left}${pad}${c.blurb}${c.extra ? " " +
|
|
11544
|
+
return `${left}${pad}${c.blurb}${c.extra ? " " + import_chalk54.default.dim(`(${c.extra})`) : ""}`;
|
|
11411
11545
|
});
|
|
11412
11546
|
return [
|
|
11413
|
-
|
|
11547
|
+
import_chalk54.default.bold("Operator commands"),
|
|
11414
11548
|
...lines,
|
|
11415
11549
|
"",
|
|
11416
|
-
|
|
11417
|
-
|
|
11418
|
-
|
|
11550
|
+
import_chalk54.default.dim(" Operators only. The gate is server-side (dashboard /api/cli/op checks the"),
|
|
11551
|
+
import_chalk54.default.dim(" signed-in email, admin-api re-checks with operatorGate) \u2014 a patched CLI just"),
|
|
11552
|
+
import_chalk54.default.dim(" gets 403s. Every op call is read-only except `op sweep`."),
|
|
11419
11553
|
"",
|
|
11420
|
-
|
|
11421
|
-
|
|
11422
|
-
|
|
11554
|
+
import_chalk54.default.dim(" Not a CLI command: to prune all non-CP data run scripts/nuke-but-cp.sh --apply --sweep"),
|
|
11555
|
+
import_chalk54.default.dim(" in the repo. Operator dashboards (dlq, thresholds, throttling, pricing, billing,"),
|
|
11556
|
+
import_chalk54.default.dim(" agent-spend, teams, tests, leak-detection, lifecycle) live at /operator/* in the app.")
|
|
11423
11557
|
].join("\n");
|
|
11424
11558
|
}
|
|
11425
11559
|
function printResidue(report, applied) {
|
|
11426
11560
|
const up = report?.upstash ?? {};
|
|
11427
11561
|
const fga = report?.fga ?? {};
|
|
11428
11562
|
const ghosts = report?.ghosts ?? {};
|
|
11429
|
-
console.log(
|
|
11430
|
-
console.log(
|
|
11563
|
+
console.log(import_chalk54.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
|
|
11564
|
+
console.log(import_chalk54.default.bold("\n Upstash"));
|
|
11431
11565
|
const orphans = up.orphans ?? [];
|
|
11432
|
-
if (orphans.length === 0) console.log(
|
|
11433
|
-
for (const o of orphans) console.log(` ${
|
|
11434
|
-
console.log(
|
|
11566
|
+
if (orphans.length === 0) console.log(import_chalk54.default.green(" no orphaned keys"));
|
|
11567
|
+
for (const o of orphans) console.log(` ${import_chalk54.default.yellow(o.key)} ${import_chalk54.default.dim(`\u2014 ${o.reason}`)}`);
|
|
11568
|
+
console.log(import_chalk54.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
|
|
11435
11569
|
if (up.anon_wallet_detail) {
|
|
11436
11570
|
const d = up.anon_wallet_detail;
|
|
11437
|
-
console.log(
|
|
11571
|
+
console.log(import_chalk54.default.dim(` anon wallets: ${d.count} ($${(d.total_cents / 100).toFixed(2)}), ${d.no_ttl} with NO TTL${d.no_ttl ? " \u26A0" : " (all self-expire)"}`));
|
|
11438
11572
|
}
|
|
11439
11573
|
if (up.keyspace_census) {
|
|
11440
11574
|
const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
|
|
11441
|
-
console.log(
|
|
11575
|
+
console.log(import_chalk54.default.dim(` keyspace: ${census}`));
|
|
11442
11576
|
}
|
|
11443
|
-
if (up.unknown?.length) console.log(
|
|
11444
|
-
if (applied) console.log(` ${
|
|
11445
|
-
for (const e of up.errors ?? []) console.log(
|
|
11446
|
-
console.log(
|
|
11577
|
+
if (up.unknown?.length) console.log(import_chalk54.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
|
|
11578
|
+
if (applied) console.log(` ${import_chalk54.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
|
|
11579
|
+
for (const e of up.errors ?? []) console.log(import_chalk54.default.red(` error: ${e}`));
|
|
11580
|
+
console.log(import_chalk54.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
|
|
11447
11581
|
if (applied) {
|
|
11448
11582
|
const swept = fga?.swept ?? [];
|
|
11449
|
-
if (swept.length === 0) console.log(
|
|
11583
|
+
if (swept.length === 0) console.log(import_chalk54.default.green(" no orphaned stores"));
|
|
11450
11584
|
for (const s of swept) {
|
|
11451
11585
|
console.log(
|
|
11452
|
-
` ${
|
|
11586
|
+
` ${import_chalk54.default.yellow(s.store_id)} ${import_chalk54.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
|
|
11453
11587
|
);
|
|
11454
11588
|
}
|
|
11455
|
-
if (fga?.remaining) console.log(
|
|
11589
|
+
if (fga?.remaining) console.log(import_chalk54.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
|
|
11456
11590
|
const st = fga?.side_tables;
|
|
11457
|
-
if (st) console.log(
|
|
11591
|
+
if (st) console.log(import_chalk54.default.dim(` Neon side-tables purged: ${st.soft_deleted_stores} store records, ${st.orphan_models} models, ${st.orphan_changelog} changelog rows${st.error ? ` (${st.error})` : ""}`));
|
|
11458
11592
|
} else {
|
|
11459
11593
|
const fgaOrphans = fga?.orphans ?? [];
|
|
11460
|
-
if (fgaOrphans.length === 0) console.log(
|
|
11594
|
+
if (fgaOrphans.length === 0) console.log(import_chalk54.default.green(" no orphaned stores"));
|
|
11461
11595
|
for (const s of fgaOrphans) {
|
|
11462
11596
|
const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
|
|
11463
|
-
console.log(` ${
|
|
11597
|
+
console.log(` ${import_chalk54.default.yellow(s.store_id)} ${import_chalk54.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
|
|
11464
11598
|
}
|
|
11465
|
-
console.log(
|
|
11599
|
+
console.log(import_chalk54.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
|
|
11466
11600
|
const st = fga?.side_tables;
|
|
11467
|
-
if (st) console.log(
|
|
11601
|
+
if (st) console.log(import_chalk54.default.dim(` Neon side-table residue: ${st.soft_deleted_stores} soft-deleted store records, ${st.orphan_models} orphan models, ${st.orphan_changelog} orphan changelog rows`));
|
|
11468
11602
|
}
|
|
11469
|
-
for (const e of fga?.errors ?? []) console.log(
|
|
11470
|
-
console.log(
|
|
11603
|
+
for (const e of fga?.errors ?? []) console.log(import_chalk54.default.red(` error: ${e}`));
|
|
11604
|
+
console.log(import_chalk54.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
|
|
11471
11605
|
if (applied) {
|
|
11472
|
-
if ((ghosts?.ghost_count ?? 0) === 0) console.log(
|
|
11473
|
-
else console.log(` ${
|
|
11606
|
+
if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk54.default.green(" no ghost tuples"));
|
|
11607
|
+
else console.log(` ${import_chalk54.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk54.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
|
|
11474
11608
|
} else {
|
|
11475
11609
|
const n = ghosts?.ghost_count ?? 0;
|
|
11476
|
-
if (n === 0) console.log(
|
|
11610
|
+
if (n === 0) console.log(import_chalk54.default.green(` no ghost tuples ${import_chalk54.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
|
|
11477
11611
|
else {
|
|
11478
|
-
console.log(
|
|
11612
|
+
console.log(import_chalk54.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
|
|
11479
11613
|
for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
|
|
11480
|
-
console.log(
|
|
11614
|
+
console.log(import_chalk54.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
|
|
11481
11615
|
}
|
|
11482
|
-
if (n > 20) console.log(
|
|
11616
|
+
if (n > 20) console.log(import_chalk54.default.dim(` \u2026 and ${n - 20} more`));
|
|
11483
11617
|
}
|
|
11484
11618
|
}
|
|
11485
|
-
for (const e of ghosts?.errors ?? []) console.log(
|
|
11619
|
+
for (const e of ghosts?.errors ?? []) console.log(import_chalk54.default.red(` error: ${e}`));
|
|
11486
11620
|
console.log();
|
|
11487
11621
|
}
|
|
11488
11622
|
async function runOp(sub, opts = {}, view) {
|
|
11489
11623
|
if (!loadCredentials()) {
|
|
11490
|
-
console.log(
|
|
11624
|
+
console.log(import_chalk54.default.dim("Not logged in. Run `apiblaze login`."));
|
|
11491
11625
|
return;
|
|
11492
11626
|
}
|
|
11493
11627
|
if (!isOperatorLogin()) {
|
|
11494
|
-
console.log(
|
|
11628
|
+
console.log(import_chalk54.default.dim("`apiblaze op` is only available to platform operators."));
|
|
11495
11629
|
return;
|
|
11496
11630
|
}
|
|
11497
11631
|
switch (sub) {
|
|
@@ -11517,17 +11651,17 @@ async function runOp(sub, opts = {}, view) {
|
|
|
11517
11651
|
const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
|
|
11518
11652
|
printResidue(report, false);
|
|
11519
11653
|
if (nUp + nFga + nGhost + nSide === 0) {
|
|
11520
|
-
console.log(
|
|
11654
|
+
console.log(import_chalk54.default.green("Nothing to sweep."));
|
|
11521
11655
|
return;
|
|
11522
11656
|
}
|
|
11523
11657
|
if (!opts.yes) {
|
|
11524
11658
|
const readline3 = await import("readline/promises");
|
|
11525
11659
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
11526
11660
|
const answer = await rl.question(
|
|
11527
|
-
|
|
11661
|
+
import_chalk54.default.red(`Delete ${nUp} Upstash key(s) + ${nFga} OpenFGA store(s) + ${nGhost} ghost tuple(s) + ${nSide} Neon side-table row(s)? Type 'sweep' to confirm: `)
|
|
11528
11662
|
);
|
|
11529
11663
|
rl.close();
|
|
11530
|
-
if (answer.trim() !== "sweep") return void console.log(
|
|
11664
|
+
if (answer.trim() !== "sweep") return void console.log(import_chalk54.default.dim("Aborted."));
|
|
11531
11665
|
}
|
|
11532
11666
|
const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
|
|
11533
11667
|
if (opts.json) return void console.log(JSON.stringify(result, null, 2));
|
|
@@ -11537,25 +11671,25 @@ async function runOp(sub, opts = {}, view) {
|
|
|
11537
11671
|
case "mark": {
|
|
11538
11672
|
const label3 = (view ?? "").trim();
|
|
11539
11673
|
if (!label3) {
|
|
11540
|
-
console.log(
|
|
11674
|
+
console.log(import_chalk54.default.red("Give the change a name:") + import_chalk54.default.cyan(' apiblaze op mark "cached tenant count"'));
|
|
11541
11675
|
return;
|
|
11542
11676
|
}
|
|
11543
11677
|
const res = await opCall({ method: "POST", path: "/operator/latency/mark", body: { label: label3 }, summary: "record change marker" });
|
|
11544
11678
|
const ts = new Date(res?.marker?.ts ?? Date.now()).toISOString();
|
|
11545
|
-
console.log(
|
|
11546
|
-
Marked: `) +
|
|
11547
|
-
console.log(
|
|
11548
|
-
console.log(
|
|
11679
|
+
console.log(import_chalk54.default.green(`
|
|
11680
|
+
Marked: `) + import_chalk54.default.bold(label3));
|
|
11681
|
+
console.log(import_chalk54.default.dim(` ${ts}`));
|
|
11682
|
+
console.log(import_chalk54.default.dim(` Once traffic has run on both sides, compare with: `) + import_chalk54.default.cyan("apiblaze op latency compare") + "\n");
|
|
11549
11683
|
return;
|
|
11550
11684
|
}
|
|
11551
11685
|
case "credits": {
|
|
11552
11686
|
const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
|
|
11553
11687
|
if (opts.json) return void console.log(JSON.stringify(data, null, 2));
|
|
11554
11688
|
const accounts = data?.accounts ?? [];
|
|
11555
|
-
if (accounts.length === 0) return void console.log(
|
|
11689
|
+
if (accounts.length === 0) return void console.log(import_chalk54.default.dim("No credit wallets."));
|
|
11556
11690
|
for (const a of accounts) {
|
|
11557
11691
|
const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
|
|
11558
|
-
console.log(` ${
|
|
11692
|
+
console.log(` ${import_chalk54.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk54.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk54.default.dim(" \u2014 anon") : ""}`);
|
|
11559
11693
|
}
|
|
11560
11694
|
return;
|
|
11561
11695
|
}
|
|
@@ -11566,7 +11700,7 @@ async function runOp(sub, opts = {}, view) {
|
|
|
11566
11700
|
case "billing": {
|
|
11567
11701
|
const which = (view ?? "").trim().toLowerCase();
|
|
11568
11702
|
if (which && which !== "doors" && which !== "meter") {
|
|
11569
|
-
return void console.log(
|
|
11703
|
+
return void console.log(import_chalk54.default.red(`Unknown: apiblaze op billing ${which}. Use 'doors', 'meter', or neither for both.`));
|
|
11570
11704
|
}
|
|
11571
11705
|
const checks = [];
|
|
11572
11706
|
let doorsData = null;
|
|
@@ -11627,29 +11761,29 @@ async function runOp(sub, opts = {}, view) {
|
|
|
11627
11761
|
const data = await opCall({ method: "GET", path: `/operator/latency/grades${q}`, summary: "latency grades" });
|
|
11628
11762
|
if (opts.json) return void console.log(JSON.stringify(data, null, 2));
|
|
11629
11763
|
const t = data.thresholds_ms;
|
|
11630
|
-
console.log(
|
|
11631
|
-
console.log(
|
|
11764
|
+
console.log(import_chalk54.default.bold("\nHow good was apiblaze itself?") + import_chalk54.default.dim(" (our overhead only \u2014 a slow customer API never counts against us)"));
|
|
11765
|
+
console.log(import_chalk54.default.dim(` excellent <${t.excellent.replace("<", "")}ms \xB7 okay ${t.okay}ms \xB7 bad ${t.bad}ms \xB7 terrible ${t.terrible.replace(">=", "")}ms+
|
|
11632
11766
|
`));
|
|
11633
|
-
console.log(
|
|
11767
|
+
console.log(import_chalk54.default.dim(" date reqs excellent okay bad terrible"));
|
|
11634
11768
|
for (const d of data.days ?? []) {
|
|
11635
11769
|
const p = d.pct;
|
|
11636
|
-
const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) :
|
|
11770
|
+
const cell = (v, colour) => v > 0 ? colour(`${String(v).padStart(5)}%`) : import_chalk54.default.dim(`${String(v).padStart(5)}%`);
|
|
11637
11771
|
console.log(
|
|
11638
|
-
` ${d.date} ${String(d.total).padStart(5)} ${cell(p.excellent,
|
|
11772
|
+
` ${d.date} ${String(d.total).padStart(5)} ${cell(p.excellent, import_chalk54.default.green)} ${cell(p.okay, import_chalk54.default.cyan)} ${cell(p.bad, import_chalk54.default.yellow)} ${cell(p.terrible, import_chalk54.default.red)}`
|
|
11639
11773
|
);
|
|
11640
11774
|
}
|
|
11641
11775
|
const cul = data.culprits ?? [];
|
|
11642
11776
|
if (cul.length) {
|
|
11643
|
-
console.log(
|
|
11644
|
-
console.log(
|
|
11777
|
+
console.log(import_chalk54.default.bold("\n Who caused the bad and terrible ones\n"));
|
|
11778
|
+
console.log(import_chalk54.default.dim(" bad terrible feature \u2192 dependency"));
|
|
11645
11779
|
for (const r of cul.slice(0, 12)) {
|
|
11646
11780
|
if (!r.bad && !r.terrible) continue;
|
|
11647
11781
|
console.log(
|
|
11648
|
-
` ${String(r.bad).padStart(6)} ${
|
|
11782
|
+
` ${String(r.bad).padStart(6)} ${import_chalk54.default.red(String(r.terrible).padStart(8))} ${import_chalk54.default.yellow(r.feature)} ${import_chalk54.default.dim("\u2192")} ${import_chalk54.default.cyan(r.dep)}`
|
|
11649
11783
|
);
|
|
11650
11784
|
}
|
|
11651
11785
|
}
|
|
11652
|
-
if (data.caveat) console.log(
|
|
11786
|
+
if (data.caveat) console.log(import_chalk54.default.dim(`
|
|
11653
11787
|
\u26A0 ${data.caveat}
|
|
11654
11788
|
`));
|
|
11655
11789
|
return;
|
|
@@ -11658,24 +11792,24 @@ async function runOp(sub, opts = {}, view) {
|
|
|
11658
11792
|
const data = await opCall({ method: "GET", path: `/operator/latency/compare${q}`, summary: "latency before/after" });
|
|
11659
11793
|
if (opts.json) return void console.log(JSON.stringify(data, null, 2));
|
|
11660
11794
|
const b = data.before, a = data.after, d = data.delta;
|
|
11661
|
-
console.log(
|
|
11662
|
-
Before vs after: `) +
|
|
11663
|
-
console.log(
|
|
11795
|
+
console.log(import_chalk54.default.bold(`
|
|
11796
|
+
Before vs after: `) + import_chalk54.default.cyan(data.marker.label));
|
|
11797
|
+
console.log(import_chalk54.default.dim(` marked ${new Date(data.marker.ts).toISOString()} \xB7 ${data.window_hours}h either side
|
|
11664
11798
|
`));
|
|
11665
11799
|
const row = (name, before, after, delta) => {
|
|
11666
11800
|
const arrow = delta === 0 ? "=" : delta < 0 ? "\u2193" : "\u2191";
|
|
11667
11801
|
const txt = `${String(before).padStart(6)}ms \u2192${String(after).padStart(7)}ms ${arrow}${Math.abs(delta)}ms`;
|
|
11668
|
-
console.log(` ${name.padEnd(22)}${data.trustworthy ? delta <= 0 ?
|
|
11802
|
+
console.log(` ${name.padEnd(22)}${data.trustworthy ? delta <= 0 ? import_chalk54.default.green(txt) : import_chalk54.default.red(txt) : import_chalk54.default.dim(txt)}`);
|
|
11669
11803
|
};
|
|
11670
|
-
console.log(
|
|
11804
|
+
console.log(import_chalk54.default.dim(" metric before after change"));
|
|
11671
11805
|
row("total p50", b.total_p50, a.total_p50, d.total_p50);
|
|
11672
11806
|
row("total p95", b.total_p95, a.total_p95, d.total_p95);
|
|
11673
11807
|
row("apiblaze overhead p50", b.gw_p50, a.gw_p50, d.gw_p50);
|
|
11674
11808
|
row("apiblaze overhead p95", b.gw_p95, a.gw_p95, d.gw_p95);
|
|
11675
|
-
console.log(
|
|
11809
|
+
console.log(import_chalk54.default.dim(`
|
|
11676
11810
|
requests: ${b.requests} before \xB7 ${a.requests} after`));
|
|
11677
11811
|
for (const w of data.warnings ?? []) {
|
|
11678
|
-
console.log((data.trustworthy ?
|
|
11812
|
+
console.log((data.trustworthy ? import_chalk54.default.dim : import_chalk54.default.yellow)(` ${data.trustworthy ? "\xB7" : "\u26A0"} ${w}`));
|
|
11679
11813
|
}
|
|
11680
11814
|
console.log("");
|
|
11681
11815
|
return;
|
|
@@ -11684,19 +11818,19 @@ Before vs after: `) + import_chalk53.default.cyan(data.marker.label));
|
|
|
11684
11818
|
const data = await opCall({ method: "GET", path: `/operator/latency/slow${q}`, summary: "slowest requests" });
|
|
11685
11819
|
if (opts.json) return void console.log(JSON.stringify(data, null, 2));
|
|
11686
11820
|
const rows2 = data?.rows ?? [];
|
|
11687
|
-
if (!rows2.length) return void console.log(
|
|
11688
|
-
console.log(
|
|
11821
|
+
if (!rows2.length) return void console.log(import_chalk54.default.dim("No requests over the threshold in that window."));
|
|
11822
|
+
console.log(import_chalk54.default.bold(`
|
|
11689
11823
|
Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
|
|
11690
11824
|
`));
|
|
11691
|
-
console.log(
|
|
11825
|
+
console.log(import_chalk54.default.dim(" total ours theirs blame request id"));
|
|
11692
11826
|
for (const r of rows2.slice(0, 30)) {
|
|
11693
11827
|
console.log(
|
|
11694
|
-
` ${String(Math.round(r.duration_ms)).padStart(6)} ${String(Math.round(r.gateway_ms)).padStart(5)} ${String(Math.round(r.upstream_ttfb_ms)).padStart(6)} ${
|
|
11828
|
+
` ${String(Math.round(r.duration_ms)).padStart(6)} ${String(Math.round(r.gateway_ms)).padStart(5)} ${String(Math.round(r.upstream_ttfb_ms)).padStart(6)} ${import_chalk54.default.yellow(`${r.slow_gw_feature || "-"}\u2192${r.slow_dep || "-"}`.padEnd(20))} ${import_chalk54.default.dim(r.request_id || "")}`
|
|
11695
11829
|
);
|
|
11696
11830
|
}
|
|
11697
|
-
console.log(
|
|
11831
|
+
console.log(import_chalk54.default.dim(`
|
|
11698
11832
|
The last column is the request id (Cloudflare calls it a "cf-ray"). Look one up with`));
|
|
11699
|
-
console.log(
|
|
11833
|
+
console.log(import_chalk54.default.dim(` \`apiblaze logs\` for that request's exact per-feature breakdown \u2014 unsampled, unlike the table above.
|
|
11700
11834
|
`));
|
|
11701
11835
|
return;
|
|
11702
11836
|
}
|
|
@@ -11704,18 +11838,18 @@ Slowest requests \u2014 last ${data.window_hours}h, over ${data.min_ms}ms
|
|
|
11704
11838
|
const data = await opCall({ method: "GET", path: `/operator/latency/llm${q}`, summary: "llm latency" });
|
|
11705
11839
|
if (opts.json) return void console.log(JSON.stringify(data, null, 2));
|
|
11706
11840
|
const rows2 = data?.rows ?? [];
|
|
11707
|
-
if (!rows2.length) return void console.log(
|
|
11708
|
-
console.log(
|
|
11841
|
+
if (!rows2.length) return void console.log(import_chalk54.default.dim("No LLM traffic in that window."));
|
|
11842
|
+
console.log(import_chalk54.default.bold(`
|
|
11709
11843
|
LLM timing \u2014 last ${data.window_hours}h
|
|
11710
11844
|
`));
|
|
11711
|
-
console.log(
|
|
11845
|
+
console.log(import_chalk54.default.dim(" turns turn p95 ttfc p95 gen p95 reserve p95 in/out tokens p95 model"));
|
|
11712
11846
|
for (const r of rows2) {
|
|
11713
11847
|
const n = r.turns ?? r.requests ?? 0;
|
|
11714
11848
|
console.log(
|
|
11715
11849
|
` ${String(Math.round(n)).padStart(8)} ${String(Math.round(r.turn_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.ttfc_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.gen_p95_ms ?? 0)).padStart(6)}ms ${String(Math.round(r.reserve_p95_ms ?? 0)).padStart(9)}ms ${String(Math.round(r.input_tokens_p95 ?? 0)).padStart(6)}/${String(Math.round(r.output_tokens_p95 ?? 0)).padEnd(6)} ${r.model || "-"}`
|
|
11716
11850
|
);
|
|
11717
11851
|
}
|
|
11718
|
-
console.log(
|
|
11852
|
+
console.log(import_chalk54.default.dim(`
|
|
11719
11853
|
${data.note}
|
|
11720
11854
|
`));
|
|
11721
11855
|
return;
|
|
@@ -11726,26 +11860,26 @@ LLM timing \u2014 last ${data.window_hours}h
|
|
|
11726
11860
|
]);
|
|
11727
11861
|
if (opts.json) return void console.log(JSON.stringify({ blame, summary }, null, 2));
|
|
11728
11862
|
const ov = summary?.apiblaze_overhead_ms ?? {};
|
|
11729
|
-
console.log(
|
|
11863
|
+
console.log(import_chalk54.default.bold(`
|
|
11730
11864
|
Latency \u2014 last ${summary?.window_hours ?? "?"}h, ${Number(summary?.requests ?? 0).toLocaleString()} requests
|
|
11731
11865
|
`));
|
|
11732
|
-
console.log(` ${
|
|
11733
|
-
console.log(` ${
|
|
11734
|
-
console.log(
|
|
11866
|
+
console.log(` ${import_chalk54.default.bold("apiblaze overhead")} p50 ${String(ov.p50 ?? 0).padStart(5)}ms p95 ${String(ov.p95 ?? 0).padStart(6)}ms p99 ${String(ov.p99 ?? 0).padStart(6)}ms ${import_chalk54.default.dim("\u2190 ours")}`);
|
|
11867
|
+
console.log(` ${import_chalk54.default.bold("upstream ttfb ")} ${" ".repeat(24)}p95 ${String(summary?.upstream_ttfb_p95_ms ?? 0).padStart(6)}ms ${import_chalk54.default.dim("\u2190 theirs")}`);
|
|
11868
|
+
console.log(import_chalk54.default.dim(` (per-request percentiles \u2014 never subtract one from the other)
|
|
11735
11869
|
`));
|
|
11736
11870
|
const rows = blame?.blame ?? [];
|
|
11737
|
-
if (!rows.length) return void console.log(
|
|
11738
|
-
console.log(
|
|
11739
|
-
console.log(
|
|
11871
|
+
if (!rows.length) return void console.log(import_chalk54.default.dim("No latency rows in that window."));
|
|
11872
|
+
console.log(import_chalk54.default.bold(" Which feature ate the time, and what inside it\n"));
|
|
11873
|
+
console.log(import_chalk54.default.dim(" share p95 feature \u2192 dependency"));
|
|
11740
11874
|
for (const r of rows.slice(0, 15)) {
|
|
11741
11875
|
const share = `${(r.share * 100).toFixed(1)}%`;
|
|
11742
|
-
console.log(` ${share.padStart(6)} ${String(r.p95_ms).padStart(6)}ms ${
|
|
11876
|
+
console.log(` ${share.padStart(6)} ${String(r.p95_ms).padStart(6)}ms ${import_chalk54.default.yellow(r.feature)} ${import_chalk54.default.dim("\u2192")} ${import_chalk54.default.cyan(r.dep)}`);
|
|
11743
11877
|
}
|
|
11744
11878
|
console.log("");
|
|
11745
11879
|
return;
|
|
11746
11880
|
}
|
|
11747
11881
|
default:
|
|
11748
|
-
console.log(
|
|
11882
|
+
console.log(import_chalk54.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
|
|
11749
11883
|
}
|
|
11750
11884
|
}
|
|
11751
11885
|
|
|
@@ -11808,7 +11942,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
|
|
|
11808
11942
|
try {
|
|
11809
11943
|
const resolved = parseInt(port ?? opts.port, 10);
|
|
11810
11944
|
if (Number.isNaN(resolved)) {
|
|
11811
|
-
console.error(
|
|
11945
|
+
console.error(import_chalk55.default.red(`Invalid port: ${port ?? opts.port}`));
|
|
11812
11946
|
process.exit(1);
|
|
11813
11947
|
}
|
|
11814
11948
|
await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile, newSession: opts.newSession });
|
|
@@ -11841,6 +11975,7 @@ program.command("claim").description("Claim your anonymous workspace into your a
|
|
|
11841
11975
|
process.exit(1);
|
|
11842
11976
|
}
|
|
11843
11977
|
});
|
|
11978
|
+
program.command("docs").description("Ask an AI chatbot about APIblaze \u2014 and let it act on your account (it's the real API, not a docs search)").option("-p, --prompt <question>", "Ask one question and exit").option("--install-mcp <cli>", "Wire it straight into an external agent CLI: claude | codex").option("--remove-mcp <cli>", "Disconnect APIblaze from an external agent CLI (claude | codex)").option("--yes", 'Skip the "this can change things" confirmation').option("--verbose", "Show the per-turn proxy curl trace").action(action((opts) => runDocs(opts)));
|
|
11844
11979
|
program.command("allowoauthregistration").description("Approve the next OAuth client that registers against your tenant (Claude Code, Codex, any MCP client) \u2014 single use").requiredOption("--tenant <slug>", "Tenant the client will register against (see `apiblaze projects`)").option("--team <id|name>", "Team owning the tenant (defaults to your active team)").option("--minutes <n>", "Expire the unused authorization after this many minutes (default 10, max 60)").option("--cancel", "Cancel an unused authorization instead of opening one").action(action((opts) => runAllowOauthRegistration(opts)));
|
|
11845
11980
|
program.command("team").description("Switch the active team, or create a new one").argument("[team]", "Team name or id to switch to (omit to choose interactively)").option("--new [name]", "Create a new team and make it active (omit the name to be asked)").action(async (team, opts) => {
|
|
11846
11981
|
try {
|
|
@@ -11918,7 +12053,7 @@ spec.command("set").description("Replace the stored OpenAPI spec from a local fi
|
|
|
11918
12053
|
spec.command("carry").description("Copy a route's saved rules to the path a spec rename moved traffic to").argument("<project>", "Project name or id").requiredOption("--method <method>", "HTTP method of the route (GET, POST, ...)").requiredOption("--from <path>", "Old route path, e.g. /owners/{ownerId}").requiredOption("--to <path>", "New route path, e.g. /customers/{customerId}").option("--delete-source", "Also delete the old rules after carrying").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version").option("--json", "Output machine-readable JSON").action(action((project, opts) => runSpecCarry(project, opts)));
|
|
11919
12054
|
spec.command("delete-rule").description("Delete the saved rules for a route (e.g. an orphan left by a spec change)").argument("<project>", "Project name or id").requiredOption("--method <method>", "HTTP method of the route").requiredOption("--route <path>", "Route path, e.g. /owners/{ownerId}").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version").action(action((project, opts) => runSpecDeleteRule(project, opts)));
|
|
11920
12055
|
var HELP_GROUPS = [
|
|
11921
|
-
{ title: "Chat", commands: ["apichat", "agent"] },
|
|
12056
|
+
{ title: "Chat", commands: ["docs", "apichat", "agent"] },
|
|
11922
12057
|
{ title: "Setup", commands: ["login", "create", "init", "sidecar", "dev", "claim", "team", "whoami", "logout"] },
|
|
11923
12058
|
{ title: "Recipes \u2014 install a working setup, or publish yours", commands: ["search", "show", "install", "publish", "withdraw"] },
|
|
11924
12059
|
{ title: "Control plane commands", commands: ["config", "projects", "logs", "tenant", "group", "admins", "iam", "identified", "preapprove", "rule", "domain", "delete", "target", "throttle", "rename", "spec", "export"] },
|
|
@@ -11941,7 +12076,7 @@ function groupedCommandHelp() {
|
|
|
11941
12076
|
const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
|
|
11942
12077
|
return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
|
|
11943
12078
|
}).filter(Boolean).join("\n");
|
|
11944
|
-
return `${
|
|
12079
|
+
return `${import_chalk55.default.bold(g.title)}
|
|
11945
12080
|
${rows}`;
|
|
11946
12081
|
}).join("\n\n");
|
|
11947
12082
|
}
|
|
@@ -11952,6 +12087,8 @@ program.configureHelp({
|
|
|
11952
12087
|
}
|
|
11953
12088
|
});
|
|
11954
12089
|
program.addHelpText("after", () => `
|
|
12090
|
+
${import_chalk55.default.bold("Don't like reading docs?")} Run ${import_chalk55.default.bgCyan.black.bold(" npx apiblaze docs ")} ${import_chalk55.default.cyan("\u2014 ask an AI chatbot about APIblaze, and let it act on your account.")}
|
|
12091
|
+
|
|
11955
12092
|
${groupedCommandHelp()}
|
|
11956
12093
|
|
|
11957
12094
|
Tips:
|
|
@@ -11981,14 +12118,14 @@ async function recoverStaleTeam() {
|
|
|
11981
12118
|
const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
|
|
11982
12119
|
const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
|
|
11983
12120
|
if (!linked) {
|
|
11984
|
-
console.error(
|
|
12121
|
+
console.error(import_chalk55.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
|
|
11985
12122
|
return;
|
|
11986
12123
|
}
|
|
11987
12124
|
if (linked.teamId === creds.teamId) return;
|
|
11988
12125
|
const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
|
|
11989
12126
|
delete next.activeTenant;
|
|
11990
12127
|
saveCredentials(next);
|
|
11991
|
-
console.error(
|
|
12128
|
+
console.error(import_chalk55.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk55.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
|
|
11992
12129
|
} catch {
|
|
11993
12130
|
}
|
|
11994
12131
|
}
|
|
@@ -11996,16 +12133,16 @@ async function printError(err) {
|
|
|
11996
12133
|
if (err instanceof ApiError) {
|
|
11997
12134
|
const data = err.body;
|
|
11998
12135
|
const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
|
|
11999
|
-
console.error(
|
|
12136
|
+
console.error(import_chalk55.default.red(`
|
|
12000
12137
|
API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
|
|
12001
12138
|
if (err.status === 403 || err.status === 404) {
|
|
12002
12139
|
await recoverStaleTeam();
|
|
12003
12140
|
}
|
|
12004
12141
|
} else if (err instanceof Error) {
|
|
12005
|
-
console.error(
|
|
12142
|
+
console.error(import_chalk55.default.red(`
|
|
12006
12143
|
Error: ${err.message}`));
|
|
12007
12144
|
} else {
|
|
12008
|
-
console.error(
|
|
12145
|
+
console.error(import_chalk55.default.red("\nUnknown error"));
|
|
12009
12146
|
}
|
|
12010
12147
|
}
|
|
12011
12148
|
program.parse(process.argv);
|