apiblaze 0.19.25 → 0.19.28
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 +668 -583
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -476,7 +476,7 @@ var init_admin = __esm({
|
|
|
476
476
|
function requireAuth() {
|
|
477
477
|
const creds = loadCredentials();
|
|
478
478
|
if (!creds) {
|
|
479
|
-
console.error(
|
|
479
|
+
console.error(import_chalk9.default.red("Not logged in. Run `apiblaze login` first."));
|
|
480
480
|
process.exit(1);
|
|
481
481
|
}
|
|
482
482
|
return creds;
|
|
@@ -485,7 +485,7 @@ async function resolveTeam(opt) {
|
|
|
485
485
|
const creds = requireAuth();
|
|
486
486
|
if (!opt) {
|
|
487
487
|
if (!creds.teamId) {
|
|
488
|
-
console.error(
|
|
488
|
+
console.error(import_chalk9.default.red("No active team. Run `apiblaze login` or pass --team."));
|
|
489
489
|
process.exit(1);
|
|
490
490
|
}
|
|
491
491
|
return { teamId: creds.teamId, teamName: creds.teamName };
|
|
@@ -494,7 +494,7 @@ async function resolveTeam(opt) {
|
|
|
494
494
|
const teams = await getTeams().catch(() => []);
|
|
495
495
|
const match = teams.find((t) => t.name === opt || t.teamId === opt);
|
|
496
496
|
if (!match) {
|
|
497
|
-
console.error(
|
|
497
|
+
console.error(import_chalk9.default.red(`Team "${opt}" not found.${teams.length ? " Available: " + teams.map((t) => t.name).join(", ") : ""}`));
|
|
498
498
|
process.exit(1);
|
|
499
499
|
}
|
|
500
500
|
return { teamId: match.teamId, teamName: match.name };
|
|
@@ -505,13 +505,13 @@ async function resolveProject(teamId, nameOrId, version2) {
|
|
|
505
505
|
(p) => p.projectId === nameOrId || p.projectName === nameOrId
|
|
506
506
|
);
|
|
507
507
|
if (candidates.length === 0) {
|
|
508
|
-
console.error(
|
|
509
|
-
if (projects.length) console.error(
|
|
508
|
+
console.error(import_chalk9.default.red(`Project "${nameOrId}" not found in this team.`));
|
|
509
|
+
if (projects.length) console.error(import_chalk9.default.dim(" Known: " + projects.map((p) => p.projectName).join(", ")));
|
|
510
510
|
process.exit(1);
|
|
511
511
|
}
|
|
512
512
|
const chosen = version2 ? candidates.find((p) => p.apiVersion === version2) : candidates[0];
|
|
513
513
|
if (!chosen) {
|
|
514
|
-
console.error(
|
|
514
|
+
console.error(import_chalk9.default.red(`Project "${nameOrId}" has no version ${version2}. Versions: ${candidates.map((p) => p.apiVersion).join(", ")}`));
|
|
515
515
|
process.exit(1);
|
|
516
516
|
}
|
|
517
517
|
return {
|
|
@@ -522,11 +522,11 @@ async function resolveProject(teamId, nameOrId, version2) {
|
|
|
522
522
|
tenant: chosen.tenant
|
|
523
523
|
};
|
|
524
524
|
}
|
|
525
|
-
var
|
|
525
|
+
var import_chalk9;
|
|
526
526
|
var init_resolve = __esm({
|
|
527
527
|
"src/lib/resolve.ts"() {
|
|
528
528
|
"use strict";
|
|
529
|
-
|
|
529
|
+
import_chalk9 = __toESM(require("chalk"));
|
|
530
530
|
init_auth();
|
|
531
531
|
init_api();
|
|
532
532
|
}
|
|
@@ -635,12 +635,12 @@ async function runIamToggle(project, state, opts) {
|
|
|
635
635
|
summary: `IAM ${state} for tenant ${tenant2}`
|
|
636
636
|
});
|
|
637
637
|
if (opts.quiet) return;
|
|
638
|
-
spinner?.succeed(`IAM is ${
|
|
638
|
+
spinner?.succeed(`IAM is ${import_chalk10.default.bold(state)} for tenant ${tenant2}.`);
|
|
639
639
|
if (opts.json) console.log(JSON.stringify(out ?? { iam_enabled: enabled }));
|
|
640
640
|
else if (enabled) {
|
|
641
|
-
console.log(
|
|
642
|
-
console.log(
|
|
643
|
-
console.log(
|
|
641
|
+
console.log(import_chalk10.default.dim(" Groups now apply to identified calls. Identify callers with"));
|
|
642
|
+
console.log(import_chalk10.default.dim(" X-End-User-Id, a login token, or per-user keys \u2014 and consider"));
|
|
643
|
+
console.log(import_chalk10.default.dim(` \`apiblaze identified ${project} require\` to reject unattributed traffic.`));
|
|
644
644
|
}
|
|
645
645
|
} catch (err) {
|
|
646
646
|
spinner?.fail(`IAM ${state} failed.`);
|
|
@@ -692,11 +692,11 @@ async function runIdentifiedToggle(project, mode, opts) {
|
|
|
692
692
|
throw err;
|
|
693
693
|
}
|
|
694
694
|
}
|
|
695
|
-
var
|
|
695
|
+
var import_chalk10, import_ora4;
|
|
696
696
|
var init_iam = __esm({
|
|
697
697
|
"src/commands/iam.ts"() {
|
|
698
698
|
"use strict";
|
|
699
|
-
|
|
699
|
+
import_chalk10 = __toESM(require("chalk"));
|
|
700
700
|
import_ora4 = __toESM(require("ora"));
|
|
701
701
|
init_caller();
|
|
702
702
|
}
|
|
@@ -714,7 +714,7 @@ async function createTenantRow(teamId) {
|
|
|
714
714
|
const { name } = await inquirer3.prompt([{
|
|
715
715
|
type: "input",
|
|
716
716
|
name: "name",
|
|
717
|
-
message: `Tenant name ${
|
|
717
|
+
message: `Tenant name ${import_chalk27.default.dim("(lowercase letters/numbers; globally unique \u2014 becomes {name}.portal.apiblaze.com)")}:`,
|
|
718
718
|
validate: (s) => /^[a-z0-9]+$/.test(s.trim()) ? true : "lowercase letters and numbers only"
|
|
719
719
|
}]);
|
|
720
720
|
const slug = name.trim();
|
|
@@ -729,7 +729,7 @@ async function createTenantRow(teamId) {
|
|
|
729
729
|
} catch (err) {
|
|
730
730
|
const msg = err instanceof Error ? err.message : String(err);
|
|
731
731
|
if (/taken|unique|exists|reserved|conflict/i.test(msg)) {
|
|
732
|
-
console.log(
|
|
732
|
+
console.log(import_chalk27.default.yellow(` "${slug}" is not available (tenant names are global): ${msg}`));
|
|
733
733
|
continue;
|
|
734
734
|
}
|
|
735
735
|
throw err;
|
|
@@ -746,11 +746,11 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
|
|
|
746
746
|
pageSize: 10,
|
|
747
747
|
choices: [
|
|
748
748
|
...PROVIDERS.map((p) => ({ name: p.label, value: p.id })),
|
|
749
|
-
...opts.allowSkip ? [new inquirer3.Separator(), { name:
|
|
749
|
+
...opts.allowSkip ? [new inquirer3.Separator(), { name: import_chalk27.default.dim("Skip for now \u2014 set up a login method later"), value: null }] : []
|
|
750
750
|
]
|
|
751
751
|
}]);
|
|
752
752
|
if (!provider) {
|
|
753
|
-
console.log(
|
|
753
|
+
console.log(import_chalk27.default.dim(" No login method yet \u2014 add one later under Login methods."));
|
|
754
754
|
return false;
|
|
755
755
|
}
|
|
756
756
|
const opt = PROVIDERS.find((p) => p.id === provider);
|
|
@@ -796,26 +796,26 @@ async function addApiblazeHostedLogin(teamId, tenant2, opts = {}) {
|
|
|
796
796
|
async function createTenantInteractive(teamId) {
|
|
797
797
|
const { default: inquirer3 } = await import("inquirer");
|
|
798
798
|
const tenant2 = await createTenantRow(teamId);
|
|
799
|
-
console.log(
|
|
799
|
+
console.log(import_chalk27.default.green(` Tenant ${import_chalk27.default.bold(tenant2)} created.`));
|
|
800
800
|
const { users } = await inquirer3.prompt([{
|
|
801
801
|
type: "confirm",
|
|
802
802
|
name: "users",
|
|
803
803
|
default: false,
|
|
804
|
-
message: `Enable Users & groups? ${
|
|
804
|
+
message: `Enable Users & groups? ${import_chalk27.default.dim(`(identity/key management at iam.apiblaze.com)`)}`
|
|
805
805
|
}]);
|
|
806
806
|
if (users) {
|
|
807
807
|
await admin({ method: "PATCH", path: `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}/iam`, body: { enabled: true }, summary: "Enable Users & groups" }).catch(() => {
|
|
808
808
|
});
|
|
809
|
-
console.log(
|
|
809
|
+
console.log(import_chalk27.default.green(" Users & groups enabled."));
|
|
810
810
|
}
|
|
811
811
|
await addApiblazeHostedLogin(teamId, tenant2, { allowSkip: true });
|
|
812
812
|
return tenant2;
|
|
813
813
|
}
|
|
814
|
-
var
|
|
814
|
+
var import_chalk27, import_ora10, PROVIDERS, DEFAULT_SCOPES;
|
|
815
815
|
var init_tenant_create = __esm({
|
|
816
816
|
"src/lib/tenant-create.ts"() {
|
|
817
817
|
"use strict";
|
|
818
|
-
|
|
818
|
+
import_chalk27 = __toESM(require("chalk"));
|
|
819
819
|
import_ora10 = __toESM(require("ora"));
|
|
820
820
|
init_admin();
|
|
821
821
|
PROVIDERS = [
|
|
@@ -854,10 +854,10 @@ async function fetchPage(teamId, q) {
|
|
|
854
854
|
}
|
|
855
855
|
function label(t, defaultTenant, active) {
|
|
856
856
|
const tags = [
|
|
857
|
-
t.tenant_name === active ?
|
|
858
|
-
t.tenant_name === defaultTenant ?
|
|
857
|
+
t.tenant_name === active ? import_chalk28.default.cyan("active scope") : "",
|
|
858
|
+
t.tenant_name === defaultTenant ? import_chalk28.default.dim("team default") : ""
|
|
859
859
|
].filter(Boolean).join(", ");
|
|
860
|
-
const disp = t.display_name && t.display_name !== t.tenant_name ?
|
|
860
|
+
const disp = t.display_name && t.display_name !== t.tenant_name ? import_chalk28.default.dim(` ${t.display_name}`) : "";
|
|
861
861
|
return `${t.tenant_name}${disp}${tags ? ` (${tags})` : ""}`;
|
|
862
862
|
}
|
|
863
863
|
async function pickTenant(teamId, opts = {}) {
|
|
@@ -872,7 +872,7 @@ async function pickTenant(teamId, opts = {}) {
|
|
|
872
872
|
const { make } = await inquirer3.prompt([{ type: "confirm", name: "make", message: "No tenants yet \u2014 create one?", default: true }]);
|
|
873
873
|
if (make) return await createTenantInline(teamId);
|
|
874
874
|
}
|
|
875
|
-
console.error(
|
|
875
|
+
console.error(import_chalk28.default.red("This team has no tenants. Create one with `apiblaze tenant create`."));
|
|
876
876
|
return null;
|
|
877
877
|
}
|
|
878
878
|
const truncated = page.total > page.rows.length;
|
|
@@ -881,7 +881,7 @@ async function pickTenant(teamId, opts = {}) {
|
|
|
881
881
|
value: t.tenant_name
|
|
882
882
|
}));
|
|
883
883
|
if (truncated || q) {
|
|
884
|
-
choices.push(new inquirer3.Separator(
|
|
884
|
+
choices.push(new inquirer3.Separator(import_chalk28.default.dim(
|
|
885
885
|
truncated ? `showing ${page.rows.length} of ${page.total}${q ? ` matching "${q}"` : ""} \u2014 search to narrow` : `matches for "${q}"`
|
|
886
886
|
)));
|
|
887
887
|
choices.push({ name: `\u{1F50D} Search${q ? " again" : ""}\u2026`, value: "\0search" });
|
|
@@ -915,11 +915,11 @@ async function createTenantInline(teamId) {
|
|
|
915
915
|
const { createTenantInteractive: createTenantInteractive2 } = await Promise.resolve().then(() => (init_tenant_create(), tenant_create_exports));
|
|
916
916
|
return createTenantInteractive2(teamId);
|
|
917
917
|
}
|
|
918
|
-
var
|
|
918
|
+
var import_chalk28, import_ora11, PAGE;
|
|
919
919
|
var init_tenant_pick = __esm({
|
|
920
920
|
"src/lib/tenant-pick.ts"() {
|
|
921
921
|
"use strict";
|
|
922
|
-
|
|
922
|
+
import_chalk28 = __toESM(require("chalk"));
|
|
923
923
|
import_ora11 = __toESM(require("ora"));
|
|
924
924
|
init_admin();
|
|
925
925
|
init_auth();
|
|
@@ -929,10 +929,10 @@ var init_tenant_pick = __esm({
|
|
|
929
929
|
|
|
930
930
|
// src/index.ts
|
|
931
931
|
var import_commander = require("commander");
|
|
932
|
-
var
|
|
932
|
+
var import_chalk45 = __toESM(require("chalk"));
|
|
933
933
|
|
|
934
934
|
// package.json
|
|
935
|
-
var version = "0.19.
|
|
935
|
+
var version = "0.19.28";
|
|
936
936
|
|
|
937
937
|
// src/index.ts
|
|
938
938
|
init_types();
|
|
@@ -1936,8 +1936,79 @@ ${projects.length} project${projects.length === 1 ? "" : "s"}`));
|
|
|
1936
1936
|
|
|
1937
1937
|
// src/commands/create.ts
|
|
1938
1938
|
var import_fs2 = __toESM(require("fs"));
|
|
1939
|
+
|
|
1940
|
+
// src/lib/tenant-choice.ts
|
|
1941
|
+
var import_chalk8 = __toESM(require("chalk"));
|
|
1942
|
+
init_admin();
|
|
1943
|
+
function decideTenant(input) {
|
|
1944
|
+
if (input.tenant) {
|
|
1945
|
+
const slug = input.tenant.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1946
|
+
return slug ? { kind: "use", tenant: slug } : { kind: "server-default" };
|
|
1947
|
+
}
|
|
1948
|
+
if (input.existing.length === 0) return { kind: "server-default" };
|
|
1949
|
+
const suggested = suggestTenantName(input.projectSlug, input.existing);
|
|
1950
|
+
if (input.existing.length === 1) return { kind: "use", tenant: input.existing[0] };
|
|
1951
|
+
if (!input.interactive) return { kind: "use", tenant: suggested };
|
|
1952
|
+
return { kind: "ask", existing: input.existing, suggested };
|
|
1953
|
+
}
|
|
1954
|
+
async function chooseTenantForCreate(teamId, projectSlug, opts) {
|
|
1955
|
+
if (opts.tenant) return opts.tenant.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1956
|
+
if (!teamId) return void 0;
|
|
1957
|
+
let existing = [];
|
|
1958
|
+
try {
|
|
1959
|
+
const rows = await admin({
|
|
1960
|
+
method: "GET",
|
|
1961
|
+
path: `/teams/${encodeURIComponent(teamId)}/tenants`,
|
|
1962
|
+
summary: "List tenants to place the new proxy"
|
|
1963
|
+
});
|
|
1964
|
+
const list = Array.isArray(rows) ? rows : rows?.tenants ?? [];
|
|
1965
|
+
existing = list.map((t) => t?.tenant_name ?? t?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
1966
|
+
} catch {
|
|
1967
|
+
return void 0;
|
|
1968
|
+
}
|
|
1969
|
+
const decision = decideTenant({
|
|
1970
|
+
existing,
|
|
1971
|
+
projectSlug,
|
|
1972
|
+
tenant: opts.tenant,
|
|
1973
|
+
yes: opts.yes,
|
|
1974
|
+
json: opts.json,
|
|
1975
|
+
interactive: !opts.yes && !opts.json && !!process.stdin.isTTY
|
|
1976
|
+
});
|
|
1977
|
+
if (decision.kind === "server-default") return void 0;
|
|
1978
|
+
if (decision.kind === "use") {
|
|
1979
|
+
if (!opts.json && !existing.includes(decision.tenant)) {
|
|
1980
|
+
console.log(import_chalk8.default.dim(` Placing this proxy in a new tenant "${decision.tenant}" (pass --tenant to choose another).`));
|
|
1981
|
+
}
|
|
1982
|
+
return decision.tenant;
|
|
1983
|
+
}
|
|
1984
|
+
const { existing: choices, suggested } = decision;
|
|
1985
|
+
const { default: inquirer3 } = await import("inquirer");
|
|
1986
|
+
const { pick: pick2 } = await inquirer3.prompt([
|
|
1987
|
+
{
|
|
1988
|
+
type: "list",
|
|
1989
|
+
name: "pick",
|
|
1990
|
+
message: "Which tenant should this proxy's consumers live in?",
|
|
1991
|
+
choices: [
|
|
1992
|
+
{ name: `${import_chalk8.default.green("\uFF0B")} New tenant "${suggested}" ${import_chalk8.default.dim("(its own portal, login and users)")}`, value: "\0new" },
|
|
1993
|
+
...choices.map((t) => ({ name: `${t} ${import_chalk8.default.dim("(share its portal, login app and users)")}`, value: t }))
|
|
1994
|
+
]
|
|
1995
|
+
}
|
|
1996
|
+
]);
|
|
1997
|
+
return pick2 === "\0new" ? suggested : pick2;
|
|
1998
|
+
}
|
|
1999
|
+
function suggestTenantName(projectSlug, taken) {
|
|
2000
|
+
const base2 = (projectSlug || "tenant").toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 24) || "tenant";
|
|
2001
|
+
if (!taken.includes(base2)) return base2;
|
|
2002
|
+
for (let i = 2; i < 100; i++) {
|
|
2003
|
+
const candidate = `${base2}${i}`;
|
|
2004
|
+
if (!taken.includes(candidate)) return candidate;
|
|
2005
|
+
}
|
|
2006
|
+
return `${base2}${Math.random().toString(36).slice(2, 7)}`;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
// src/commands/create.ts
|
|
1939
2010
|
var import_yaml = require("yaml");
|
|
1940
|
-
var
|
|
2011
|
+
var import_chalk11 = __toESM(require("chalk"));
|
|
1941
2012
|
var import_ora5 = __toESM(require("ora"));
|
|
1942
2013
|
init_auth();
|
|
1943
2014
|
init_api();
|
|
@@ -2000,7 +2071,7 @@ function stripTenantFromPortal(devPortal) {
|
|
|
2000
2071
|
}
|
|
2001
2072
|
}
|
|
2002
2073
|
function fail(message) {
|
|
2003
|
-
console.error(
|
|
2074
|
+
console.error(import_chalk11.default.red(`Error: ${message}`));
|
|
2004
2075
|
process.exit(1);
|
|
2005
2076
|
}
|
|
2006
2077
|
function buildTryItCurl(url, authType, apiKey) {
|
|
@@ -2015,11 +2086,11 @@ function printCurlExample(url, authType, apiKey, devPortal) {
|
|
|
2015
2086
|
const curl = buildTryItCurl(url, authType, apiKey);
|
|
2016
2087
|
console.log();
|
|
2017
2088
|
if (curl) {
|
|
2018
|
-
console.log(` ${
|
|
2019
|
-
console.log(` ${
|
|
2089
|
+
console.log(` ${import_chalk11.default.dim("Try it \u2014 copy/paste:")}`);
|
|
2090
|
+
console.log(` ${import_chalk11.default.cyan(curl)}`);
|
|
2020
2091
|
} else if (authType === "oauth") {
|
|
2021
|
-
console.log(` ${
|
|
2022
|
-
console.log(` ${
|
|
2092
|
+
console.log(` ${import_chalk11.default.dim("Try it:")} this proxy uses OAuth \u2014 sign in at ${import_chalk11.default.bold(devPortal ?? "the dev portal")} to get a token,`);
|
|
2093
|
+
console.log(` ${import_chalk11.default.dim(`then call ${url} with`)} ${import_chalk11.default.cyan('-H "Authorization: Bearer <token>"')}`);
|
|
2023
2094
|
}
|
|
2024
2095
|
}
|
|
2025
2096
|
var VALID_AUTH = ["api_key", "none", "oauth"];
|
|
@@ -2049,7 +2120,7 @@ async function runCreate(opts = {}) {
|
|
|
2049
2120
|
teamId = match.teamId;
|
|
2050
2121
|
}
|
|
2051
2122
|
}
|
|
2052
|
-
if (!opts.json) console.log(
|
|
2123
|
+
if (!opts.json) console.log(import_chalk11.default.bold("\nCreate an API proxy\n"));
|
|
2053
2124
|
let name = "";
|
|
2054
2125
|
if (opts.name !== void 0) {
|
|
2055
2126
|
name = normalizeName(opts.name);
|
|
@@ -2069,7 +2140,7 @@ async function runCreate(opts = {}) {
|
|
|
2069
2140
|
}]);
|
|
2070
2141
|
name = normalizeName(rawName);
|
|
2071
2142
|
if (name.length < 3) {
|
|
2072
|
-
console.log(
|
|
2143
|
+
console.log(import_chalk11.default.yellow(" Name must be at least 3 characters (letters and digits only).\n"));
|
|
2073
2144
|
continue;
|
|
2074
2145
|
}
|
|
2075
2146
|
const spinner2 = (0, import_ora5.default)("Checking availability...").start();
|
|
@@ -2077,15 +2148,15 @@ async function runCreate(opts = {}) {
|
|
|
2077
2148
|
const check = await checkProxyName(name, teamId, opts.apiversion);
|
|
2078
2149
|
spinner2.stop();
|
|
2079
2150
|
if (!check.canUseProjectName || !check.canUseApiVersion) {
|
|
2080
|
-
console.log(
|
|
2151
|
+
console.log(import_chalk11.default.yellow(` "${name}" is not available${check.message ? ` \u2014 ${check.message}` : ""}. Try another.
|
|
2081
2152
|
`));
|
|
2082
2153
|
continue;
|
|
2083
2154
|
}
|
|
2084
2155
|
} catch {
|
|
2085
2156
|
spinner2.stop();
|
|
2086
|
-
console.log(
|
|
2157
|
+
console.log(import_chalk11.default.dim(" (could not verify availability; continuing)"));
|
|
2087
2158
|
}
|
|
2088
|
-
console.log(`${
|
|
2159
|
+
console.log(`${import_chalk11.default.cyan("\u2192")} Your API will live at ${import_chalk11.default.bold(`https://${name}.abz.run`)}
|
|
2089
2160
|
`);
|
|
2090
2161
|
break;
|
|
2091
2162
|
}
|
|
@@ -2111,7 +2182,7 @@ async function runCreate(opts = {}) {
|
|
|
2111
2182
|
message: "Target URL to forward requests to (e.g. https://httpbin.org):"
|
|
2112
2183
|
}]);
|
|
2113
2184
|
if (!isHttpUrl(url)) {
|
|
2114
|
-
console.log(
|
|
2185
|
+
console.log(import_chalk11.default.yellow(" Enter a valid http(s) URL.\n"));
|
|
2115
2186
|
continue;
|
|
2116
2187
|
}
|
|
2117
2188
|
targetUrl = url.trim();
|
|
@@ -2122,7 +2193,7 @@ async function runCreate(opts = {}) {
|
|
|
2122
2193
|
}
|
|
2123
2194
|
if (interactive && !opts.yes) {
|
|
2124
2195
|
const { default: inquirer3 } = await import("inquirer");
|
|
2125
|
-
console.log(`${
|
|
2196
|
+
console.log(`${import_chalk11.default.cyan("\u2192")} Auth: ${import_chalk11.default.bold(auth)}${auth === "api_key" ? " \u2014 consumers send an X-API-Key header" : ""}`);
|
|
2126
2197
|
const { ok } = await inquirer3.prompt([{
|
|
2127
2198
|
type: "confirm",
|
|
2128
2199
|
name: "ok",
|
|
@@ -2130,10 +2201,15 @@ async function runCreate(opts = {}) {
|
|
|
2130
2201
|
default: true
|
|
2131
2202
|
}]);
|
|
2132
2203
|
if (!ok) {
|
|
2133
|
-
console.log(
|
|
2204
|
+
console.log(import_chalk11.default.yellow("Cancelled."));
|
|
2134
2205
|
return;
|
|
2135
2206
|
}
|
|
2136
2207
|
}
|
|
2208
|
+
const chosenTenant = await chooseTenantForCreate(teamId, name, {
|
|
2209
|
+
tenant: opts.tenant,
|
|
2210
|
+
yes: opts.yes,
|
|
2211
|
+
json: opts.json
|
|
2212
|
+
});
|
|
2137
2213
|
const spinner = !opts.json ? (0, import_ora5.default)("Creating proxy (tenant, keys, dev portal)...").start() : null;
|
|
2138
2214
|
let result;
|
|
2139
2215
|
try {
|
|
@@ -2142,10 +2218,10 @@ async function runCreate(opts = {}) {
|
|
|
2142
2218
|
...openapiContent ? { openapi: openapiContent } : { target_url: targetUrl },
|
|
2143
2219
|
auth_type: auth,
|
|
2144
2220
|
team_id: teamId,
|
|
2145
|
-
...
|
|
2221
|
+
...chosenTenant ? { tenant: chosenTenant } : {},
|
|
2146
2222
|
...opts.apiversion ? { api_version: opts.apiversion } : {}
|
|
2147
2223
|
});
|
|
2148
|
-
spinner?.succeed(
|
|
2224
|
+
spinner?.succeed(import_chalk11.default.green("Proxy created!"));
|
|
2149
2225
|
} catch (err) {
|
|
2150
2226
|
spinner?.fail("Failed to create proxy.");
|
|
2151
2227
|
throw err;
|
|
@@ -2170,16 +2246,16 @@ async function runCreate(opts = {}) {
|
|
|
2170
2246
|
return;
|
|
2171
2247
|
}
|
|
2172
2248
|
console.log();
|
|
2173
|
-
console.log(` ${
|
|
2174
|
-
if (devPortal) console.log(` ${
|
|
2249
|
+
console.log(` ${import_chalk11.default.dim("Proxy URL: ")} ${import_chalk11.default.bold(proxyUrl)}`);
|
|
2250
|
+
if (devPortal) console.log(` ${import_chalk11.default.dim("Dev portal:")} ${import_chalk11.default.bold(devPortal)}`);
|
|
2175
2251
|
if (adminKey) {
|
|
2176
2252
|
console.log();
|
|
2177
|
-
console.log(` ${
|
|
2178
|
-
console.log(` ${
|
|
2179
|
-
console.log(
|
|
2253
|
+
console.log(` ${import_chalk11.default.dim("Consumer admin API key (dev):")}`);
|
|
2254
|
+
console.log(` ${import_chalk11.default.bold.green(adminKey)}`);
|
|
2255
|
+
console.log(import_chalk11.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
|
|
2180
2256
|
const otherEnvs = Object.keys(keys).filter((e) => e !== "dev");
|
|
2181
2257
|
if (otherEnvs.length) {
|
|
2182
|
-
console.log(
|
|
2258
|
+
console.log(import_chalk11.default.dim(` (Separate keys were also created for: ${otherEnvs.join(", ")}.)`));
|
|
2183
2259
|
}
|
|
2184
2260
|
}
|
|
2185
2261
|
printCurlExample(proxyUrl, auth, adminKey, devPortal);
|
|
@@ -2195,8 +2271,8 @@ async function applyCreateToggles(name, opts) {
|
|
|
2195
2271
|
async function runAnonymousCreate(opts) {
|
|
2196
2272
|
const interactive = !!process.stdin.isTTY && !opts.json;
|
|
2197
2273
|
if (!opts.json) {
|
|
2198
|
-
console.log(
|
|
2199
|
-
console.log(
|
|
2274
|
+
console.log(import_chalk11.default.bold("\nCreate an API proxy"));
|
|
2275
|
+
console.log(import_chalk11.default.dim("Not logged in \u2014 creating an anonymous proxy. You can claim it to your account within 30 days.\n"));
|
|
2200
2276
|
}
|
|
2201
2277
|
let body = {};
|
|
2202
2278
|
if (opts.config) {
|
|
@@ -2245,7 +2321,7 @@ async function runAnonymousCreate(opts) {
|
|
|
2245
2321
|
message: "Target URL to forward requests to (e.g. https://httpbin.org):"
|
|
2246
2322
|
}]);
|
|
2247
2323
|
if (!isHttpUrl(url)) {
|
|
2248
|
-
console.log(
|
|
2324
|
+
console.log(import_chalk11.default.yellow(" Enter a valid http(s) URL.\n"));
|
|
2249
2325
|
continue;
|
|
2250
2326
|
}
|
|
2251
2327
|
target = url.trim();
|
|
@@ -2286,7 +2362,7 @@ async function runAnonymousCreate(opts) {
|
|
|
2286
2362
|
saveAnonCred2(result.cp_key, result.team_id, result.claim_code);
|
|
2287
2363
|
}
|
|
2288
2364
|
}
|
|
2289
|
-
spinner?.succeed(
|
|
2365
|
+
spinner?.succeed(import_chalk11.default.green("Proxy created!"));
|
|
2290
2366
|
} catch (err) {
|
|
2291
2367
|
spinner?.fail("Failed to create proxy.");
|
|
2292
2368
|
throw err;
|
|
@@ -2309,36 +2385,36 @@ async function runAnonymousCreate(opts) {
|
|
|
2309
2385
|
return;
|
|
2310
2386
|
}
|
|
2311
2387
|
console.log();
|
|
2312
|
-
if (prodEndpoint) console.log(` ${
|
|
2313
|
-
if (result.portal) console.log(` ${
|
|
2388
|
+
if (prodEndpoint) console.log(` ${import_chalk11.default.dim("Proxy URL: ")} ${import_chalk11.default.bold(prodEndpoint)}`);
|
|
2389
|
+
if (result.portal) console.log(` ${import_chalk11.default.dim("Dev portal:")} ${import_chalk11.default.bold(result.portal)}`);
|
|
2314
2390
|
if (apiKey) {
|
|
2315
2391
|
console.log();
|
|
2316
|
-
console.log(` ${
|
|
2317
|
-
console.log(` ${
|
|
2318
|
-
console.log(
|
|
2392
|
+
console.log(` ${import_chalk11.default.dim("API key:")}`);
|
|
2393
|
+
console.log(` ${import_chalk11.default.bold.green(apiKey)}`);
|
|
2394
|
+
console.log(import_chalk11.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
|
|
2319
2395
|
}
|
|
2320
2396
|
if (prodEndpoint) printCurlExample(prodEndpoint, opts.auth || "api_key", apiKey, result.portal);
|
|
2321
2397
|
const claimCode = result.claim_code || cred?.claim_code;
|
|
2322
2398
|
if (claimCode) {
|
|
2323
2399
|
console.log();
|
|
2324
|
-
console.log(` ${
|
|
2325
|
-
console.log(` ${
|
|
2400
|
+
console.log(` ${import_chalk11.default.yellow("\u26A0 Anonymous \u2014 claim within 30 days or it expires.")} To claim these proxies:`);
|
|
2401
|
+
console.log(` ${import_chalk11.default.cyan(`npx apiblaze login && npx apiblaze claim ${claimCode}`)}`);
|
|
2326
2402
|
} else if (result.claim_url) {
|
|
2327
2403
|
console.log();
|
|
2328
|
-
console.log(` ${
|
|
2329
|
-
console.log(` ${
|
|
2404
|
+
console.log(` ${import_chalk11.default.yellow("\u26A0 Anonymous proxy \u2014 claim it to your account within 30 days or it expires:")}`);
|
|
2405
|
+
console.log(` ${import_chalk11.default.bold(result.claim_url)}`);
|
|
2330
2406
|
}
|
|
2331
2407
|
console.log();
|
|
2332
2408
|
}
|
|
2333
2409
|
|
|
2334
2410
|
// src/commands/claim.ts
|
|
2335
|
-
var
|
|
2411
|
+
var import_chalk12 = __toESM(require("chalk"));
|
|
2336
2412
|
init_auth();
|
|
2337
2413
|
init_anon_cred();
|
|
2338
2414
|
init_api();
|
|
2339
2415
|
init_types();
|
|
2340
2416
|
function fail2(message) {
|
|
2341
|
-
console.error(
|
|
2417
|
+
console.error(import_chalk12.default.red(`Error: ${message}`));
|
|
2342
2418
|
process.exit(1);
|
|
2343
2419
|
}
|
|
2344
2420
|
async function runClaim(claimCodeArg, opts) {
|
|
@@ -2374,9 +2450,9 @@ async function runClaim(claimCodeArg, opts) {
|
|
|
2374
2450
|
const c = typeof err.body === "object" && err.body ? err.body.error : void 0;
|
|
2375
2451
|
if (c === "already_claimed" || c === "not_claimable") {
|
|
2376
2452
|
if (fromLocal) clearAnonCred();
|
|
2377
|
-
console.log(
|
|
2378
|
-
if (fromLocal) console.log(
|
|
2379
|
-
console.log(
|
|
2453
|
+
console.log(import_chalk12.default.yellow("\nThis workspace was already claimed (e.g. on dashboard.apiblaze.com)."));
|
|
2454
|
+
if (fromLocal) console.log(import_chalk12.default.dim(" Cleared the local anonymous key."));
|
|
2455
|
+
console.log(import_chalk12.default.dim(" Your proxies are safe under your account \u2014 manage them with `apiblaze login`."));
|
|
2380
2456
|
return;
|
|
2381
2457
|
}
|
|
2382
2458
|
if (c === "expired") {
|
|
@@ -2394,20 +2470,20 @@ async function runClaim(claimCodeArg, opts) {
|
|
|
2394
2470
|
console.log(JSON.stringify(res, null, 2));
|
|
2395
2471
|
return;
|
|
2396
2472
|
}
|
|
2397
|
-
console.log(
|
|
2473
|
+
console.log(import_chalk12.default.green("\n\u2714 Claimed your anonymous workspace into your account."));
|
|
2398
2474
|
if (res.merged) {
|
|
2399
|
-
console.log(` Merged ${
|
|
2475
|
+
console.log(` Merged ${import_chalk12.default.bold(String(res.proxy_count ?? ""))} prox${res.proxy_count === 1 ? "y" : "ies"} into team ${import_chalk12.default.bold(res.team_id)}.`);
|
|
2400
2476
|
} else {
|
|
2401
2477
|
const label3 = res.team_name ? `\u201C${res.team_name}\u201D` : res.team_id;
|
|
2402
|
-
console.log(` It's now your team ${
|
|
2403
|
-
console.log(
|
|
2478
|
+
console.log(` It's now your team ${import_chalk12.default.bold(label3)}. Switch to it with ${import_chalk12.default.cyan(`apiblaze team ${res.team_id}`)}.`);
|
|
2479
|
+
console.log(import_chalk12.default.dim(` (Tip: name it with --name, or --team <name> to merge into an existing team instead.)`));
|
|
2404
2480
|
}
|
|
2405
2481
|
console.log(`
|
|
2406
|
-
Manage it at ${
|
|
2482
|
+
Manage it at ${import_chalk12.default.cyan("https://dashboard.apiblaze.com/dashboard")}`);
|
|
2407
2483
|
}
|
|
2408
2484
|
|
|
2409
2485
|
// src/commands/logout.ts
|
|
2410
|
-
var
|
|
2486
|
+
var import_chalk13 = __toESM(require("chalk"));
|
|
2411
2487
|
init_auth();
|
|
2412
2488
|
|
|
2413
2489
|
// src/lib/consumer-auth.ts
|
|
@@ -2539,7 +2615,7 @@ async function runLogout(opts = {}) {
|
|
|
2539
2615
|
const creds = loadCredentials();
|
|
2540
2616
|
const consumer2 = loadConsumer();
|
|
2541
2617
|
if (!creds && !consumer2) {
|
|
2542
|
-
console.log(
|
|
2618
|
+
console.log(import_chalk13.default.yellow("You were not logged in."));
|
|
2543
2619
|
return;
|
|
2544
2620
|
}
|
|
2545
2621
|
let target;
|
|
@@ -2566,16 +2642,16 @@ async function runLogout(opts = {}) {
|
|
|
2566
2642
|
}
|
|
2567
2643
|
if (target === "producer" || target === "all") {
|
|
2568
2644
|
clearCredentials();
|
|
2569
|
-
console.log(
|
|
2645
|
+
console.log(import_chalk13.default.green(`\u2714 Logged out of API Producer${creds?.githubHandle ? ` (${creds.githubHandle})` : ""}.`));
|
|
2570
2646
|
}
|
|
2571
2647
|
if (target === "consumer" || target === "all") {
|
|
2572
2648
|
clearConsumer();
|
|
2573
|
-
console.log(
|
|
2649
|
+
console.log(import_chalk13.default.green(`\u2714 Logged out of API Consumer${consumer2?.tenant ? ` (${consumer2.tenant})` : ""}.`));
|
|
2574
2650
|
}
|
|
2575
2651
|
}
|
|
2576
2652
|
|
|
2577
2653
|
// src/commands/flush.ts
|
|
2578
|
-
var
|
|
2654
|
+
var import_chalk14 = __toESM(require("chalk"));
|
|
2579
2655
|
var fs6 = __toESM(require("fs"));
|
|
2580
2656
|
var path4 = __toESM(require("path"));
|
|
2581
2657
|
init_auth();
|
|
@@ -2583,22 +2659,22 @@ async function runFlush(opts) {
|
|
|
2583
2659
|
const dir = getApiblazeDir();
|
|
2584
2660
|
const entries2 = fs6.existsSync(dir) ? fs6.readdirSync(dir) : [];
|
|
2585
2661
|
if (!entries2.length) {
|
|
2586
|
-
console.log(
|
|
2662
|
+
console.log(import_chalk14.default.dim("Nothing to flush \u2014 no local apiblaze config found."));
|
|
2587
2663
|
return;
|
|
2588
2664
|
}
|
|
2589
|
-
console.log(
|
|
2590
|
-
console.log(
|
|
2591
|
-
console.log(
|
|
2592
|
-
console.log(
|
|
2593
|
-
console.log(
|
|
2594
|
-
console.log(
|
|
2665
|
+
console.log(import_chalk14.default.yellow("This removes ALL local apiblaze state from this machine:"));
|
|
2666
|
+
console.log(import_chalk14.default.dim(" \u2022 login credentials & anonymous-workspace keys"));
|
|
2667
|
+
console.log(import_chalk14.default.dim(" \u2022 saved apichats \u2014 their DP API keys and transcripts"));
|
|
2668
|
+
console.log(import_chalk14.default.dim(" \u2022 your BYO LLM key and any cached secrets"));
|
|
2669
|
+
console.log(import_chalk14.default.dim(` (${entries2.length} item(s) in ${dir})`));
|
|
2670
|
+
console.log(import_chalk14.default.dim(" It does NOT delete server-side proxies/keys \u2014 those GC or are revoked separately."));
|
|
2595
2671
|
if (!opts.yes) {
|
|
2596
2672
|
const { default: inquirer3 } = await import("inquirer");
|
|
2597
2673
|
const { ok } = await inquirer3.prompt([
|
|
2598
2674
|
{ type: "confirm", name: "ok", message: "Delete all local state?", default: false }
|
|
2599
2675
|
]);
|
|
2600
2676
|
if (!ok) {
|
|
2601
|
-
console.log(
|
|
2677
|
+
console.log(import_chalk14.default.dim("Cancelled \u2014 nothing removed."));
|
|
2602
2678
|
return;
|
|
2603
2679
|
}
|
|
2604
2680
|
}
|
|
@@ -2608,14 +2684,14 @@ async function runFlush(opts) {
|
|
|
2608
2684
|
fs6.rmSync(path4.join(dir, e), { recursive: true, force: true });
|
|
2609
2685
|
removed++;
|
|
2610
2686
|
} catch (err) {
|
|
2611
|
-
console.log(
|
|
2687
|
+
console.log(import_chalk14.default.red(` \u2717 could not remove ${e}: ${err instanceof Error ? err.message : "error"}`));
|
|
2612
2688
|
}
|
|
2613
2689
|
}
|
|
2614
|
-
console.log(`${
|
|
2690
|
+
console.log(`${import_chalk14.default.green("\u2714")} Flushed \u2014 removed ${removed} item(s). You're fully logged out and clean.`);
|
|
2615
2691
|
}
|
|
2616
2692
|
|
|
2617
2693
|
// src/commands/whoami.ts
|
|
2618
|
-
var
|
|
2694
|
+
var import_chalk15 = __toESM(require("chalk"));
|
|
2619
2695
|
init_auth();
|
|
2620
2696
|
init_anon_cred();
|
|
2621
2697
|
async function runWhoami(opts = {}) {
|
|
@@ -2638,43 +2714,43 @@ async function runWhoami(opts = {}) {
|
|
|
2638
2714
|
}, null, 2));
|
|
2639
2715
|
return;
|
|
2640
2716
|
}
|
|
2641
|
-
console.log(
|
|
2717
|
+
console.log(import_chalk15.default.bold("API Producer"));
|
|
2642
2718
|
if (!creds) {
|
|
2643
|
-
console.log(
|
|
2719
|
+
console.log(import_chalk15.default.dim(" Not logged in. Run `apiblaze login`."));
|
|
2644
2720
|
} else {
|
|
2645
2721
|
const who = creds.githubHandle ?? creds.email ?? creds.apiblazeUserId ?? "unknown";
|
|
2646
|
-
console.log(` ${
|
|
2722
|
+
console.log(` ${import_chalk15.default.cyan("Signed in as")} ${import_chalk15.default.bold(who)}`);
|
|
2647
2723
|
if (creds.email && creds.email !== who) console.log(` Email: ${creds.email}`);
|
|
2648
|
-
if (creds.teamName || creds.teamId) console.log(` Team: ${
|
|
2649
|
-
if (creds.activeTenant) console.log(` Tenant scope: ${
|
|
2650
|
-
if (Date.now() >= creds.expiresAt) console.log(
|
|
2724
|
+
if (creds.teamName || creds.teamId) console.log(` Team: ${import_chalk15.default.bold(creds.teamName ?? creds.teamId)}`);
|
|
2725
|
+
if (creds.activeTenant) console.log(` Tenant scope: ${import_chalk15.default.bold(creds.activeTenant)} ${import_chalk15.default.dim("(clear: `apiblaze tenant use --clear`)")}`);
|
|
2726
|
+
if (Date.now() >= creds.expiresAt) console.log(import_chalk15.default.yellow(" \u26A0 Session expired \u2014 run `apiblaze login`."));
|
|
2651
2727
|
}
|
|
2652
2728
|
if (anon) {
|
|
2653
2729
|
const masked = `${anon.cp_key.slice(0, 11)}\u2026${anon.cp_key.slice(-4)}`;
|
|
2654
|
-
console.log(
|
|
2655
|
-
console.log(` Team: ${
|
|
2656
|
-
console.log(` CP key: ${
|
|
2730
|
+
console.log(import_chalk15.default.bold("\nAnonymous workspace") + import_chalk15.default.dim(" (created without an account \u2014 unclaimed)"));
|
|
2731
|
+
console.log(` Team: ${import_chalk15.default.bold(anon.team_id)}`);
|
|
2732
|
+
console.log(` CP key: ${import_chalk15.default.bold(masked)} ${import_chalk15.default.dim("controls the proxies you created anonymously")}`);
|
|
2657
2733
|
console.log(
|
|
2658
|
-
|
|
2734
|
+
import_chalk15.default.dim(` Keep it: ${import_chalk15.default.cyan("apiblaze login")} then ${import_chalk15.default.cyan("apiblaze claim")}`) + (anon.claim_code ? import_chalk15.default.dim(` \xB7 from another machine: ${import_chalk15.default.cyan(`apiblaze claim ${anon.claim_code}`)}`) : "")
|
|
2659
2735
|
);
|
|
2660
|
-
if (creds) console.log(
|
|
2736
|
+
if (creds) console.log(import_chalk15.default.dim(" (you're logged in \u2014 `apiblaze claim` folds this workspace into your account)"));
|
|
2661
2737
|
}
|
|
2662
|
-
console.log(
|
|
2738
|
+
console.log(import_chalk15.default.bold("\nAPI Consumer"));
|
|
2663
2739
|
if (!consumer2) {
|
|
2664
|
-
console.log(
|
|
2740
|
+
console.log(import_chalk15.default.dim(" Not logged in. Run `apiblaze consumer login`."));
|
|
2665
2741
|
} else {
|
|
2666
|
-
console.log(` ${
|
|
2667
|
-
console.log(` Tenant: ${
|
|
2668
|
-
if (Date.now() >= consumer2.expiresAt) console.log(
|
|
2742
|
+
console.log(` ${import_chalk15.default.cyan("Signed in as")} ${import_chalk15.default.bold(consumer2.email ?? consumer2.tenant)}`);
|
|
2743
|
+
console.log(` Tenant: ${import_chalk15.default.bold(consumer2.tenant)}`);
|
|
2744
|
+
if (Date.now() >= consumer2.expiresAt) console.log(import_chalk15.default.yellow(" \u26A0 Token expired \u2014 it will refresh on next use, or re-run `apiblaze consumer login`."));
|
|
2669
2745
|
}
|
|
2670
2746
|
}
|
|
2671
2747
|
|
|
2672
2748
|
// src/commands/team.ts
|
|
2673
|
-
var
|
|
2749
|
+
var import_chalk16 = __toESM(require("chalk"));
|
|
2674
2750
|
init_auth();
|
|
2675
2751
|
init_api();
|
|
2676
2752
|
function fail3(message) {
|
|
2677
|
-
console.error(
|
|
2753
|
+
console.error(import_chalk16.default.red(`Error: ${message}`));
|
|
2678
2754
|
process.exit(1);
|
|
2679
2755
|
}
|
|
2680
2756
|
async function runTeam(arg) {
|
|
@@ -2696,7 +2772,7 @@ async function runTeam(arg) {
|
|
|
2696
2772
|
}
|
|
2697
2773
|
} else if (teams.length === 1) {
|
|
2698
2774
|
chosen = teams[0];
|
|
2699
|
-
console.log(`${
|
|
2775
|
+
console.log(`${import_chalk16.default.cyan("\u2192")} You only have one team: ${import_chalk16.default.bold(chosen.name)}`);
|
|
2700
2776
|
} else if (process.stdin.isTTY) {
|
|
2701
2777
|
const { default: inquirer3 } = await import("inquirer");
|
|
2702
2778
|
const { picked } = await inquirer3.prompt([{
|
|
@@ -2711,48 +2787,48 @@ async function runTeam(arg) {
|
|
|
2711
2787
|
fail3(`Specify a team: \`apiblaze team <name|id>\`. Available: ${teams.map((t) => t.name).join(", ")}.`);
|
|
2712
2788
|
}
|
|
2713
2789
|
saveCredentials({ ...creds, teamId: chosen.teamId, teamName: chosen.name });
|
|
2714
|
-
console.log(
|
|
2715
|
-
\u2714 Active team: ${
|
|
2790
|
+
console.log(import_chalk16.default.green(`
|
|
2791
|
+
\u2714 Active team: ${import_chalk16.default.bold(chosen.name)}`));
|
|
2716
2792
|
}
|
|
2717
2793
|
|
|
2718
2794
|
// src/commands/authz.ts
|
|
2719
|
-
var
|
|
2795
|
+
var import_chalk19 = __toESM(require("chalk"));
|
|
2720
2796
|
init_auth();
|
|
2721
2797
|
init_api();
|
|
2722
2798
|
|
|
2723
2799
|
// src/lib/agent-chat.ts
|
|
2724
2800
|
var import_readline = __toESM(require("readline"));
|
|
2725
|
-
var
|
|
2801
|
+
var import_chalk17 = __toESM(require("chalk"));
|
|
2726
2802
|
init_api();
|
|
2727
2803
|
init_admin();
|
|
2728
2804
|
async function runAgentChatRepl(opts) {
|
|
2729
2805
|
const { title, subtitle, endpoint, buildBody, seedPrompt, summarizeProposal, commands } = opts;
|
|
2730
|
-
console.log("\n" +
|
|
2731
|
-
if (subtitle) console.log(
|
|
2806
|
+
console.log("\n" + import_chalk17.default.cyan.bold(title));
|
|
2807
|
+
if (subtitle) console.log(import_chalk17.default.dim(subtitle));
|
|
2732
2808
|
const messages = [];
|
|
2733
2809
|
const ctx = { proposal: null, lastData: null, log: (s) => console.log(s) };
|
|
2734
2810
|
const cmdByName = new Map(commands.map((c) => [c.name, c]));
|
|
2735
2811
|
const footer = () => {
|
|
2736
2812
|
const parts = [
|
|
2737
|
-
|
|
2738
|
-
...commands.map((c) =>
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2813
|
+
import_chalk17.default.dim("type to chat/refine"),
|
|
2814
|
+
...commands.map((c) => import_chalk17.default.dim(`/${c.name} ${c.describe}`)),
|
|
2815
|
+
import_chalk17.default.dim("/show"),
|
|
2816
|
+
import_chalk17.default.dim("/exit when done"),
|
|
2817
|
+
import_chalk17.default.dim("/drop discard changes")
|
|
2742
2818
|
];
|
|
2743
|
-
return " " +
|
|
2819
|
+
return " " + import_chalk17.default.dim("[ ") + parts.join(import_chalk17.default.dim(" \xB7 ")) + import_chalk17.default.dim(" ]");
|
|
2744
2820
|
};
|
|
2745
2821
|
async function turn(content) {
|
|
2746
2822
|
messages.push({ role: "user", content });
|
|
2747
|
-
process.stdout.write(
|
|
2823
|
+
process.stdout.write(import_chalk17.default.dim(" \u2026thinking\n"));
|
|
2748
2824
|
const { status, data } = await agentCall(endpoint, "POST", { messages, ...buildBody(messages) });
|
|
2749
2825
|
if (status === 402) {
|
|
2750
|
-
console.log(
|
|
2826
|
+
console.log(import_chalk17.default.red(" Insufficient credits \u2014 top up to keep using the agents.\n"));
|
|
2751
2827
|
messages.pop();
|
|
2752
2828
|
return;
|
|
2753
2829
|
}
|
|
2754
2830
|
if (status >= 400 || !data) {
|
|
2755
|
-
console.log(
|
|
2831
|
+
console.log(import_chalk17.default.red(` Error (${status}): ${(data && data.error) ?? "request failed"}
|
|
2756
2832
|
`));
|
|
2757
2833
|
messages.pop();
|
|
2758
2834
|
return;
|
|
@@ -2760,24 +2836,24 @@ async function runAgentChatRepl(opts) {
|
|
|
2760
2836
|
ctx.lastData = data;
|
|
2761
2837
|
const reply = data.reply ?? data.message ?? "(no reply)";
|
|
2762
2838
|
messages.push({ role: "assistant", content: reply });
|
|
2763
|
-
console.log("\n" +
|
|
2839
|
+
console.log("\n" + import_chalk17.default.cyan("agent \u203A ") + reply + "\n");
|
|
2764
2840
|
if (data.proposal) {
|
|
2765
2841
|
ctx.proposal = data.proposal;
|
|
2766
2842
|
const summary = summarizeProposal?.(data);
|
|
2767
|
-
if (summary) console.log(
|
|
2843
|
+
if (summary) console.log(import_chalk17.default.yellow(" " + summary));
|
|
2768
2844
|
const applies = commands.filter((c) => c.needsProposal);
|
|
2769
2845
|
const primary = applies[applies.length - 1];
|
|
2770
2846
|
if (primary) {
|
|
2771
|
-
console.log(
|
|
2847
|
+
console.log(import_chalk17.default.bold.green(" \u279C Next: type ") + import_chalk17.default.bold.cyan(`/${primary.name}`) + import_chalk17.default.bold.green(" to apply this, then ") + import_chalk17.default.bold.cyan("/exit") + import_chalk17.default.bold.green(" to leave."));
|
|
2772
2848
|
const rest = applies.slice(0, -1).map((c) => `/${c.name} = ${c.describe}`).join(" \xB7 ");
|
|
2773
|
-
console.log(
|
|
2849
|
+
console.log(import_chalk17.default.dim(` (or keep chatting to refine${rest ? ` \xB7 ${rest}` : ""} \xB7 /show = inspect)`));
|
|
2774
2850
|
}
|
|
2775
2851
|
console.log();
|
|
2776
2852
|
}
|
|
2777
2853
|
const line = formatBilling(data.billing);
|
|
2778
2854
|
if (line) {
|
|
2779
2855
|
const llm2 = data.llm;
|
|
2780
|
-
console.log(
|
|
2856
|
+
console.log(import_chalk17.default.dim(` ${line}${llm2?.model ? ` \xB7 ${llm2.model}` : ""}`));
|
|
2781
2857
|
}
|
|
2782
2858
|
}
|
|
2783
2859
|
const rl = import_readline.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -2785,31 +2861,31 @@ async function runAgentChatRepl(opts) {
|
|
|
2785
2861
|
await turn(seedPrompt);
|
|
2786
2862
|
for (; ; ) {
|
|
2787
2863
|
console.log(footer());
|
|
2788
|
-
const line = (await ask(
|
|
2864
|
+
const line = (await ask(import_chalk17.default.green("you \u203A "))).trim();
|
|
2789
2865
|
if (!line) continue;
|
|
2790
2866
|
const lower = line.toLowerCase();
|
|
2791
2867
|
if (line === "/exit" || line === "/quit" || lower === "exit" || lower === "quit" || lower === "q") {
|
|
2792
|
-
console.log(
|
|
2868
|
+
console.log(import_chalk17.default.dim(" Bye \u2014 anything you enabled or published stays in place.\n"));
|
|
2793
2869
|
break;
|
|
2794
2870
|
}
|
|
2795
2871
|
if (line === "/drop") {
|
|
2796
|
-
console.log(
|
|
2872
|
+
console.log(import_chalk17.default.dim(" Dropped the pending proposal \u2014 rules you already enabled/published are untouched.\n"));
|
|
2797
2873
|
break;
|
|
2798
2874
|
}
|
|
2799
2875
|
if (line === "/show") {
|
|
2800
|
-
if (!ctx.proposal) console.log(
|
|
2876
|
+
if (!ctx.proposal) console.log(import_chalk17.default.dim(" No proposal yet \u2014 keep chatting until the agent proposes one.\n"));
|
|
2801
2877
|
else console.log("\n" + JSON.stringify(ctx.proposal, null, 2) + "\n");
|
|
2802
2878
|
continue;
|
|
2803
2879
|
}
|
|
2804
2880
|
if (line.startsWith("/")) {
|
|
2805
2881
|
const cmd = cmdByName.get(line.slice(1));
|
|
2806
2882
|
if (!cmd) {
|
|
2807
|
-
console.log(
|
|
2883
|
+
console.log(import_chalk17.default.red(` Unknown command "${line}". Try one of: ${commands.map((c) => "/" + c.name).join(", ")}, /show, /drop
|
|
2808
2884
|
`));
|
|
2809
2885
|
continue;
|
|
2810
2886
|
}
|
|
2811
2887
|
if (cmd.needsProposal && !ctx.proposal) {
|
|
2812
|
-
console.log(
|
|
2888
|
+
console.log(import_chalk17.default.yellow(" No proposal yet \u2014 keep chatting until the agent generates one, then try again.\n"));
|
|
2813
2889
|
continue;
|
|
2814
2890
|
}
|
|
2815
2891
|
await cmd.run(ctx);
|
|
@@ -2821,7 +2897,7 @@ async function runAgentChatRepl(opts) {
|
|
|
2821
2897
|
}
|
|
2822
2898
|
|
|
2823
2899
|
// src/lib/authz-apply.ts
|
|
2824
|
-
var
|
|
2900
|
+
var import_chalk18 = __toESM(require("chalk"));
|
|
2825
2901
|
init_api();
|
|
2826
2902
|
async function gatherSampleIds(projectId, apiVersion, cap = 50) {
|
|
2827
2903
|
try {
|
|
@@ -2846,10 +2922,10 @@ async function gatherSampleIds(projectId, apiVersion, cap = 50) {
|
|
|
2846
2922
|
}
|
|
2847
2923
|
function maybeWarnNoTraffic(total, projectArg) {
|
|
2848
2924
|
if (total >= 3) return;
|
|
2849
|
-
console.log(
|
|
2850
|
-
console.log(
|
|
2851
|
-
console.log(
|
|
2852
|
-
console.log(
|
|
2925
|
+
console.log(import_chalk18.default.yellow(total === 0 ? " \u26A0 No captured traffic for this API yet." : ` \u26A0 Only ${total} captured request(s) so far.`));
|
|
2926
|
+
console.log(import_chalk18.default.dim(" The authorization agent designs much better models & rules from REAL requests"));
|
|
2927
|
+
console.log(import_chalk18.default.dim(" (it sees who is allowed vs denied). Send some through your proxy first \u2014"));
|
|
2928
|
+
console.log(import_chalk18.default.dim(` curl a few endpoints, or `) + import_chalk18.default.cyan("npx apiblaze dev") + import_chalk18.default.dim(` \u2014 then re-run.
|
|
2853
2929
|
`));
|
|
2854
2930
|
}
|
|
2855
2931
|
async function applyProposal(opts) {
|
|
@@ -2858,11 +2934,11 @@ async function applyProposal(opts) {
|
|
|
2858
2934
|
{
|
|
2859
2935
|
const m = await agentCall(`/projects/${projectId}/${apiVersion}/policies/model?tenantId=${encodeURIComponent(tenant2)}`, "POST", proposal.model);
|
|
2860
2936
|
if (m.status === 404) {
|
|
2861
|
-
log(
|
|
2937
|
+
log(import_chalk18.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"));
|
|
2862
2938
|
return { ok: 0, fail: 0, enabled: false, storeMissing: true };
|
|
2863
2939
|
}
|
|
2864
2940
|
if (m.status >= 400) {
|
|
2865
|
-
log(
|
|
2941
|
+
log(import_chalk18.default.red(` Model save failed (${m.status}): ${m.data?.error ?? ""}
|
|
2866
2942
|
`));
|
|
2867
2943
|
return { ok: 0, fail: 0, enabled: false };
|
|
2868
2944
|
}
|
|
@@ -2891,7 +2967,7 @@ async function applyProposal(opts) {
|
|
|
2891
2967
|
if (enable) {
|
|
2892
2968
|
const e = await agentCall(`/projects/${projectId}/${apiVersion}`, "PATCH", { authorization: { enforce_authorization: true }, tenant: tenant2 });
|
|
2893
2969
|
if (e.status >= 400) {
|
|
2894
|
-
log(
|
|
2970
|
+
log(import_chalk18.default.red(` Enforced ${ok} route(s) but turning on the project-level switch failed (${e.status}). Toggle "Enforce Authorization" on in the dashboard.
|
|
2895
2971
|
`));
|
|
2896
2972
|
return { ok, fail: fail5, enabled: false };
|
|
2897
2973
|
}
|
|
@@ -2917,10 +2993,10 @@ async function runAuthz(projectArg, apiVersionArg) {
|
|
|
2917
2993
|
const r = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable, log: ctx.log });
|
|
2918
2994
|
if (r.storeMissing) return;
|
|
2919
2995
|
if (enable && r.enabled) {
|
|
2920
|
-
ctx.log(
|
|
2921
|
-
ctx.log(
|
|
2996
|
+
ctx.log(import_chalk19.default.green(` \u2713 Enforcement ON \u2014 ${r.ok} route(s) + project switch on${r.fail ? `, ${r.fail} failed` : ""}.`));
|
|
2997
|
+
ctx.log(import_chalk19.default.dim(" Done here? Type /exit to leave the chat (your rule stays on).\n"));
|
|
2922
2998
|
} else if (!enable) {
|
|
2923
|
-
ctx.log(
|
|
2999
|
+
ctx.log(import_chalk19.default.green(` \u2713 Published (shadow): model + ${r.ok} route(s)${r.fail ? `, ${r.fail} failed` : ""}. Review, then /enable.
|
|
2924
3000
|
`));
|
|
2925
3001
|
}
|
|
2926
3002
|
}
|
|
@@ -2947,7 +3023,7 @@ async function runAuthz(projectArg, apiVersionArg) {
|
|
|
2947
3023
|
}
|
|
2948
3024
|
|
|
2949
3025
|
// src/commands/rule.ts
|
|
2950
|
-
var
|
|
3026
|
+
var import_chalk20 = __toESM(require("chalk"));
|
|
2951
3027
|
var import_ora6 = __toESM(require("ora"));
|
|
2952
3028
|
init_auth();
|
|
2953
3029
|
init_api();
|
|
@@ -2984,27 +3060,27 @@ async function runRule(ruleText, projectArg, opts) {
|
|
|
2984
3060
|
const proposal = data?.proposal;
|
|
2985
3061
|
if (!proposal || !Array.isArray(proposal.routes) || proposal.routes.length === 0) {
|
|
2986
3062
|
spinner.fail("The agent couldn\u2019t turn that into a rule in one shot.");
|
|
2987
|
-
if (data?.reply) console.log(
|
|
2988
|
-
console.log(
|
|
3063
|
+
if (data?.reply) console.log(import_chalk20.default.dim("\n " + String(data.reply).slice(0, 500) + "\n"));
|
|
3064
|
+
console.log(import_chalk20.default.dim(" Try an interactive session for anything nuanced: ") + import_chalk20.default.cyan(`apiblaze agent authz ${projectArg}`));
|
|
2989
3065
|
return;
|
|
2990
3066
|
}
|
|
2991
3067
|
spinner.succeed(`Rule designed \u2014 ${proposal.routes.length} route(s) affected.`);
|
|
2992
|
-
if (data?.reply) console.log(
|
|
3068
|
+
if (data?.reply) console.log(import_chalk20.default.dim(" " + String(data.reply).slice(0, 240)));
|
|
2993
3069
|
const pub = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: false });
|
|
2994
3070
|
if (pub.storeMissing) return;
|
|
2995
|
-
console.log(
|
|
3071
|
+
console.log(import_chalk20.default.green(` \u2713 Published in shadow mode \u2014 model + ${pub.ok} route(s)${pub.fail ? `, ${pub.fail} failed` : ""}.`));
|
|
2996
3072
|
if (opts.enforce) {
|
|
2997
3073
|
const enf = await applyProposal({ projectId, apiVersion, tenant: tenant2, proposal, enable: true });
|
|
2998
3074
|
if (enf.enabled) {
|
|
2999
|
-
console.log(
|
|
3075
|
+
console.log(import_chalk20.default.green(` \u2713 Enforcement ON \u2014 ${enf.ok} route(s) + project switch on${enf.fail ? `, ${enf.fail} failed` : ""}.`));
|
|
3000
3076
|
}
|
|
3001
3077
|
} else {
|
|
3002
|
-
console.log(
|
|
3078
|
+
console.log(import_chalk20.default.dim(` Review it (shadow logs), then enforce: `) + import_chalk20.default.cyan(`apiblaze rule "${rule}" ${projectArg} --enforce`));
|
|
3003
3079
|
}
|
|
3004
3080
|
}
|
|
3005
3081
|
|
|
3006
3082
|
// src/commands/openapi.ts
|
|
3007
|
-
var
|
|
3083
|
+
var import_chalk21 = __toESM(require("chalk"));
|
|
3008
3084
|
init_auth();
|
|
3009
3085
|
init_api();
|
|
3010
3086
|
async function runOpenapi(projectArg, apiVersionArg) {
|
|
@@ -3015,10 +3091,10 @@ async function runOpenapi(projectArg, apiVersionArg) {
|
|
|
3015
3091
|
if (!match) throw new Error(`Project "${projectArg}" not found in your active team. Run \`apiblaze projects\`.`);
|
|
3016
3092
|
const projectId = match.projectId;
|
|
3017
3093
|
const apiVersion = apiVersionArg || match.apiVersion;
|
|
3018
|
-
console.log(
|
|
3094
|
+
console.log(import_chalk21.default.dim("Gathering captured traffic samples\u2026"));
|
|
3019
3095
|
const routesRes = await agentCall(`/projects/${projectId}/${apiVersion}/samples/routes`, "GET");
|
|
3020
3096
|
if (routesRes.status >= 400) {
|
|
3021
|
-
console.log(
|
|
3097
|
+
console.log(import_chalk21.default.red(`Could not list traffic (${routesRes.status}): ${routesRes.data?.error ?? ""}`));
|
|
3022
3098
|
return;
|
|
3023
3099
|
}
|
|
3024
3100
|
const routes = routesRes.data?.routes ?? (Array.isArray(routesRes.data) ? routesRes.data : []);
|
|
@@ -3031,25 +3107,25 @@ async function runOpenapi(projectArg, apiVersionArg) {
|
|
|
3031
3107
|
}
|
|
3032
3108
|
const sampleIds = [...ids];
|
|
3033
3109
|
if (sampleIds.length === 0) {
|
|
3034
|
-
console.log(
|
|
3110
|
+
console.log(import_chalk21.default.yellow("No captured traffic samples found. Hit the dev environment of this proxy to capture some traces, then retry."));
|
|
3035
3111
|
return;
|
|
3036
3112
|
}
|
|
3037
3113
|
async function publish(ctx) {
|
|
3038
3114
|
const patch = ctx.proposal.patch;
|
|
3039
3115
|
if (!Array.isArray(patch) || patch.length === 0) {
|
|
3040
|
-
ctx.log(
|
|
3116
|
+
ctx.log(import_chalk21.default.green(" Nothing to publish \u2014 the spec already covers the observed traffic.\n"));
|
|
3041
3117
|
return;
|
|
3042
3118
|
}
|
|
3043
3119
|
const specSource = ctx.lastData?.spec_source ?? "unknown";
|
|
3044
3120
|
const endpoint = specSource === "github" ? "open-pr" : "publish-openapi";
|
|
3045
3121
|
const pub = await agentCall(`/projects/${projectId}/${apiVersion}/samples/${endpoint}`, "POST", { patch, sample_ids_used: sampleIds });
|
|
3046
3122
|
if (pub.status >= 400) {
|
|
3047
|
-
ctx.log(
|
|
3123
|
+
ctx.log(import_chalk21.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
|
|
3048
3124
|
`));
|
|
3049
3125
|
return;
|
|
3050
3126
|
}
|
|
3051
3127
|
const prUrl = pub.data?.pr_url;
|
|
3052
|
-
ctx.log(
|
|
3128
|
+
ctx.log(import_chalk21.default.green(prUrl ? ` \u2713 Pull request opened: ${prUrl}
|
|
3053
3129
|
` : " \u2713 Published updated OpenAPI spec.\n"));
|
|
3054
3130
|
}
|
|
3055
3131
|
await runAgentChatRepl({
|
|
@@ -3070,7 +3146,7 @@ async function runOpenapi(projectArg, apiVersionArg) {
|
|
|
3070
3146
|
}
|
|
3071
3147
|
|
|
3072
3148
|
// src/commands/mcp.ts
|
|
3073
|
-
var
|
|
3149
|
+
var import_chalk22 = __toESM(require("chalk"));
|
|
3074
3150
|
init_auth();
|
|
3075
3151
|
init_api();
|
|
3076
3152
|
async function runMcp(projectArg, apiVersionArg, opts) {
|
|
@@ -3087,11 +3163,11 @@ async function runMcp(projectArg, apiVersionArg, opts) {
|
|
|
3087
3163
|
const spec2 = ctx.proposal;
|
|
3088
3164
|
const pub = await agentCall(`/projects/${projectId}/${apiVersion}/mcp/spec`, "PUT", { environment, spec: spec2 });
|
|
3089
3165
|
if (pub.status >= 400) {
|
|
3090
|
-
ctx.log(
|
|
3166
|
+
ctx.log(import_chalk22.default.red(` Publish failed (${pub.status}): ${pub.data?.error ?? ""}
|
|
3091
3167
|
`));
|
|
3092
3168
|
return;
|
|
3093
3169
|
}
|
|
3094
|
-
ctx.log(
|
|
3170
|
+
ctx.log(import_chalk22.default.green(` \u2713 Published MCP server \u2014 ${mcpHost}.mcp.apiblaze.com/${apiVersion}/${environment}.
|
|
3095
3171
|
`));
|
|
3096
3172
|
}
|
|
3097
3173
|
await runAgentChatRepl({
|
|
@@ -3113,7 +3189,7 @@ async function runMcp(projectArg, apiVersionArg, opts) {
|
|
|
3113
3189
|
}
|
|
3114
3190
|
|
|
3115
3191
|
// src/commands/delete.ts
|
|
3116
|
-
var
|
|
3192
|
+
var import_chalk23 = __toESM(require("chalk"));
|
|
3117
3193
|
var import_ora7 = __toESM(require("ora"));
|
|
3118
3194
|
init_admin();
|
|
3119
3195
|
init_resolve();
|
|
@@ -3139,10 +3215,10 @@ async function runDelete(project, version2, opts) {
|
|
|
3139
3215
|
return;
|
|
3140
3216
|
}
|
|
3141
3217
|
} else {
|
|
3142
|
-
console.log(`${
|
|
3218
|
+
console.log(`${import_chalk23.default.red.bold("Delete")} ${import_chalk23.default.bold(proj2.projectName)} ${import_chalk23.default.dim("v" + proj2.apiVersion)} ${import_chalk23.default.dim("(" + proj2.projectId + ")")}`);
|
|
3143
3219
|
if (impact && typeof impact === "object") {
|
|
3144
3220
|
const counts = impact.counts ?? impact.impact ?? impact;
|
|
3145
|
-
console.log(
|
|
3221
|
+
console.log(import_chalk23.default.dim(" This removes (cascade): ") + import_chalk23.default.yellow(JSON.stringify(counts)));
|
|
3146
3222
|
}
|
|
3147
3223
|
if (!opts.yes) {
|
|
3148
3224
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -3150,7 +3226,7 @@ async function runDelete(project, version2, opts) {
|
|
|
3150
3226
|
{ type: "confirm", name: "confirm", message: `Permanently delete ${proj2.projectName} v${proj2.apiVersion}? This cannot be undone.`, default: false }
|
|
3151
3227
|
]);
|
|
3152
3228
|
if (!confirm) {
|
|
3153
|
-
console.log(
|
|
3229
|
+
console.log(import_chalk23.default.dim("Aborted."));
|
|
3154
3230
|
return;
|
|
3155
3231
|
}
|
|
3156
3232
|
}
|
|
@@ -3171,7 +3247,7 @@ async function runDelete(project, version2, opts) {
|
|
|
3171
3247
|
}
|
|
3172
3248
|
|
|
3173
3249
|
// src/commands/export.ts
|
|
3174
|
-
var
|
|
3250
|
+
var import_chalk24 = __toESM(require("chalk"));
|
|
3175
3251
|
var import_fs3 = require("fs");
|
|
3176
3252
|
init_admin();
|
|
3177
3253
|
init_auth();
|
|
@@ -3190,7 +3266,7 @@ async function runExport(projectArg, versionArg, opts) {
|
|
|
3190
3266
|
if (opts.noConsumers) q.set("include_consumers", "0");
|
|
3191
3267
|
if (opts.keys) q.set("keys", opts.keys);
|
|
3192
3268
|
const qs = q.toString() ? `?${q.toString()}` : "";
|
|
3193
|
-
console.log(
|
|
3269
|
+
console.log(import_chalk24.default.dim(`Queuing ${target} export of ${projectId}@${version2}\u2026`));
|
|
3194
3270
|
const job = await admin({
|
|
3195
3271
|
path: `/projects/${projectId}/${version2}/export/${target}${qs}`,
|
|
3196
3272
|
method: "GET",
|
|
@@ -3200,11 +3276,11 @@ async function runExport(projectArg, versionArg, opts) {
|
|
|
3200
3276
|
const statusPath = `/projects/${projectId}/${version2}/export/jobs/${job.job_id}`;
|
|
3201
3277
|
let status = "queued";
|
|
3202
3278
|
const started = Date.now();
|
|
3203
|
-
process.stdout.write(
|
|
3279
|
+
process.stdout.write(import_chalk24.default.dim("Building bundle"));
|
|
3204
3280
|
while (status !== "ready" && status !== "failed") {
|
|
3205
3281
|
if (Date.now() - started > 10 * 6e4) throw new Error("Export timed out after 10 minutes.");
|
|
3206
3282
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
3207
|
-
process.stdout.write(
|
|
3283
|
+
process.stdout.write(import_chalk24.default.dim("."));
|
|
3208
3284
|
const st = await admin({ path: statusPath, method: "GET", summary: "poll export" });
|
|
3209
3285
|
status = st?.status ?? "queued";
|
|
3210
3286
|
if (status === "failed") {
|
|
@@ -3222,14 +3298,14 @@ async function runExport(projectArg, versionArg, opts) {
|
|
|
3222
3298
|
if (!res.ok) throw new Error(`Download failed (${res.status}): ${await res.text().catch(() => "")}`);
|
|
3223
3299
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
3224
3300
|
(0, import_fs3.writeFileSync)(outFile, buf);
|
|
3225
|
-
console.log(
|
|
3226
|
-
if (job.decryption_key) console.log(
|
|
3227
|
-
console.log(
|
|
3228
|
-
if (target === "kong") console.log(
|
|
3301
|
+
console.log(import_chalk24.default.green(`\u2713 Saved ${outFile} (${(buf.length / 1024).toFixed(0)} KB)`));
|
|
3302
|
+
if (job.decryption_key) console.log(import_chalk24.default.yellow(`Decryption key (shown once): ${job.decryption_key}`));
|
|
3303
|
+
console.log(import_chalk24.default.dim("Read MIGRATION-REPORT.json inside the zip for the full fidelity ledger."));
|
|
3304
|
+
if (target === "kong") console.log(import_chalk24.default.dim("Kong: unzip, then `cd kong && docker compose up` (see kong/README.md)."));
|
|
3229
3305
|
}
|
|
3230
3306
|
|
|
3231
3307
|
// src/commands/config.ts
|
|
3232
|
-
var
|
|
3308
|
+
var import_chalk25 = __toESM(require("chalk"));
|
|
3233
3309
|
var import_ora8 = __toESM(require("ora"));
|
|
3234
3310
|
init_admin();
|
|
3235
3311
|
init_resolve();
|
|
@@ -3253,7 +3329,7 @@ async function patchConfig(project, opts, body, summary) {
|
|
|
3253
3329
|
}
|
|
3254
3330
|
async function runTargetSet(project, opts) {
|
|
3255
3331
|
if (!opts.url) {
|
|
3256
|
-
console.error(
|
|
3332
|
+
console.error(import_chalk25.default.red("--url is required."));
|
|
3257
3333
|
process.exit(1);
|
|
3258
3334
|
}
|
|
3259
3335
|
const body = opts.env ? { environments: { [opts.env]: { target: opts.url } } } : { target_url: opts.url };
|
|
@@ -3266,40 +3342,40 @@ async function runThrottleSet(project, opts) {
|
|
|
3266
3342
|
if (opts.quota !== void 0) throttling.proxyQuota = Number(opts.quota);
|
|
3267
3343
|
if (opts.period !== void 0) {
|
|
3268
3344
|
if (!["daily", "weekly", "monthly"].includes(opts.period)) {
|
|
3269
|
-
console.error(
|
|
3345
|
+
console.error(import_chalk25.default.red("--period must be daily, weekly, or monthly."));
|
|
3270
3346
|
process.exit(1);
|
|
3271
3347
|
}
|
|
3272
3348
|
throttling.quotaPeriod = opts.period;
|
|
3273
3349
|
}
|
|
3274
3350
|
if (Object.keys(throttling).length === 0) {
|
|
3275
|
-
console.error(
|
|
3351
|
+
console.error(import_chalk25.default.red("Nothing to set. Pass at least one of --rate, --end-user-rate, --quota, --period."));
|
|
3276
3352
|
process.exit(1);
|
|
3277
3353
|
}
|
|
3278
3354
|
await patchConfig(project, opts, { throttling }, `Update throttling ${JSON.stringify(throttling)}`);
|
|
3279
3355
|
}
|
|
3280
3356
|
async function runRename(project, opts) {
|
|
3281
3357
|
if (!opts.displayName) {
|
|
3282
|
-
console.error(
|
|
3358
|
+
console.error(import_chalk25.default.red("--display-name is required."));
|
|
3283
3359
|
process.exit(1);
|
|
3284
3360
|
}
|
|
3285
3361
|
await patchConfig(project, opts, { display_name: opts.displayName }, `Rename \u2192 "${opts.displayName}"`);
|
|
3286
3362
|
}
|
|
3287
3363
|
|
|
3288
3364
|
// src/commands/config-browse.ts
|
|
3289
|
-
var
|
|
3365
|
+
var import_chalk34 = __toESM(require("chalk"));
|
|
3290
3366
|
var import_ora16 = __toESM(require("ora"));
|
|
3291
3367
|
init_admin();
|
|
3292
3368
|
init_auth();
|
|
3293
3369
|
init_resolve();
|
|
3294
3370
|
|
|
3295
3371
|
// src/commands/domain.ts
|
|
3296
|
-
var
|
|
3372
|
+
var import_chalk26 = __toESM(require("chalk"));
|
|
3297
3373
|
var import_ora9 = __toESM(require("ora"));
|
|
3298
3374
|
init_admin();
|
|
3299
3375
|
init_resolve();
|
|
3300
3376
|
async function runDomainAdd(project, opts) {
|
|
3301
3377
|
if (!opts.domain) {
|
|
3302
|
-
console.error(
|
|
3378
|
+
console.error(import_chalk26.default.red("--domain is required."));
|
|
3303
3379
|
process.exit(1);
|
|
3304
3380
|
}
|
|
3305
3381
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -3318,9 +3394,9 @@ async function runDomainAdd(project, opts) {
|
|
|
3318
3394
|
console.log(JSON.stringify(out));
|
|
3319
3395
|
return;
|
|
3320
3396
|
}
|
|
3321
|
-
if (out?.cnameRecord) console.log(` ${
|
|
3322
|
-
if (out?.dcv) console.log(` ${
|
|
3323
|
-
if (out?.id) console.log(
|
|
3397
|
+
if (out?.cnameRecord) console.log(` ${import_chalk26.default.cyan("CNAME")} ${out.cnameRecord.name ?? opts.domain} \u2192 ${out.cnameRecord.value ?? out.cnameRecord.target}`);
|
|
3398
|
+
if (out?.dcv) console.log(` ${import_chalk26.default.cyan("TXT")} ${out.dcv.name} = ${out.dcv.value}`);
|
|
3399
|
+
if (out?.id) console.log(import_chalk26.default.dim(` domain id: ${out.id}`));
|
|
3324
3400
|
} catch (err) {
|
|
3325
3401
|
spinner.fail("Domain registration failed.");
|
|
3326
3402
|
throw err;
|
|
@@ -3340,14 +3416,14 @@ async function runDomainList(project, opts) {
|
|
|
3340
3416
|
return;
|
|
3341
3417
|
}
|
|
3342
3418
|
if (!domains.length) {
|
|
3343
|
-
console.log(
|
|
3419
|
+
console.log(import_chalk26.default.yellow("No custom domains."));
|
|
3344
3420
|
return;
|
|
3345
3421
|
}
|
|
3346
|
-
for (const d of domains) console.log(` ${
|
|
3422
|
+
for (const d of domains) console.log(` ${import_chalk26.default.bold(d.hostname)} ${import_chalk26.default.dim(d.status ?? "")} ${import_chalk26.default.dim(d.id ?? "")}`);
|
|
3347
3423
|
}
|
|
3348
3424
|
async function runDomainStatus(project, opts) {
|
|
3349
3425
|
if (!opts.id) {
|
|
3350
|
-
console.error(
|
|
3426
|
+
console.error(import_chalk26.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
|
|
3351
3427
|
process.exit(1);
|
|
3352
3428
|
}
|
|
3353
3429
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -3357,11 +3433,11 @@ async function runDomainStatus(project, opts) {
|
|
|
3357
3433
|
path: `/projects/${proj2.projectId}/domains/${encodeURIComponent(opts.id)}/status`,
|
|
3358
3434
|
summary: `Check custom-domain status`
|
|
3359
3435
|
});
|
|
3360
|
-
console.log(opts.json ? JSON.stringify(out) : ` ${
|
|
3436
|
+
console.log(opts.json ? JSON.stringify(out) : ` ${import_chalk26.default.bold(out?.hostname ?? opts.id)}: ${import_chalk26.default.cyan(out?.status ?? "unknown")}`);
|
|
3361
3437
|
}
|
|
3362
3438
|
async function runDomainRemove(project, opts) {
|
|
3363
3439
|
if (!opts.id) {
|
|
3364
|
-
console.error(
|
|
3440
|
+
console.error(import_chalk26.default.red("--id <domainId> is required (see `apiblaze domain list`)."));
|
|
3365
3441
|
process.exit(1);
|
|
3366
3442
|
}
|
|
3367
3443
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -3399,7 +3475,7 @@ async function runDomainSetBase(project, opts) {
|
|
|
3399
3475
|
}
|
|
3400
3476
|
|
|
3401
3477
|
// src/commands/tenant.ts
|
|
3402
|
-
var
|
|
3478
|
+
var import_chalk29 = __toESM(require("chalk"));
|
|
3403
3479
|
var import_ora12 = __toESM(require("ora"));
|
|
3404
3480
|
init_admin();
|
|
3405
3481
|
init_resolve();
|
|
@@ -3408,20 +3484,20 @@ init_tenant_pick();
|
|
|
3408
3484
|
async function runTenantUse(query, opts) {
|
|
3409
3485
|
const creds = loadCredentials();
|
|
3410
3486
|
if (!creds) {
|
|
3411
|
-
console.error(
|
|
3487
|
+
console.error(import_chalk29.default.red("Not logged in. Run `apiblaze login` first."));
|
|
3412
3488
|
process.exit(1);
|
|
3413
3489
|
}
|
|
3414
3490
|
if (opts.clear) {
|
|
3415
3491
|
delete creds.activeTenant;
|
|
3416
3492
|
saveCredentials(creds);
|
|
3417
|
-
console.log(
|
|
3493
|
+
console.log(import_chalk29.default.green("Tenant scope cleared."));
|
|
3418
3494
|
return;
|
|
3419
3495
|
}
|
|
3420
3496
|
const { teamId } = await resolveTeam(opts.team);
|
|
3421
3497
|
const slug = await pickTenant(teamId, { message: "Scope future commands to which tenant?", initialQuery: query });
|
|
3422
3498
|
if (!slug) process.exit(1);
|
|
3423
3499
|
saveCredentials({ ...creds, activeTenant: slug });
|
|
3424
|
-
console.log(
|
|
3500
|
+
console.log(import_chalk29.default.green(`Tenant scope set to ${import_chalk29.default.bold(slug)}.`) + import_chalk29.default.dim(" (clear with `apiblaze tenant use --clear`)"));
|
|
3425
3501
|
}
|
|
3426
3502
|
async function runTenantList(opts) {
|
|
3427
3503
|
const { teamId, teamName } = await resolveTeam(opts.team);
|
|
@@ -3438,22 +3514,22 @@ async function runTenantList(opts) {
|
|
|
3438
3514
|
return;
|
|
3439
3515
|
}
|
|
3440
3516
|
if (!tenants.length) {
|
|
3441
|
-
console.log(
|
|
3517
|
+
console.log(import_chalk29.default.yellow(opts.q ? `No tenants matching "${opts.q}".` : "No tenants."));
|
|
3442
3518
|
return;
|
|
3443
3519
|
}
|
|
3444
3520
|
for (const t of tenants) {
|
|
3445
3521
|
const name = typeof t === "string" ? t : t.tenant_name;
|
|
3446
|
-
const display = typeof t === "string" ? "" :
|
|
3447
|
-
console.log(` ${
|
|
3522
|
+
const display = typeof t === "string" ? "" : import_chalk29.default.dim(` ${t.display_name ?? ""}`);
|
|
3523
|
+
console.log(` ${import_chalk29.default.bold(name)}${display}`);
|
|
3448
3524
|
}
|
|
3449
3525
|
const total = out?.total ?? tenants.length;
|
|
3450
3526
|
if (total > tenants.length) {
|
|
3451
|
-
console.log(
|
|
3527
|
+
console.log(import_chalk29.default.dim(` \u2026 showing ${tenants.length} of ${total} \u2014 narrow with --q <search>`));
|
|
3452
3528
|
}
|
|
3453
3529
|
}
|
|
3454
3530
|
async function runTenantCreate(opts) {
|
|
3455
3531
|
if (!opts.name) {
|
|
3456
|
-
console.error(
|
|
3532
|
+
console.error(import_chalk29.default.red("--name (display name) is required."));
|
|
3457
3533
|
process.exit(1);
|
|
3458
3534
|
}
|
|
3459
3535
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -3465,7 +3541,7 @@ async function runTenantCreate(opts) {
|
|
|
3465
3541
|
body: { display_name: opts.name, ...opts.slug ? { tenant_name: opts.slug } : {} },
|
|
3466
3542
|
summary: `Create tenant "${opts.name}"`
|
|
3467
3543
|
});
|
|
3468
|
-
spinner.succeed(`Created tenant ${
|
|
3544
|
+
spinner.succeed(`Created tenant ${import_chalk29.default.bold(out?.tenant_name ?? opts.name)}.`);
|
|
3469
3545
|
if (opts.json) console.log(JSON.stringify(out));
|
|
3470
3546
|
} catch (err) {
|
|
3471
3547
|
spinner.fail("Tenant create failed.");
|
|
@@ -3474,7 +3550,7 @@ async function runTenantCreate(opts) {
|
|
|
3474
3550
|
}
|
|
3475
3551
|
async function runTenantAttach(project, opts) {
|
|
3476
3552
|
if (!opts.tenant) {
|
|
3477
|
-
console.error(
|
|
3553
|
+
console.error(import_chalk29.default.red("--tenant <slug> is required."));
|
|
3478
3554
|
process.exit(1);
|
|
3479
3555
|
}
|
|
3480
3556
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -3502,7 +3578,7 @@ async function runTenantDelete(slug, opts) {
|
|
|
3502
3578
|
{ type: "confirm", name: "confirm", message: `Permanently delete tenant "${slug}" and everything under it? This cannot be undone.`, default: false }
|
|
3503
3579
|
]);
|
|
3504
3580
|
if (!confirm) {
|
|
3505
|
-
console.log(
|
|
3581
|
+
console.log(import_chalk29.default.dim("Aborted."));
|
|
3506
3582
|
return;
|
|
3507
3583
|
}
|
|
3508
3584
|
}
|
|
@@ -3521,7 +3597,7 @@ async function runTenantDelete(slug, opts) {
|
|
|
3521
3597
|
}
|
|
3522
3598
|
async function runTenantCors(opts) {
|
|
3523
3599
|
if (!opts.tenant) {
|
|
3524
|
-
console.error(
|
|
3600
|
+
console.error(import_chalk29.default.red("--tenant <slug> is required."));
|
|
3525
3601
|
process.exit(1);
|
|
3526
3602
|
}
|
|
3527
3603
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -3543,7 +3619,7 @@ async function runTenantCors(opts) {
|
|
|
3543
3619
|
}
|
|
3544
3620
|
|
|
3545
3621
|
// src/commands/tenant-drill.ts
|
|
3546
|
-
var
|
|
3622
|
+
var import_chalk30 = __toESM(require("chalk"));
|
|
3547
3623
|
var import_ora13 = __toESM(require("ora"));
|
|
3548
3624
|
var import_crypto = require("crypto");
|
|
3549
3625
|
init_admin();
|
|
@@ -3574,15 +3650,15 @@ async function validScopedTenant(teamId, query) {
|
|
|
3574
3650
|
const next = { ...creds };
|
|
3575
3651
|
delete next.activeTenant;
|
|
3576
3652
|
saveCredentials2(next);
|
|
3577
|
-
console.log(
|
|
3653
|
+
console.log(import_chalk30.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
|
|
3578
3654
|
return void 0;
|
|
3579
3655
|
}
|
|
3580
3656
|
async function tenantHome(teamId, tenant2) {
|
|
3581
3657
|
const { default: inquirer3 } = await import("inquirer");
|
|
3582
3658
|
const base2 = `/teams/${encodeURIComponent(teamId)}/tenants/${encodeURIComponent(tenant2)}`;
|
|
3583
|
-
console.log(
|
|
3659
|
+
console.log(import_chalk30.default.bold(`
|
|
3584
3660
|
Tenant ${tenant2}`));
|
|
3585
|
-
console.log(
|
|
3661
|
+
console.log(import_chalk30.default.dim("Tenant auth/settings are SHARED: changes apply to every proxy this tenant serves.\n"));
|
|
3586
3662
|
for (; ; ) {
|
|
3587
3663
|
const spinner = (0, import_ora13.default)("Reading tenant state...").start();
|
|
3588
3664
|
const [iam, cors, emails, issuers, opaque, clients] = await Promise.all([
|
|
@@ -3598,18 +3674,18 @@ Tenant ${tenant2}`));
|
|
|
3598
3674
|
const nClients = Array.isArray(clients) ? clients.length : 0;
|
|
3599
3675
|
const nOpaque = opaque?.opaque?.endpoint ? 1 : 0;
|
|
3600
3676
|
const nLogin = nClients + nIssuers + nOpaque;
|
|
3601
|
-
const onOff = (b) => b ?
|
|
3677
|
+
const onOff = (b) => b ? import_chalk30.default.green("on") : import_chalk30.default.dim("off");
|
|
3602
3678
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
3603
3679
|
type: "list",
|
|
3604
3680
|
name: "pick",
|
|
3605
3681
|
message: `Tenant ${tenant2}:`,
|
|
3606
3682
|
pageSize: 12,
|
|
3607
3683
|
choices: [
|
|
3608
|
-
{ name: `Login methods (${nLogin}) ${
|
|
3609
|
-
{ name: `Users & groups: ${onOff(iam?.iam_enabled)} ${
|
|
3610
|
-
{ name: `Portal admins (${nEmails}) ${
|
|
3611
|
-
new inquirer3.Separator(
|
|
3612
|
-
{ name: `CORS: ${cors?.cors ?
|
|
3684
|
+
{ name: `Login methods (${nLogin}) ${import_chalk30.default.dim("how your consumers sign in")}`, value: "login" },
|
|
3685
|
+
{ name: `Users & groups: ${onOff(iam?.iam_enabled)} ${import_chalk30.default.dim(`identity & key management (iam.apiblaze.com)`)}`, value: "iam" },
|
|
3686
|
+
{ name: `Portal admins (${nEmails}) ${import_chalk30.default.dim("emails allowed to administer this tenant's portal")}`, value: "emails" },
|
|
3687
|
+
new inquirer3.Separator(import_chalk30.default.dim(" Settings")),
|
|
3688
|
+
{ name: `CORS: ${cors?.cors ? import_chalk30.default.cyan(JSON.stringify(cors.cors)) : import_chalk30.default.dim("(unset)")} ${import_chalk30.default.dim("browser origins allowed to call this tenant")}`, value: "cors" },
|
|
3613
3689
|
{ name: "\u2190 Back", value: "back" }
|
|
3614
3690
|
]
|
|
3615
3691
|
}]);
|
|
@@ -3622,7 +3698,7 @@ Tenant ${tenant2}`));
|
|
|
3622
3698
|
case "iam": {
|
|
3623
3699
|
const { v } = await inquirer3.prompt([{ type: "confirm", name: "v", message: "Enable Users & groups?", default: !!iam?.iam_enabled }]);
|
|
3624
3700
|
await admin({ method: "PATCH", path: `${base2}/iam`, body: { enabled: v }, summary: `IAM enforcement \u2192 ${v ? "on" : "off"}` });
|
|
3625
|
-
console.log(
|
|
3701
|
+
console.log(import_chalk30.default.green(` Users & groups ${v ? "enabled" : "disabled"}.`));
|
|
3626
3702
|
break;
|
|
3627
3703
|
}
|
|
3628
3704
|
case "cors": {
|
|
@@ -3635,11 +3711,11 @@ Tenant ${tenant2}`));
|
|
|
3635
3711
|
if (v === "") break;
|
|
3636
3712
|
const parsed = v === "null" ? null : safeJson(v);
|
|
3637
3713
|
if (parsed === void 0) {
|
|
3638
|
-
console.log(
|
|
3714
|
+
console.log(import_chalk30.default.yellow(" Not valid JSON \u2014 unchanged."));
|
|
3639
3715
|
break;
|
|
3640
3716
|
}
|
|
3641
3717
|
await admin({ method: "PUT", path: `${base2}/cors`, body: { cors: parsed }, summary: "Set tenant CORS" });
|
|
3642
|
-
console.log(
|
|
3718
|
+
console.log(import_chalk30.default.green(" CORS updated."));
|
|
3643
3719
|
break;
|
|
3644
3720
|
}
|
|
3645
3721
|
case "emails":
|
|
@@ -3663,15 +3739,15 @@ async function loginMethodsMenu(teamId, tenant2, base2) {
|
|
|
3663
3739
|
const choices = [];
|
|
3664
3740
|
for (const c of appClients) {
|
|
3665
3741
|
const nP = (c.providers ?? []).length || c.providers_count || 0;
|
|
3666
|
-
choices.push({ name: `${
|
|
3742
|
+
choices.push({ name: `${import_chalk30.default.cyan("APIblaze-hosted")} ${import_chalk30.default.bold(c.name ?? c.clientId)} ${import_chalk30.default.dim(`${c.clientId}${nP ? ` \xB7 ${nP} provider${nP === 1 ? "" : "s"}` : import_chalk30.default.yellow(" \xB7 needs a provider")}`)}`, value: { kind: "client", item: c } });
|
|
3667
3743
|
}
|
|
3668
3744
|
for (const i of issuers) {
|
|
3669
|
-
choices.push({ name: `${
|
|
3745
|
+
choices.push({ name: `${import_chalk30.default.cyan("Your own \u2014 JWT ")} ${import_chalk30.default.bold(i.iss)} ${import_chalk30.default.dim(`aud=${i.aud}`)}`, value: { kind: "issuer", item: i } });
|
|
3670
3746
|
}
|
|
3671
3747
|
if (opaque?.endpoint) {
|
|
3672
|
-
choices.push({ name: `${
|
|
3748
|
+
choices.push({ name: `${import_chalk30.default.cyan("Your own \u2014 opaque")} ${import_chalk30.default.bold(opaque.endpoint)}`, value: { kind: "opaque", item: opaque } });
|
|
3673
3749
|
}
|
|
3674
|
-
if (!choices.length) console.log(
|
|
3750
|
+
if (!choices.length) console.log(import_chalk30.default.dim("\n No login methods yet \u2014 consumers cannot sign in until you add one."));
|
|
3675
3751
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
3676
3752
|
type: "list",
|
|
3677
3753
|
name: "pick",
|
|
@@ -3711,9 +3787,9 @@ async function addLoginMethod(teamId, tenant2, base2) {
|
|
|
3711
3787
|
message: "How do people log in?",
|
|
3712
3788
|
pageSize: 8,
|
|
3713
3789
|
choices: [
|
|
3714
|
-
{ name: `APIblaze hosted login page ${
|
|
3715
|
-
{ name: `Your own hosted login \u2014 JWT ${
|
|
3716
|
-
{ name: `Your own login \u2014 opaque token ${
|
|
3790
|
+
{ name: `APIblaze hosted login page ${import_chalk30.default.dim("we host login; pick a provider (GitHub/Google/\u2026) \u2014 easiest")}`, value: "apiblaze" },
|
|
3791
|
+
{ name: `Your own hosted login \u2014 JWT ${import_chalk30.default.dim("your identity provider issues JWTs; we trust them")}`, value: "jwt" },
|
|
3792
|
+
{ name: `Your own login \u2014 opaque token ${import_chalk30.default.dim("we validate your opaque tokens via an introspection endpoint")}`, value: "opaque" },
|
|
3717
3793
|
{ name: "\u2190 Back", value: null }
|
|
3718
3794
|
]
|
|
3719
3795
|
}]);
|
|
@@ -3737,8 +3813,8 @@ function safeJson(s) {
|
|
|
3737
3813
|
async function emailsMenu(base2, emails) {
|
|
3738
3814
|
const { default: inquirer3 } = await import("inquirer");
|
|
3739
3815
|
console.log();
|
|
3740
|
-
if (!emails.length) console.log(
|
|
3741
|
-
for (const e of emails) console.log(` ${
|
|
3816
|
+
if (!emails.length) console.log(import_chalk30.default.dim(" No consumer-admin emails."));
|
|
3817
|
+
for (const e of emails) console.log(` ${import_chalk30.default.bold(e.email ?? e)} ${import_chalk30.default.dim(e.status ?? "")}`);
|
|
3742
3818
|
const { act } = await inquirer3.prompt([{
|
|
3743
3819
|
type: "list",
|
|
3744
3820
|
name: "act",
|
|
@@ -3753,7 +3829,7 @@ async function emailsMenu(base2, emails) {
|
|
|
3753
3829
|
if (act === "add") {
|
|
3754
3830
|
const { email } = await inquirer3.prompt([{ type: "input", name: "email", message: "Email:", validate: (s) => /.+@.+\..+/.test(s) || "not an email" }]);
|
|
3755
3831
|
await admin({ method: "POST", path: `${base2}/admin-emails`, body: { email }, summary: `Add consumer-admin ${email}` });
|
|
3756
|
-
console.log(
|
|
3832
|
+
console.log(import_chalk30.default.green(` ${email} added.`));
|
|
3757
3833
|
} else {
|
|
3758
3834
|
const { e } = await inquirer3.prompt([{
|
|
3759
3835
|
type: "list",
|
|
@@ -3763,7 +3839,7 @@ async function emailsMenu(base2, emails) {
|
|
|
3763
3839
|
}]);
|
|
3764
3840
|
if (!e) return;
|
|
3765
3841
|
await admin({ method: "DELETE", path: `${base2}/admin-emails/${encodeURIComponent(e)}`, summary: `Remove consumer-admin ${e}` });
|
|
3766
|
-
console.log(
|
|
3842
|
+
console.log(import_chalk30.default.green(` ${e} removed.`));
|
|
3767
3843
|
}
|
|
3768
3844
|
}
|
|
3769
3845
|
async function addIssuer(base2) {
|
|
@@ -3784,19 +3860,19 @@ async function addIssuer(base2) {
|
|
|
3784
3860
|
body: { iss: a.iss.trim(), aud: a.aud.trim(), jwks_url: a.jwks.trim() || null, sub_semantics: a.sem, ...claim ? { claim_name: claim } : {} },
|
|
3785
3861
|
summary: `Add external issuer ${a.iss.trim()}`
|
|
3786
3862
|
});
|
|
3787
|
-
console.log(
|
|
3863
|
+
console.log(import_chalk30.default.green(" JWT login method saved."));
|
|
3788
3864
|
}
|
|
3789
3865
|
async function issuerHome(base2, issuer) {
|
|
3790
3866
|
const { default: inquirer3 } = await import("inquirer");
|
|
3791
3867
|
console.log(`
|
|
3792
|
-
${
|
|
3868
|
+
${import_chalk30.default.bold(issuer.iss)} ${import_chalk30.default.dim(`aud=${issuer.aud} \xB7 ${issuer.sub_semantics ?? ""}`)}`);
|
|
3793
3869
|
const { act } = await inquirer3.prompt([{
|
|
3794
3870
|
type: "list",
|
|
3795
3871
|
name: "act",
|
|
3796
3872
|
message: "This JWT login method:",
|
|
3797
3873
|
choices: [
|
|
3798
3874
|
{ name: "Replace it (re-enter details)", value: "edit" },
|
|
3799
|
-
{ name:
|
|
3875
|
+
{ name: import_chalk30.default.red("Delete it"), value: "rm" },
|
|
3800
3876
|
{ name: "\u2190 Back", value: "back" }
|
|
3801
3877
|
]
|
|
3802
3878
|
}]);
|
|
@@ -3812,7 +3888,7 @@ async function issuerHome(base2, issuer) {
|
|
|
3812
3888
|
path: `${base2}/external-issuers?iss=${encodeURIComponent(issuer.iss)}&aud=${encodeURIComponent(issuer.aud)}`,
|
|
3813
3889
|
summary: `Delete issuer ${issuer.iss}`
|
|
3814
3890
|
});
|
|
3815
|
-
console.log(
|
|
3891
|
+
console.log(import_chalk30.default.green(" Deleted."));
|
|
3816
3892
|
}
|
|
3817
3893
|
async function setOpaque(base2, cur) {
|
|
3818
3894
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -3821,19 +3897,19 @@ async function setOpaque(base2, cur) {
|
|
|
3821
3897
|
{ type: "list", name: "method", message: "HTTP method:", choices: ["GET", "POST"], default: cur?.method ?? "GET" }
|
|
3822
3898
|
]);
|
|
3823
3899
|
await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: { endpoint: a.endpoint, method: a.method } }, summary: "Set opaque validator" });
|
|
3824
|
-
console.log(
|
|
3900
|
+
console.log(import_chalk30.default.green(" Opaque login method set."));
|
|
3825
3901
|
}
|
|
3826
3902
|
async function opaqueHome(base2, cur) {
|
|
3827
3903
|
const { default: inquirer3 } = await import("inquirer");
|
|
3828
3904
|
console.log(`
|
|
3829
|
-
${
|
|
3905
|
+
${import_chalk30.default.bold(cur.endpoint)} ${import_chalk30.default.dim(cur.method ?? "GET")}`);
|
|
3830
3906
|
const { act } = await inquirer3.prompt([{
|
|
3831
3907
|
type: "list",
|
|
3832
3908
|
name: "act",
|
|
3833
3909
|
message: "This opaque login method:",
|
|
3834
3910
|
choices: [
|
|
3835
3911
|
{ name: "Replace it", value: "edit" },
|
|
3836
|
-
{ name:
|
|
3912
|
+
{ name: import_chalk30.default.red("Delete it"), value: "rm" },
|
|
3837
3913
|
{ name: "\u2190 Back", value: "back" }
|
|
3838
3914
|
]
|
|
3839
3915
|
}]);
|
|
@@ -3843,7 +3919,7 @@ async function opaqueHome(base2, cur) {
|
|
|
3843
3919
|
return;
|
|
3844
3920
|
}
|
|
3845
3921
|
await admin({ method: "PUT", path: `${base2}/opaque`, body: { opaque: null }, summary: "Clear opaque validator" });
|
|
3846
|
-
console.log(
|
|
3922
|
+
console.log(import_chalk30.default.green(" Deleted."));
|
|
3847
3923
|
}
|
|
3848
3924
|
async function clientHome(base2, summary) {
|
|
3849
3925
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -3862,13 +3938,13 @@ async function clientHome(base2, summary) {
|
|
|
3862
3938
|
message: `${c.name ?? id}:`,
|
|
3863
3939
|
pageSize: 12,
|
|
3864
3940
|
choices: [
|
|
3865
|
-
{ name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${
|
|
3866
|
-
{ name: `Callback URLs: ${cb.length ?
|
|
3867
|
-
{ name: `Scopes: ${scopes.length ?
|
|
3941
|
+
{ name: `Login providers${nProviders ? ` (${nProviders})` : ""} ${import_chalk30.default.dim("google/github/microsoft/\u2026 \u2014 how consumers sign in")}`, value: "providers" },
|
|
3942
|
+
{ name: `Callback URLs: ${cb.length ? import_chalk30.default.cyan(cb.join(", ")) : import_chalk30.default.dim("(none)")}`, value: "callbacks" },
|
|
3943
|
+
{ name: `Scopes: ${scopes.length ? import_chalk30.default.cyan(scopes.join(" ")) : import_chalk30.default.dim("(defaults)")}`, value: "scopes" },
|
|
3868
3944
|
{ name: `Token expiries: access ${c.accessTokenExpiry ?? 3600}s \xB7 id ${c.idTokenExpiry ?? 3600}s \xB7 refresh ${c.refreshTokenExpiry ?? 2592e3}s`, value: "expiries" },
|
|
3869
3945
|
{ name: "Reveal client secret", value: "secret" },
|
|
3870
3946
|
{ name: "Rotate client secret", value: "rotate" },
|
|
3871
|
-
{ name:
|
|
3947
|
+
{ name: import_chalk30.default.red("Delete this app client"), value: "delete" },
|
|
3872
3948
|
{ name: "\u2190 Back", value: "back" }
|
|
3873
3949
|
]
|
|
3874
3950
|
}]);
|
|
@@ -3881,13 +3957,13 @@ async function clientHome(base2, summary) {
|
|
|
3881
3957
|
case "callbacks": {
|
|
3882
3958
|
const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Callback URLs (comma-separated):", default: cb.join(", ") }]);
|
|
3883
3959
|
await admin({ method: "PATCH", path: cBase, body: { authorizedCallbackUrls: parseList(v) }, summary: "Update callback URLs" });
|
|
3884
|
-
console.log(
|
|
3960
|
+
console.log(import_chalk30.default.green(" Callbacks updated."));
|
|
3885
3961
|
break;
|
|
3886
3962
|
}
|
|
3887
3963
|
case "scopes": {
|
|
3888
3964
|
const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: "Scopes (space/comma-separated):", default: scopes.join(" ") }]);
|
|
3889
3965
|
await admin({ method: "PATCH", path: cBase, body: { scopes: v.split(/[\s,]+/).filter(Boolean) }, summary: "Update scopes" });
|
|
3890
|
-
console.log(
|
|
3966
|
+
console.log(import_chalk30.default.green(" Scopes updated."));
|
|
3891
3967
|
break;
|
|
3892
3968
|
}
|
|
3893
3969
|
case "expiries": {
|
|
@@ -3902,14 +3978,14 @@ async function clientHome(base2, summary) {
|
|
|
3902
3978
|
body: { accessTokenExpiry: Number(a.access), idTokenExpiry: Number(a.id), refreshTokenExpiry: Number(a.refresh) },
|
|
3903
3979
|
summary: "Update token expiries"
|
|
3904
3980
|
});
|
|
3905
|
-
console.log(
|
|
3981
|
+
console.log(import_chalk30.default.green(" Expiries updated."));
|
|
3906
3982
|
break;
|
|
3907
3983
|
}
|
|
3908
3984
|
case "secret": {
|
|
3909
3985
|
const { sure } = await inquirer3.prompt([{ type: "confirm", name: "sure", message: "Print the client secret to this terminal?", default: false }]);
|
|
3910
3986
|
if (!sure) break;
|
|
3911
3987
|
const s = await admin({ method: "GET", path: `${cBase}/secret`, summary: "Reveal client secret" });
|
|
3912
|
-
console.log(` ${
|
|
3988
|
+
console.log(` ${import_chalk30.default.bold("client_secret")}: ${import_chalk30.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
|
|
3913
3989
|
break;
|
|
3914
3990
|
}
|
|
3915
3991
|
case "rotate": {
|
|
@@ -3917,14 +3993,14 @@ async function clientHome(base2, summary) {
|
|
|
3917
3993
|
if (!sure) break;
|
|
3918
3994
|
const fresh = randomSecret();
|
|
3919
3995
|
await admin({ method: "PATCH", path: cBase, body: { clientSecret: fresh }, summary: "Rotate client secret" });
|
|
3920
|
-
console.log(` New ${
|
|
3996
|
+
console.log(` New ${import_chalk30.default.bold("client_secret")}: ${import_chalk30.default.green(fresh)} ${import_chalk30.default.dim("(store it now)")}`);
|
|
3921
3997
|
break;
|
|
3922
3998
|
}
|
|
3923
3999
|
case "delete": {
|
|
3924
4000
|
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 }]);
|
|
3925
4001
|
if (!sure) break;
|
|
3926
4002
|
await admin({ method: "DELETE", path: cBase, summary: `Delete app client ${id}` });
|
|
3927
|
-
console.log(
|
|
4003
|
+
console.log(import_chalk30.default.green(" App client deleted."));
|
|
3928
4004
|
return;
|
|
3929
4005
|
}
|
|
3930
4006
|
}
|
|
@@ -3951,9 +4027,9 @@ async function providersMenu(cBase, clientLabel) {
|
|
|
3951
4027
|
const providers = Array.isArray(raw) ? raw : [];
|
|
3952
4028
|
console.log();
|
|
3953
4029
|
for (const p of providers) {
|
|
3954
|
-
console.log(` ${
|
|
4030
|
+
console.log(` ${import_chalk30.default.bold(p.type)} ${import_chalk30.default.dim(`${p.clientId || "(managed)"} \xB7 identity=${p.tokenType ?? "apiblaze"} \xB7 to-upstream=${p.targetServerToken ?? "apiblaze"}${p.isApiblazeDefault ? " \xB7 apiblaze-managed" : ""}`)}`);
|
|
3955
4031
|
}
|
|
3956
|
-
if (!providers.length) console.log(
|
|
4032
|
+
if (!providers.length) console.log(import_chalk30.default.dim(" No login providers \u2014 consumers cannot sign in to this client yet."));
|
|
3957
4033
|
const { act } = await inquirer3.prompt([{
|
|
3958
4034
|
type: "list",
|
|
3959
4035
|
name: "act",
|
|
@@ -4011,23 +4087,23 @@ async function providersMenu(cBase, clientLabel) {
|
|
|
4011
4087
|
body.targetServerToken = routing;
|
|
4012
4088
|
}
|
|
4013
4089
|
await admin({ method: "POST", path: `${cBase}/providers`, body, summary: `Add ${type} login provider` });
|
|
4014
|
-
console.log(
|
|
4090
|
+
console.log(import_chalk30.default.green(` ${type} provider added.`));
|
|
4015
4091
|
} else {
|
|
4016
4092
|
const { p } = await inquirer3.prompt([{
|
|
4017
4093
|
type: "list",
|
|
4018
4094
|
name: "p",
|
|
4019
4095
|
message: act === "rm" ? "Remove which provider?" : "Reveal which secret?",
|
|
4020
|
-
choices: [...providers.map((x) => ({ name: `${x.type} ${
|
|
4096
|
+
choices: [...providers.map((x) => ({ name: `${x.type} ${import_chalk30.default.dim(x.clientId || "(managed)")}`, value: x })), { name: "\u2190 Back", value: null }]
|
|
4021
4097
|
}]);
|
|
4022
4098
|
if (!p) continue;
|
|
4023
4099
|
if (act === "rm") {
|
|
4024
4100
|
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 }]);
|
|
4025
4101
|
if (!sure) continue;
|
|
4026
4102
|
await admin({ method: "DELETE", path: `${cBase}/providers/${encodeURIComponent(p.id)}`, summary: `Remove ${p.type} provider` });
|
|
4027
|
-
console.log(
|
|
4103
|
+
console.log(import_chalk30.default.green(` ${p.type} removed.`));
|
|
4028
4104
|
} else {
|
|
4029
4105
|
const s = await admin({ method: "GET", path: `${cBase}/providers/${encodeURIComponent(p.id)}/secret`, summary: `Reveal ${p.type} provider secret` });
|
|
4030
|
-
console.log(` ${
|
|
4106
|
+
console.log(` ${import_chalk30.default.bold("client_secret")}: ${import_chalk30.default.green(s?.clientSecret ?? s?.client_secret ?? JSON.stringify(s))}`);
|
|
4031
4107
|
}
|
|
4032
4108
|
}
|
|
4033
4109
|
}
|
|
@@ -4035,7 +4111,7 @@ async function providersMenu(cBase, clientLabel) {
|
|
|
4035
4111
|
|
|
4036
4112
|
// src/commands/spec.ts
|
|
4037
4113
|
var fs7 = __toESM(require("fs"));
|
|
4038
|
-
var
|
|
4114
|
+
var import_chalk31 = __toESM(require("chalk"));
|
|
4039
4115
|
var import_ora14 = __toESM(require("ora"));
|
|
4040
4116
|
init_admin();
|
|
4041
4117
|
init_api();
|
|
@@ -4052,14 +4128,14 @@ async function runSpecGet(project, opts) {
|
|
|
4052
4128
|
}
|
|
4053
4129
|
async function runSpecSet(project, opts) {
|
|
4054
4130
|
if (!opts.file) {
|
|
4055
|
-
console.error(
|
|
4131
|
+
console.error(import_chalk31.default.red("--file <path> is required (OpenAPI JSON or YAML)."));
|
|
4056
4132
|
process.exit(1);
|
|
4057
4133
|
}
|
|
4058
4134
|
let specContent;
|
|
4059
4135
|
try {
|
|
4060
4136
|
specContent = fs7.readFileSync(opts.file, "utf-8");
|
|
4061
4137
|
} catch {
|
|
4062
|
-
console.error(
|
|
4138
|
+
console.error(import_chalk31.default.red(`Cannot read file: ${opts.file}`));
|
|
4063
4139
|
process.exit(1);
|
|
4064
4140
|
}
|
|
4065
4141
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -4088,23 +4164,23 @@ async function runSpecSet(project, opts) {
|
|
|
4088
4164
|
function printSpecChangeReport(report, projectName) {
|
|
4089
4165
|
const r = report.routes;
|
|
4090
4166
|
if (r) {
|
|
4091
|
-
for (const a of r.added) console.log(
|
|
4092
|
-
for (const d of r.removed) console.log(
|
|
4093
|
-
for (const rn of r.renamed ?? []) console.log(
|
|
4094
|
-
for (const m of r.modified ?? []) console.log(
|
|
4167
|
+
for (const a of r.added) console.log(import_chalk31.default.green(` + ${a}`));
|
|
4168
|
+
for (const d of r.removed) console.log(import_chalk31.default.red(` \u2212 ${d}`));
|
|
4169
|
+
for (const rn of r.renamed ?? []) console.log(import_chalk31.default.yellow(` ~ ${rn.from} \u2192 ${rn.to}`));
|
|
4170
|
+
for (const m of r.modified ?? []) console.log(import_chalk31.default.dim(` \xB1 ${m} (params/schema changed)`));
|
|
4095
4171
|
}
|
|
4096
|
-
if (report.applied?.mcp_regenerated) console.log(
|
|
4097
|
-
if (report.applied?.candidates_cleared) console.log(
|
|
4172
|
+
if (report.applied?.mcp_regenerated) console.log(import_chalk31.default.dim(" MCP catalogue regenerated."));
|
|
4173
|
+
if (report.applied?.candidates_cleared) console.log(import_chalk31.default.dim(` ${report.applied.candidates_cleared} route candidate(s) now documented \u2014 cleared.`));
|
|
4098
4174
|
for (const item of report.attention ?? []) {
|
|
4099
|
-
console.log(
|
|
4175
|
+
console.log(import_chalk31.default.yellow(` \u26A0 ${item.detail}`));
|
|
4100
4176
|
if (item.suggestion?.carry_from && item.suggestion.carry_to) {
|
|
4101
|
-
console.log(
|
|
4177
|
+
console.log(import_chalk31.default.dim(` Fix: apiblaze spec carry ${projectName} --method ${item.suggestion.method} --from "${item.suggestion.carry_from}" --to "${item.suggestion.carry_to}"`));
|
|
4102
4178
|
}
|
|
4103
4179
|
}
|
|
4104
4180
|
}
|
|
4105
4181
|
async function runSpecCarry(project, opts) {
|
|
4106
4182
|
if (!opts.method || !opts.from || !opts.to) {
|
|
4107
|
-
console.error(
|
|
4183
|
+
console.error(import_chalk31.default.red("--method, --from and --to are required."));
|
|
4108
4184
|
process.exit(1);
|
|
4109
4185
|
}
|
|
4110
4186
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -4126,7 +4202,7 @@ async function runSpecCarry(project, opts) {
|
|
|
4126
4202
|
}
|
|
4127
4203
|
async function runSpecDeleteRule(project, opts) {
|
|
4128
4204
|
if (!opts.method || !opts.route) {
|
|
4129
|
-
console.error(
|
|
4205
|
+
console.error(import_chalk31.default.red("--method and --route are required."));
|
|
4130
4206
|
process.exit(1);
|
|
4131
4207
|
}
|
|
4132
4208
|
const { teamId } = await resolveTeam(opts.team);
|
|
@@ -4146,14 +4222,14 @@ async function runSpecDeleteRule(project, opts) {
|
|
|
4146
4222
|
}
|
|
4147
4223
|
|
|
4148
4224
|
// src/commands/agent.ts
|
|
4149
|
-
var
|
|
4225
|
+
var import_chalk33 = __toESM(require("chalk"));
|
|
4150
4226
|
var import_ora15 = __toESM(require("ora"));
|
|
4151
4227
|
init_auth();
|
|
4152
4228
|
init_admin();
|
|
4153
4229
|
init_resolve();
|
|
4154
4230
|
|
|
4155
4231
|
// src/lib/tools.ts
|
|
4156
|
-
var
|
|
4232
|
+
var import_chalk32 = __toESM(require("chalk"));
|
|
4157
4233
|
init_admin();
|
|
4158
4234
|
init_api();
|
|
4159
4235
|
init_resolve();
|
|
@@ -4173,15 +4249,15 @@ var TOOLS = [
|
|
|
4173
4249
|
const key = keys.dev ?? Object.values(keys)[0];
|
|
4174
4250
|
const url = `https://${a.name}.abz.run/${version2}/dev`;
|
|
4175
4251
|
const tryIt = buildTryItCurl(url, auth, key);
|
|
4176
|
-
const lines = [` ${
|
|
4177
|
-
if (res.devPortal) lines.push(` ${
|
|
4252
|
+
const lines = [` ${import_chalk32.default.dim("Proxy URL:")} ${import_chalk32.default.bold(url)}`];
|
|
4253
|
+
if (res.devPortal) lines.push(` ${import_chalk32.default.dim("Dev portal:")} ${res.devPortal}`);
|
|
4178
4254
|
const envs = Object.keys(keys);
|
|
4179
4255
|
if (envs.length) {
|
|
4180
|
-
lines.push("", ` ${
|
|
4256
|
+
lines.push("", ` ${import_chalk32.default.bold("API keys")} ${import_chalk32.default.dim("(bootstrapped \u2014 send as the X-API-Key header; shown once):")}`);
|
|
4181
4257
|
const w = Math.max(...envs.map((e) => e.length));
|
|
4182
|
-
for (const env of envs) lines.push(` ${
|
|
4258
|
+
for (const env of envs) lines.push(` ${import_chalk32.default.cyan(env.padEnd(w))} ${import_chalk32.default.green(keys[env])}`);
|
|
4183
4259
|
}
|
|
4184
|
-
if (tryIt) lines.push("", ` ${
|
|
4260
|
+
if (tryIt) lines.push("", ` ${import_chalk32.default.dim("Try it:")}`, ` ${import_chalk32.default.cyan(tryIt)}`);
|
|
4185
4261
|
return { ...res, proxy_url: url, keys, ...tryIt ? { try_it: tryIt } : {}, display: lines.join("\n") };
|
|
4186
4262
|
}
|
|
4187
4263
|
},
|
|
@@ -4337,17 +4413,17 @@ function truncate(value, max = 1500) {
|
|
|
4337
4413
|
}
|
|
4338
4414
|
function printCost(resp) {
|
|
4339
4415
|
const line = formatBilling(resp.billing);
|
|
4340
|
-
if (line) console.log(
|
|
4416
|
+
if (line) console.log(import_chalk33.default.magenta(` ${line}`) + import_chalk33.default.dim(` (${resp.llm.model}, ${resp.llm.total_tokens} tok)`));
|
|
4341
4417
|
}
|
|
4342
4418
|
async function runAgent(opts) {
|
|
4343
4419
|
requireAuth();
|
|
4344
4420
|
const { teamId, teamName } = await resolveTeam(opts.team);
|
|
4345
4421
|
const { default: inquirer3 } = await import("inquirer");
|
|
4346
|
-
console.log(
|
|
4347
|
-
console.log(
|
|
4422
|
+
console.log(import_chalk33.default.bold("APIblaze agent") + import_chalk33.default.dim(` \xB7 team ${teamName ?? teamId}`));
|
|
4423
|
+
console.log(import_chalk33.default.dim('Ask me to create/delete/configure proxies, tenants, keys, domains, specs. Type "exit" to quit.\n'));
|
|
4348
4424
|
const history = [];
|
|
4349
4425
|
while (true) {
|
|
4350
|
-
const { input } = await inquirer3.prompt([{ type: "input", name: "input", message:
|
|
4426
|
+
const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk33.default.cyan("you") + " \u203A" }]);
|
|
4351
4427
|
const text = (input ?? "").trim();
|
|
4352
4428
|
if (!text) continue;
|
|
4353
4429
|
if (["exit", "quit", ":q"].includes(text.toLowerCase())) break;
|
|
@@ -4361,14 +4437,14 @@ async function runAgent(opts) {
|
|
|
4361
4437
|
} catch (err) {
|
|
4362
4438
|
spinner.stop();
|
|
4363
4439
|
if (err instanceof ApiError && err.status === 402) {
|
|
4364
|
-
console.log(
|
|
4440
|
+
console.log(import_chalk33.default.yellow(" Insufficient credits \u2014 top up to keep using the agent."));
|
|
4365
4441
|
break;
|
|
4366
4442
|
}
|
|
4367
4443
|
throw err;
|
|
4368
4444
|
}
|
|
4369
4445
|
history.push({ role: "assistant", content: resp.raw });
|
|
4370
4446
|
printCost(resp);
|
|
4371
|
-
if (resp.reply) console.log(
|
|
4447
|
+
if (resp.reply) console.log(import_chalk33.default.green("agent") + " \u203A " + resp.reply);
|
|
4372
4448
|
if (!resp.action) break;
|
|
4373
4449
|
const tool = findTool(resp.action.tool);
|
|
4374
4450
|
if (!tool) {
|
|
@@ -4393,11 +4469,11 @@ async function runAgent(opts) {
|
|
|
4393
4469
|
}
|
|
4394
4470
|
renderTrace();
|
|
4395
4471
|
if (step === MAX_TOOL_STEPS - 1) {
|
|
4396
|
-
console.log(
|
|
4472
|
+
console.log(import_chalk33.default.dim(" (paused after several steps \u2014 tell me how to continue)"));
|
|
4397
4473
|
}
|
|
4398
4474
|
}
|
|
4399
4475
|
}
|
|
4400
|
-
console.log(
|
|
4476
|
+
console.log(import_chalk33.default.dim("\nBye."));
|
|
4401
4477
|
}
|
|
4402
4478
|
|
|
4403
4479
|
// src/commands/config-browse.ts
|
|
@@ -4636,11 +4712,11 @@ function dig(blob, dotted) {
|
|
|
4636
4712
|
}
|
|
4637
4713
|
var readSetting = (s, cfg) => s.read ? s.read(cfg) : dig(cfg, s.key);
|
|
4638
4714
|
function show(v) {
|
|
4639
|
-
if (v === void 0) return
|
|
4640
|
-
if (v === null) return
|
|
4641
|
-
if (typeof v === "object") return
|
|
4642
|
-
if (typeof v === "boolean") return v ?
|
|
4643
|
-
return
|
|
4715
|
+
if (v === void 0) return import_chalk34.default.dim("(unset)");
|
|
4716
|
+
if (v === null) return import_chalk34.default.dim("null");
|
|
4717
|
+
if (typeof v === "object") return import_chalk34.default.cyan(JSON.stringify(v));
|
|
4718
|
+
if (typeof v === "boolean") return v ? import_chalk34.default.green("on") : import_chalk34.default.red("off");
|
|
4719
|
+
return import_chalk34.default.cyan(String(v));
|
|
4644
4720
|
}
|
|
4645
4721
|
function parseValue(raw) {
|
|
4646
4722
|
if (raw === "true") return true;
|
|
@@ -4682,10 +4758,10 @@ async function patchSetting(proj2, s, value, cfg) {
|
|
|
4682
4758
|
}
|
|
4683
4759
|
}
|
|
4684
4760
|
var loginFirst = (what) => {
|
|
4685
|
-
console.log(
|
|
4761
|
+
console.log(import_chalk34.default.yellow(`
|
|
4686
4762
|
Log in first to ${what}.`));
|
|
4687
|
-
console.log(
|
|
4688
|
-
console.log(
|
|
4763
|
+
console.log(import_chalk34.default.dim(" Run `npx apiblaze login` \u2014 or `npx apiblaze claim` if you created this proxy"));
|
|
4764
|
+
console.log(import_chalk34.default.dim(" anonymously and want to bring it into your account.\n"));
|
|
4689
4765
|
};
|
|
4690
4766
|
async function runConfig(project, key, value, opts) {
|
|
4691
4767
|
const creds = loadCredentials();
|
|
@@ -4702,9 +4778,9 @@ async function runConfig(project, key, value, opts) {
|
|
|
4702
4778
|
}
|
|
4703
4779
|
const setting = SETTINGS.find((s) => s.key === key);
|
|
4704
4780
|
if (!setting) {
|
|
4705
|
-
console.error(
|
|
4706
|
-
console.error(
|
|
4707
|
-
console.error(
|
|
4781
|
+
console.error(import_chalk34.default.red(`Unknown setting "${key}".`));
|
|
4782
|
+
console.error(import_chalk34.default.dim(" Known: " + SETTINGS.map((s) => s.key).join(", ")));
|
|
4783
|
+
console.error(import_chalk34.default.dim(" (Features like transforms/domains/tenants live in the menu: `apiblaze config <project>`.)"));
|
|
4708
4784
|
process.exit(1);
|
|
4709
4785
|
}
|
|
4710
4786
|
if (value === void 0) {
|
|
@@ -4719,7 +4795,7 @@ async function pickProject(teamId) {
|
|
|
4719
4795
|
const { getProjects: getProjects2 } = await Promise.resolve().then(() => (init_api(), api_exports));
|
|
4720
4796
|
const projects = await getProjects2(teamId).catch(() => []);
|
|
4721
4797
|
if (!projects.length) {
|
|
4722
|
-
console.error(
|
|
4798
|
+
console.error(import_chalk34.default.red("No projects in this team. Create one: `npx apiblaze create`."));
|
|
4723
4799
|
process.exit(1);
|
|
4724
4800
|
}
|
|
4725
4801
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -4727,7 +4803,7 @@ async function pickProject(teamId) {
|
|
|
4727
4803
|
type: "list",
|
|
4728
4804
|
name: "picked",
|
|
4729
4805
|
message: "Which project?",
|
|
4730
|
-
choices: projects.map((p) => ({ name: `${p.projectName} ${
|
|
4806
|
+
choices: projects.map((p) => ({ name: `${p.projectName} ${import_chalk34.default.dim("v" + p.apiVersion)}`, value: p }))
|
|
4731
4807
|
}]);
|
|
4732
4808
|
return { projectId: picked.projectId, projectName: picked.projectName, apiVersion: picked.apiVersion, teamId, tenant: picked.tenant };
|
|
4733
4809
|
}
|
|
@@ -4738,25 +4814,25 @@ function printAll(proj2, cfg, json) {
|
|
|
4738
4814
|
console.log(JSON.stringify(out, null, 2));
|
|
4739
4815
|
return;
|
|
4740
4816
|
}
|
|
4741
|
-
console.log(
|
|
4817
|
+
console.log(import_chalk34.default.bold(`
|
|
4742
4818
|
${proj2.projectName} v${proj2.apiVersion} \u2014 settings
|
|
4743
4819
|
`));
|
|
4744
4820
|
for (const group2 of SETTING_GROUPS) {
|
|
4745
|
-
console.log(
|
|
4821
|
+
console.log(import_chalk34.default.bold(group2));
|
|
4746
4822
|
for (const s of SETTINGS.filter((x) => x.group === group2)) {
|
|
4747
|
-
console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${
|
|
4823
|
+
console.log(` ${s.key.padEnd(32)} ${show(readSetting(s, cfg))} ${import_chalk34.default.dim(s.desc)}`);
|
|
4748
4824
|
}
|
|
4749
4825
|
console.log();
|
|
4750
4826
|
}
|
|
4751
|
-
console.log(
|
|
4827
|
+
console.log(import_chalk34.default.dim("Change one: apiblaze config " + proj2.projectName + " <key> <value> (add --verbose for the API call)"));
|
|
4752
4828
|
}
|
|
4753
4829
|
async function discoveryMenu(project) {
|
|
4754
4830
|
const { default: inquirer3 } = await import("inquirer");
|
|
4755
|
-
console.log(
|
|
4831
|
+
console.log(import_chalk34.default.bold(`
|
|
4756
4832
|
APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
|
|
4757
4833
|
`));
|
|
4758
|
-
console.log(
|
|
4759
|
-
console.log(
|
|
4834
|
+
console.log(import_chalk34.default.dim("You are not logged in \u2014 browsing what's configurable. Everything below works"));
|
|
4835
|
+
console.log(import_chalk34.default.dim("from this menu once you log in (`npx apiblaze login`).\n"));
|
|
4760
4836
|
for (; ; ) {
|
|
4761
4837
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
4762
4838
|
type: "list",
|
|
@@ -4764,13 +4840,13 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
|
|
|
4764
4840
|
message: "Explore:",
|
|
4765
4841
|
pageSize: 20,
|
|
4766
4842
|
choices: [
|
|
4767
|
-
new inquirer3.Separator(
|
|
4843
|
+
new inquirer3.Separator(import_chalk34.default.bold("\u2014 Settings \u2014")),
|
|
4768
4844
|
...SETTING_GROUPS.map((g) => ({
|
|
4769
|
-
name: `${g} ${
|
|
4845
|
+
name: `${g} ${import_chalk34.default.dim(SETTINGS.filter((s) => s.group === g).map((s) => s.label).join(", "))}`,
|
|
4770
4846
|
value: { kind: "settings", g }
|
|
4771
4847
|
})),
|
|
4772
|
-
new inquirer3.Separator(
|
|
4773
|
-
...FEATURES.map((f) => ({ name: `${f.label} ${
|
|
4848
|
+
new inquirer3.Separator(import_chalk34.default.bold("\u2014 Features \u2014")),
|
|
4849
|
+
...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk34.default.dim(f.desc)}`, value: { kind: "feature", f } })),
|
|
4774
4850
|
new inquirer3.Separator(),
|
|
4775
4851
|
{ name: "Exit", value: { kind: "exit" } }
|
|
4776
4852
|
]
|
|
@@ -4779,24 +4855,24 @@ APIblaze proxy configuration${project ? ` \u2014 ${project}` : ""}
|
|
|
4779
4855
|
if (pick2.kind === "settings") {
|
|
4780
4856
|
console.log();
|
|
4781
4857
|
for (const s of SETTINGS.filter((x) => x.group === pick2.g)) {
|
|
4782
|
-
console.log(` ${
|
|
4783
|
-
console.log(` ${
|
|
4858
|
+
console.log(` ${import_chalk34.default.bold(s.label.padEnd(28))} ${import_chalk34.default.dim(s.desc)}`);
|
|
4859
|
+
console.log(` ${import_chalk34.default.dim(" key: " + s.key)}`);
|
|
4784
4860
|
}
|
|
4785
4861
|
loginFirst("view or change these settings");
|
|
4786
4862
|
} else {
|
|
4787
4863
|
const f = pick2.f;
|
|
4788
4864
|
console.log(`
|
|
4789
|
-
${
|
|
4865
|
+
${import_chalk34.default.bold(f.label)} \u2014 ${f.desc}`);
|
|
4790
4866
|
loginFirst(`use ${f.label.toLowerCase()}`);
|
|
4791
4867
|
}
|
|
4792
4868
|
}
|
|
4793
4869
|
}
|
|
4794
4870
|
async function navigator(proj2, cfg, opts) {
|
|
4795
4871
|
const { default: inquirer3 } = await import("inquirer");
|
|
4796
|
-
console.log(
|
|
4872
|
+
console.log(import_chalk34.default.bold(`
|
|
4797
4873
|
${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
|
|
4798
4874
|
`));
|
|
4799
|
-
console.log(
|
|
4875
|
+
console.log(import_chalk34.default.dim("Tip: every change is one API call \u2014 add --verbose to see the curl equivalent.\n"));
|
|
4800
4876
|
let blob = cfg;
|
|
4801
4877
|
for (; ; ) {
|
|
4802
4878
|
const { pick: pick2 } = await inquirer3.prompt([{
|
|
@@ -4805,10 +4881,10 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
|
|
|
4805
4881
|
message: "Where to?",
|
|
4806
4882
|
pageSize: 20,
|
|
4807
4883
|
choices: [
|
|
4808
|
-
new inquirer3.Separator(
|
|
4884
|
+
new inquirer3.Separator(import_chalk34.default.bold("\u2014 Settings \u2014")),
|
|
4809
4885
|
...SETTING_GROUPS.map((g) => ({ name: g, value: { kind: "settings", g } })),
|
|
4810
|
-
new inquirer3.Separator(
|
|
4811
|
-
...FEATURES.map((f) => ({ name: `${f.label} ${
|
|
4886
|
+
new inquirer3.Separator(import_chalk34.default.bold("\u2014 Features \u2014")),
|
|
4887
|
+
...FEATURES.map((f) => ({ name: `${f.label} ${import_chalk34.default.dim(f.desc)}`, value: { kind: f.go } })),
|
|
4812
4888
|
new inquirer3.Separator(),
|
|
4813
4889
|
{ name: "Show all settings", value: { kind: "list" } },
|
|
4814
4890
|
{ name: "Exit", value: { kind: "exit" } }
|
|
@@ -4848,7 +4924,7 @@ ${proj2.projectName} v${proj2.apiVersion} \u2014 configuration
|
|
|
4848
4924
|
}
|
|
4849
4925
|
}
|
|
4850
4926
|
} catch (err) {
|
|
4851
|
-
console.error(
|
|
4927
|
+
console.error(import_chalk34.default.red(` ${err instanceof Error ? err.message : String(err)}`));
|
|
4852
4928
|
}
|
|
4853
4929
|
}
|
|
4854
4930
|
}
|
|
@@ -4862,7 +4938,7 @@ async function settingsGroup(proj2, cfg, group2) {
|
|
|
4862
4938
|
message: group2 + ":",
|
|
4863
4939
|
pageSize: 16,
|
|
4864
4940
|
choices: [
|
|
4865
|
-
...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${
|
|
4941
|
+
...items.map((s2) => ({ name: `${s2.label.padEnd(30)} ${show(readSetting(s2, cfg))} ${import_chalk34.default.dim(s2.desc)}`, value: s2 })),
|
|
4866
4942
|
new inquirer3.Separator(),
|
|
4867
4943
|
{ name: "\u2190 Back", value: null }
|
|
4868
4944
|
]
|
|
@@ -4880,7 +4956,7 @@ async function settingsGroup(proj2, cfg, group2) {
|
|
|
4880
4956
|
} else if (s.type === "number") {
|
|
4881
4957
|
const { v } = await inquirer3.prompt([{ type: "input", name: "v", message: `${s.label} (number):`, default: readSetting(s, cfg) }]);
|
|
4882
4958
|
if (v === "" || Number.isNaN(Number(v))) {
|
|
4883
|
-
console.log(
|
|
4959
|
+
console.log(import_chalk34.default.yellow(" Not a number \u2014 unchanged."));
|
|
4884
4960
|
continue;
|
|
4885
4961
|
}
|
|
4886
4962
|
value = Number(v);
|
|
@@ -4961,7 +5037,7 @@ async function buildCondition(phase) {
|
|
|
4961
5037
|
const items = [];
|
|
4962
5038
|
for (; ; ) {
|
|
4963
5039
|
const a = await inquirer3.prompt([
|
|
4964
|
-
{ type: "input", name: "source", message: `Condition field ${
|
|
5040
|
+
{ type: "input", name: "source", message: `Condition field ${import_chalk34.default.dim(srcHint)}:`, validate: (s) => !!s || "required" },
|
|
4965
5041
|
{ type: "list", name: "operator", message: "Operator:", choices: [
|
|
4966
5042
|
"eq",
|
|
4967
5043
|
"neq",
|
|
@@ -4992,7 +5068,7 @@ async function buildCondition(phase) {
|
|
|
4992
5068
|
function showCondition(cond) {
|
|
4993
5069
|
if (!Array.isArray(cond) || !cond.length) return "";
|
|
4994
5070
|
const s = cond.map((c) => `${c.source} ${c.operator}${c.value !== void 0 ? ` "${c.value}"` : ""}${c.logicOp ? ` ${c.logicOp}` : ""}`).join(" ");
|
|
4995
|
-
return
|
|
5071
|
+
return import_chalk34.default.dim(` when ${s}`);
|
|
4996
5072
|
}
|
|
4997
5073
|
async function transformsMenu(proj2) {
|
|
4998
5074
|
const { default: inquirer3 } = await import("inquirer");
|
|
@@ -5001,12 +5077,12 @@ async function transformsMenu(proj2) {
|
|
|
5001
5077
|
const out = await admin({ method: "GET", path: base2, summary: "List transform rules" });
|
|
5002
5078
|
const rules = out?.rules ?? [];
|
|
5003
5079
|
console.log();
|
|
5004
|
-
if (!rules.length) console.log(
|
|
5080
|
+
if (!rules.length) console.log(import_chalk34.default.dim(" No transform rules yet."));
|
|
5005
5081
|
for (const r of rules) {
|
|
5006
5082
|
const a = r.action ?? {};
|
|
5007
5083
|
const fns = [...a.source_fns ?? [], ...a.dest_fns ?? []].map((f) => f.fn);
|
|
5008
|
-
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 ?
|
|
5009
|
-
console.log(` ${r.enabled ?
|
|
5084
|
+
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_chalk34.default.dim(` via ${fns.join("\u2192")}`) : ""}`;
|
|
5085
|
+
console.log(` ${r.enabled ? import_chalk34.default.green("\u25CF") : import_chalk34.default.dim("\u25CB")} ${import_chalk34.default.bold(r.name)} ${import_chalk34.default.dim(`[${r.phase ?? "request"}]`)} ${what}${showCondition(r.condition)}`);
|
|
5010
5086
|
}
|
|
5011
5087
|
const { act } = await inquirer3.prompt([{
|
|
5012
5088
|
type: "list",
|
|
@@ -5018,7 +5094,7 @@ async function transformsMenu(proj2) {
|
|
|
5018
5094
|
{ name: "Enable/disable a rule", value: "toggle" },
|
|
5019
5095
|
{ name: "Delete a rule", value: "delete" }
|
|
5020
5096
|
] : [],
|
|
5021
|
-
{ name:
|
|
5097
|
+
{ name: import_chalk34.default.dim("Add from raw JSON (grouped conditions, lookup tables, \u2026)"), value: "raw" },
|
|
5022
5098
|
{ name: "\u2190 Back", value: "back" }
|
|
5023
5099
|
]
|
|
5024
5100
|
}]);
|
|
@@ -5031,11 +5107,11 @@ async function transformsMenu(proj2) {
|
|
|
5031
5107
|
}]);
|
|
5032
5108
|
const body = parseValue(raw);
|
|
5033
5109
|
if (!body || typeof body !== "object" || Array.isArray(body)) {
|
|
5034
|
-
console.log(
|
|
5110
|
+
console.log(import_chalk34.default.yellow(" Not a JSON object \u2014 skipped."));
|
|
5035
5111
|
continue;
|
|
5036
5112
|
}
|
|
5037
5113
|
await admin({ method: "POST", path: base2, body, summary: "Create transform rule (raw JSON)" });
|
|
5038
|
-
console.log(
|
|
5114
|
+
console.log(import_chalk34.default.green(" Rule created."));
|
|
5039
5115
|
continue;
|
|
5040
5116
|
}
|
|
5041
5117
|
if (act === "add") {
|
|
@@ -5051,7 +5127,7 @@ async function transformsMenu(proj2) {
|
|
|
5051
5127
|
{ name: "Remove a field", value: "remove" }
|
|
5052
5128
|
] }
|
|
5053
5129
|
]);
|
|
5054
|
-
const fieldHint =
|
|
5130
|
+
const fieldHint = import_chalk34.default.dim("(e.g. header:x-api-version, param:limit, bodyvar:user.id)");
|
|
5055
5131
|
let action2;
|
|
5056
5132
|
if (ans.kind === "hardcode") {
|
|
5057
5133
|
const a = await inquirer3.prompt([
|
|
@@ -5098,16 +5174,16 @@ async function transformsMenu(proj2) {
|
|
|
5098
5174
|
type: "list",
|
|
5099
5175
|
name: "rule",
|
|
5100
5176
|
message: act === "toggle" ? "Which rule?" : "Delete which rule?",
|
|
5101
|
-
choices: [...rules.map((r) => ({ name: `${r.name} ${
|
|
5177
|
+
choices: [...rules.map((r) => ({ name: `${r.name} ${import_chalk34.default.dim(`[${r.phase ?? "request"}]`)}`, value: r })), { name: "\u2190 Back", value: null }]
|
|
5102
5178
|
}]);
|
|
5103
5179
|
if (!rule) continue;
|
|
5104
5180
|
if (act === "toggle") {
|
|
5105
5181
|
const flipped = { ...rule, enabled: rule.enabled === false };
|
|
5106
5182
|
await admin({ method: "PUT", path: `${base2}/${rule.id}`, body: flipped, summary: `${flipped.enabled ? "Enable" : "Disable"} transform "${rule.name}"` });
|
|
5107
|
-
console.log(
|
|
5183
|
+
console.log(import_chalk34.default.green(` ${rule.name} \u2192 ${flipped.enabled ? "enabled" : "disabled"}`));
|
|
5108
5184
|
} else {
|
|
5109
5185
|
await admin({ method: "DELETE", path: `${base2}/${rule.id}`, summary: `Delete transform "${rule.name}"` });
|
|
5110
|
-
console.log(
|
|
5186
|
+
console.log(import_chalk34.default.green(` ${rule.name} deleted.`));
|
|
5111
5187
|
}
|
|
5112
5188
|
}
|
|
5113
5189
|
}
|
|
@@ -5119,9 +5195,9 @@ async function mappingsMenu(proj2) {
|
|
|
5119
5195
|
const out = await admin({ method: "GET", path: base2, summary: "List mapping tables" });
|
|
5120
5196
|
const tables = out?.mappings ?? out?.tables ?? [];
|
|
5121
5197
|
console.log();
|
|
5122
|
-
if (!tables.length) console.log(
|
|
5198
|
+
if (!tables.length) console.log(import_chalk34.default.dim(" No mapping tables yet."));
|
|
5123
5199
|
for (const t of tables) {
|
|
5124
|
-
console.log(` ${
|
|
5200
|
+
console.log(` ${import_chalk34.default.bold(t.name)} ${import_chalk34.default.dim(`${t.entries?.length ?? "?"} entries${t.hide_map_values ? ", hidden" : ""}${t.encrypt_values ? ", encrypted" : ""}`)}`);
|
|
5125
5201
|
}
|
|
5126
5202
|
const { act } = await inquirer3.prompt([{
|
|
5127
5203
|
type: "list",
|
|
@@ -5141,11 +5217,11 @@ async function mappingsMenu(proj2) {
|
|
|
5141
5217
|
]);
|
|
5142
5218
|
const entries2 = parseValue(a.entries);
|
|
5143
5219
|
if (!Array.isArray(entries2)) {
|
|
5144
|
-
console.log(
|
|
5220
|
+
console.log(import_chalk34.default.yellow(" Entries must be a JSON array \u2014 not created."));
|
|
5145
5221
|
continue;
|
|
5146
5222
|
}
|
|
5147
5223
|
await admin({ method: "POST", path: base2, body: { name: a.name, entries: entries2 }, summary: `Create mapping table "${a.name}"` });
|
|
5148
|
-
console.log(
|
|
5224
|
+
console.log(import_chalk34.default.green(` Table "${a.name}" created.`));
|
|
5149
5225
|
} else {
|
|
5150
5226
|
const { table } = await inquirer3.prompt([{
|
|
5151
5227
|
type: "list",
|
|
@@ -5155,7 +5231,7 @@ async function mappingsMenu(proj2) {
|
|
|
5155
5231
|
}]);
|
|
5156
5232
|
if (!table) continue;
|
|
5157
5233
|
await admin({ method: "DELETE", path: `${base2}/${table.id}`, summary: `Delete mapping table "${table.name}"` });
|
|
5158
|
-
console.log(
|
|
5234
|
+
console.log(import_chalk34.default.green(` ${table.name} deleted.`));
|
|
5159
5235
|
}
|
|
5160
5236
|
}
|
|
5161
5237
|
}
|
|
@@ -5166,14 +5242,14 @@ async function tenantsMenu(proj2, opts) {
|
|
|
5166
5242
|
const out = await admin({ method: "GET", path: base2, summary: "List attached tenants" });
|
|
5167
5243
|
const tenants = out?.tenants ?? [];
|
|
5168
5244
|
console.log();
|
|
5169
|
-
if (!tenants.length) console.log(
|
|
5170
|
-
for (const t of tenants) console.log(` ${
|
|
5245
|
+
if (!tenants.length) console.log(import_chalk34.default.dim(" No tenants attached (consumers use the default tenant)."));
|
|
5246
|
+
for (const t of tenants) console.log(` ${import_chalk34.default.bold(t.tenant_name ?? t.name)} ${import_chalk34.default.dim(t.display_name ?? "")}`);
|
|
5171
5247
|
const { act } = await inquirer3.prompt([{
|
|
5172
5248
|
type: "list",
|
|
5173
5249
|
name: "act",
|
|
5174
5250
|
message: "Tenants:",
|
|
5175
5251
|
choices: [
|
|
5176
|
-
{ name: `Manage a tenant\u2026 ${
|
|
5252
|
+
{ name: `Manage a tenant\u2026 ${import_chalk34.default.dim("settings, login app clients, providers, issuers \u2014 affects EVERY proxy the tenant serves")}`, value: "manage" },
|
|
5177
5253
|
{ name: "Attach a tenant to this project", value: "attach" },
|
|
5178
5254
|
...tenants.length ? [{ name: "Detach a tenant from this project", value: "detach" }] : [],
|
|
5179
5255
|
{ name: "\u2190 Back", value: "back" }
|
|
@@ -5196,7 +5272,7 @@ async function tenantsMenu(proj2, opts) {
|
|
|
5196
5272
|
}]);
|
|
5197
5273
|
if (!t) continue;
|
|
5198
5274
|
await admin({ method: "DELETE", path: `${base2}/${encodeURIComponent(t.tenant_name ?? t.name)}`, summary: `Detach tenant ${t.tenant_name ?? t.name}` });
|
|
5199
|
-
console.log(
|
|
5275
|
+
console.log(import_chalk34.default.green(` Detached ${t.tenant_name ?? t.name}.`));
|
|
5200
5276
|
}
|
|
5201
5277
|
}
|
|
5202
5278
|
}
|
|
@@ -5239,7 +5315,7 @@ async function specMenu(proj2, opts) {
|
|
|
5239
5315
|
choices: [
|
|
5240
5316
|
{ name: "Print the stored spec", value: "get" },
|
|
5241
5317
|
{ name: "Refresh the spec from its source", value: "refresh" },
|
|
5242
|
-
{ name:
|
|
5318
|
+
{ name: import_chalk34.default.dim("Build the spec by chatting over real traffic \u2192 agent"), value: "agent" },
|
|
5243
5319
|
{ name: "\u2190 Back", value: "back" }
|
|
5244
5320
|
]
|
|
5245
5321
|
}]);
|
|
@@ -5247,7 +5323,7 @@ async function specMenu(proj2, opts) {
|
|
|
5247
5323
|
if (act === "get") await runSpecGet(proj2.projectName, { team: opts.team, apiversion: proj2.apiVersion });
|
|
5248
5324
|
else if (act === "refresh") {
|
|
5249
5325
|
await admin({ method: "POST", path: `/projects/${proj2.projectId}/${proj2.apiVersion}/refresh-spec`, summary: "Refresh spec from source" });
|
|
5250
|
-
console.log(
|
|
5326
|
+
console.log(import_chalk34.default.green(" Spec refresh triggered."));
|
|
5251
5327
|
} else await runOpenapi(proj2.projectName, proj2.apiVersion);
|
|
5252
5328
|
}
|
|
5253
5329
|
async function agentsMenu(proj2, opts) {
|
|
@@ -5272,7 +5348,7 @@ async function agentsMenu(proj2, opts) {
|
|
|
5272
5348
|
}
|
|
5273
5349
|
|
|
5274
5350
|
// src/commands/group.ts
|
|
5275
|
-
var
|
|
5351
|
+
var import_chalk35 = __toESM(require("chalk"));
|
|
5276
5352
|
var import_ora17 = __toESM(require("ora"));
|
|
5277
5353
|
init_auth();
|
|
5278
5354
|
init_admin();
|
|
@@ -5366,7 +5442,7 @@ async function userByRefOrCreate(t, ref) {
|
|
|
5366
5442
|
if (!ref.includes("@")) throw e;
|
|
5367
5443
|
const created = await t.call("/v1/admin/users", "POST", { email: ref.trim().toLowerCase() });
|
|
5368
5444
|
if (!created?.abz_sub) throw e;
|
|
5369
|
-
console.log(
|
|
5445
|
+
console.log(import_chalk35.default.dim(` ${ref} wasn't a user yet \u2014 created.`));
|
|
5370
5446
|
return { abz_sub: created.abz_sub, email: created.email ?? ref, display_name: null };
|
|
5371
5447
|
}
|
|
5372
5448
|
}
|
|
@@ -5374,11 +5450,11 @@ async function runGroupList(opts) {
|
|
|
5374
5450
|
const t = await resolveTransport(opts);
|
|
5375
5451
|
const groups = await listGroups(t);
|
|
5376
5452
|
if (opts.json) return void console.log(JSON.stringify(groups));
|
|
5377
|
-
if (!groups.length) return void console.log(
|
|
5378
|
-
console.log(
|
|
5453
|
+
if (!groups.length) return void console.log(import_chalk35.default.yellow(`No groups in ${t.tenant}. Create one: apiblaze group create <name>`));
|
|
5454
|
+
console.log(import_chalk35.default.dim(`Tenant ${t.tenant}:`));
|
|
5379
5455
|
for (const g of groups) {
|
|
5380
|
-
const sealed = g.name === "apiblaze_admins" ?
|
|
5381
|
-
console.log(` ${
|
|
5456
|
+
const sealed = g.name === "apiblaze_admins" ? import_chalk35.default.dim(" (admins \u2014 managed by allowlist)") : "";
|
|
5457
|
+
console.log(` ${import_chalk35.default.bold(g.name)} ${import_chalk35.default.dim(`${g.member_count ?? 0} member(s)`)}${sealed}`);
|
|
5382
5458
|
}
|
|
5383
5459
|
}
|
|
5384
5460
|
async function runGroupCreate(name, opts) {
|
|
@@ -5406,7 +5482,7 @@ async function runGroupCreate(name, opts) {
|
|
|
5406
5482
|
const spinner = (0, import_ora17.default)(`Creating group ${name}...`).start();
|
|
5407
5483
|
try {
|
|
5408
5484
|
await t.call("/v1/admin/groups", "POST", { name, admins: [adminSub] });
|
|
5409
|
-
spinner.succeed(`Group ${
|
|
5485
|
+
spinner.succeed(`Group ${import_chalk35.default.bold(name)} created in ${t.tenant}.`);
|
|
5410
5486
|
} catch (e) {
|
|
5411
5487
|
spinner.fail("Create failed.");
|
|
5412
5488
|
throw e;
|
|
@@ -5418,7 +5494,7 @@ async function runGroupDelete(name, opts) {
|
|
|
5418
5494
|
const spinner = (0, import_ora17.default)(`Deleting group ${name}...`).start();
|
|
5419
5495
|
try {
|
|
5420
5496
|
await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}`, "DELETE");
|
|
5421
|
-
spinner.succeed(`Group ${
|
|
5497
|
+
spinner.succeed(`Group ${import_chalk35.default.bold(name)} deleted.`);
|
|
5422
5498
|
} catch (e) {
|
|
5423
5499
|
spinner.fail("Delete failed.");
|
|
5424
5500
|
throw e;
|
|
@@ -5431,11 +5507,11 @@ async function runGroupMembers(name, opts) {
|
|
|
5431
5507
|
const subs = await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/subgroups`);
|
|
5432
5508
|
if (opts.json) return void console.log(JSON.stringify({ ...detail, subgroups: subs?.subgroups ?? [] }));
|
|
5433
5509
|
const members = detail?.members ?? [];
|
|
5434
|
-
console.log(
|
|
5435
|
-
for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ?
|
|
5436
|
-
if (!members.length) console.log(
|
|
5510
|
+
console.log(import_chalk35.default.bold(`${g.name}`) + import_chalk35.default.dim(` (${t.tenant})`));
|
|
5511
|
+
for (const m of members) console.log(` ${label2(m)} ${m.role === "admin" ? import_chalk35.default.cyan("group-admin") : import_chalk35.default.dim("member")}`);
|
|
5512
|
+
if (!members.length) console.log(import_chalk35.default.dim(" no members"));
|
|
5437
5513
|
const sg = subs?.subgroups ?? [];
|
|
5438
|
-
if (sg.length) console.log(
|
|
5514
|
+
if (sg.length) console.log(import_chalk35.default.dim(` subgroups: ${sg.map((s) => s.name).join(", ")}`));
|
|
5439
5515
|
}
|
|
5440
5516
|
async function runGroupAddUser(userRef, groupName, opts) {
|
|
5441
5517
|
const t = await resolveTransport(opts);
|
|
@@ -5445,7 +5521,7 @@ async function runGroupAddUser(userRef, groupName, opts) {
|
|
|
5445
5521
|
const spinner = (0, import_ora17.default)(`Adding ${label2(u)} to ${g.name}...`).start();
|
|
5446
5522
|
try {
|
|
5447
5523
|
await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members`, "POST", { abz_sub: u.abz_sub, role });
|
|
5448
|
-
spinner.succeed(`${
|
|
5524
|
+
spinner.succeed(`${import_chalk35.default.bold(label2(u))} added to ${import_chalk35.default.bold(g.name)} as ${role}.`);
|
|
5449
5525
|
} catch (e) {
|
|
5450
5526
|
spinner.fail("Add failed.");
|
|
5451
5527
|
throw e;
|
|
@@ -5457,7 +5533,7 @@ async function runGroupRemoveUser(userRef, groupName, opts) {
|
|
|
5457
5533
|
const spinner = (0, import_ora17.default)(`Removing ${label2(u)} from ${g.name}...`).start();
|
|
5458
5534
|
try {
|
|
5459
5535
|
await t.call(`/v1/admin/groups/${encodeURIComponent(g.id)}/members/_?abz_sub=${encodeURIComponent(u.abz_sub)}`, "DELETE");
|
|
5460
|
-
spinner.succeed(`${
|
|
5536
|
+
spinner.succeed(`${import_chalk35.default.bold(label2(u))} removed from ${import_chalk35.default.bold(g.name)}.`);
|
|
5461
5537
|
} catch (e) {
|
|
5462
5538
|
spinner.fail("Remove failed.");
|
|
5463
5539
|
throw e;
|
|
@@ -5469,7 +5545,7 @@ async function runGroupAddGroup(childName, parentName, opts) {
|
|
|
5469
5545
|
const spinner = (0, import_ora17.default)(`Nesting ${child.name} under ${parent.name}...`).start();
|
|
5470
5546
|
try {
|
|
5471
5547
|
await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups`, "POST", { child_group_id: child.id });
|
|
5472
|
-
spinner.succeed(`${
|
|
5548
|
+
spinner.succeed(`${import_chalk35.default.bold(child.name)} is now a subgroup of ${import_chalk35.default.bold(parent.name)}.`);
|
|
5473
5549
|
} catch (e) {
|
|
5474
5550
|
spinner.fail("Nest failed.");
|
|
5475
5551
|
throw e;
|
|
@@ -5481,7 +5557,7 @@ async function runGroupRemoveGroup(childName, parentName, opts) {
|
|
|
5481
5557
|
const spinner = (0, import_ora17.default)(`Un-nesting ${child.name} from ${parent.name}...`).start();
|
|
5482
5558
|
try {
|
|
5483
5559
|
await t.call(`/v1/admin/groups/${encodeURIComponent(parent.id)}/subgroups/${encodeURIComponent(child.id)}`, "DELETE");
|
|
5484
|
-
spinner.succeed(`${
|
|
5560
|
+
spinner.succeed(`${import_chalk35.default.bold(child.name)} un-nested from ${import_chalk35.default.bold(parent.name)}.`);
|
|
5485
5561
|
} catch (e) {
|
|
5486
5562
|
spinner.fail("Un-nest failed.");
|
|
5487
5563
|
throw e;
|
|
@@ -5492,18 +5568,18 @@ async function runGroupUsers(opts) {
|
|
|
5492
5568
|
const users = await listUsers(t);
|
|
5493
5569
|
const observed = await t.call("/v1/admin/observed-identities").catch(() => ({ identities: [] }));
|
|
5494
5570
|
if (opts.json) return void console.log(JSON.stringify({ users, observed: observed?.identities ?? [] }));
|
|
5495
|
-
console.log(
|
|
5496
|
-
for (const u of users) console.log(` ${label2(u)} ${
|
|
5497
|
-
if (!users.length) console.log(
|
|
5571
|
+
console.log(import_chalk35.default.dim(`Tenant ${t.tenant} \u2014 user directory:`));
|
|
5572
|
+
for (const u of users) console.log(` ${label2(u)} ${import_chalk35.default.dim(u.abz_sub)}`);
|
|
5573
|
+
if (!users.length) console.log(import_chalk35.default.dim(" no users yet"));
|
|
5498
5574
|
const fresh = (observed?.identities ?? []).filter((o) => !o.provisioned);
|
|
5499
5575
|
if (fresh.length) {
|
|
5500
|
-
console.log(
|
|
5501
|
-
for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${
|
|
5576
|
+
console.log(import_chalk35.default.dim("Seen in traffic (not yet users):"));
|
|
5577
|
+
for (const o of fresh) console.log(` ${o.email || o.abz_sub} ${import_chalk35.default.dim(o.source_label ?? "")}`);
|
|
5502
5578
|
}
|
|
5503
5579
|
}
|
|
5504
5580
|
|
|
5505
5581
|
// src/commands/key.ts
|
|
5506
|
-
var
|
|
5582
|
+
var import_chalk36 = __toESM(require("chalk"));
|
|
5507
5583
|
var import_ora18 = __toESM(require("ora"));
|
|
5508
5584
|
init_caller();
|
|
5509
5585
|
async function runApikeysMenu(opts) {
|
|
@@ -5533,11 +5609,11 @@ async function runKeyList(opts) {
|
|
|
5533
5609
|
return;
|
|
5534
5610
|
}
|
|
5535
5611
|
if (!keys.length) {
|
|
5536
|
-
console.log(
|
|
5612
|
+
console.log(import_chalk36.default.yellow("No developer keys."));
|
|
5537
5613
|
return;
|
|
5538
5614
|
}
|
|
5539
5615
|
for (const k of keys) {
|
|
5540
|
-
console.log(` ${
|
|
5616
|
+
console.log(` ${import_chalk36.default.bold(k.key_id ?? k.id)} ${import_chalk36.default.dim(k.description ?? "")} ${import_chalk36.default.dim(k.expires_at ?? "no expiry")}`);
|
|
5541
5617
|
}
|
|
5542
5618
|
}
|
|
5543
5619
|
async function runKeyMint(opts) {
|
|
@@ -5559,9 +5635,9 @@ async function runKeyMint(opts) {
|
|
|
5559
5635
|
console.log(JSON.stringify(out));
|
|
5560
5636
|
return;
|
|
5561
5637
|
}
|
|
5562
|
-
console.log(` ${
|
|
5563
|
-
console.log(` ${
|
|
5564
|
-
if (out?.expires_at) console.log(` ${
|
|
5638
|
+
console.log(` ${import_chalk36.default.bold("key_id")}: ${out?.key_id}`);
|
|
5639
|
+
console.log(` ${import_chalk36.default.bold("key")}: ${import_chalk36.default.green(out?.key)} ${import_chalk36.default.dim("(shown once \u2014 store it now)")}`);
|
|
5640
|
+
if (out?.expires_at) console.log(` ${import_chalk36.default.dim("expires:")} ${out.expires_at}`);
|
|
5565
5641
|
} catch (err) {
|
|
5566
5642
|
spinner.fail("Mint failed.");
|
|
5567
5643
|
throw err;
|
|
@@ -5588,7 +5664,7 @@ async function runKeyRevoke(keyId, opts) {
|
|
|
5588
5664
|
init_iam();
|
|
5589
5665
|
|
|
5590
5666
|
// src/commands/admins.ts
|
|
5591
|
-
var
|
|
5667
|
+
var import_chalk37 = __toESM(require("chalk"));
|
|
5592
5668
|
var import_ora19 = __toESM(require("ora"));
|
|
5593
5669
|
init_caller();
|
|
5594
5670
|
function requireTenant(opts) {
|
|
@@ -5616,13 +5692,13 @@ async function runAdminsList(opts) {
|
|
|
5616
5692
|
return;
|
|
5617
5693
|
}
|
|
5618
5694
|
if (!admins2.length) {
|
|
5619
|
-
console.log(
|
|
5695
|
+
console.log(import_chalk37.default.yellow(`No tenant admins for ${tenant2} yet.`));
|
|
5620
5696
|
return;
|
|
5621
5697
|
}
|
|
5622
5698
|
for (const a of admins2) {
|
|
5623
5699
|
const email = typeof a === "string" ? a : a.email;
|
|
5624
5700
|
const flags = [a.active === false ? "pending" : null, a.pinned ? "pinned" : null].filter(Boolean).join(", ");
|
|
5625
|
-
console.log(` ${
|
|
5701
|
+
console.log(` ${import_chalk37.default.bold(email)}${flags ? import_chalk37.default.dim(` (${flags})`) : ""}`);
|
|
5626
5702
|
}
|
|
5627
5703
|
}
|
|
5628
5704
|
async function runAdminsAdd(email, opts) {
|
|
@@ -5637,9 +5713,9 @@ async function runAdminsAdd(email, opts) {
|
|
|
5637
5713
|
body: { email },
|
|
5638
5714
|
summary: `Add ${email} to tenant ${tenant2} admins`
|
|
5639
5715
|
});
|
|
5640
|
-
spinner?.succeed(`${
|
|
5716
|
+
spinner?.succeed(`${import_chalk37.default.bold(email)} is now a tenant admin of ${import_chalk37.default.bold(tenant2)}.`);
|
|
5641
5717
|
if (opts.json) console.log(JSON.stringify(out ?? { ok: true }));
|
|
5642
|
-
else console.log(
|
|
5718
|
+
else console.log(import_chalk37.default.dim(" Reload the Users & Groups widget \u2014 access flips from \u201Cpending\u201D to ready."));
|
|
5643
5719
|
} catch (err) {
|
|
5644
5720
|
spinner?.fail("Add failed.");
|
|
5645
5721
|
throw err;
|
|
@@ -5656,7 +5732,7 @@ async function runAdminsRemove(email, opts) {
|
|
|
5656
5732
|
path: `${base(teamId, tenant2)}/${encodeURIComponent(email)}`,
|
|
5657
5733
|
summary: `Remove ${email} from tenant ${tenant2} admins`
|
|
5658
5734
|
});
|
|
5659
|
-
spinner?.succeed(`Removed ${
|
|
5735
|
+
spinner?.succeed(`Removed ${import_chalk37.default.bold(email)} from the tenant admins of ${import_chalk37.default.bold(tenant2)}.`);
|
|
5660
5736
|
} catch (err) {
|
|
5661
5737
|
spinner?.fail("Remove failed.");
|
|
5662
5738
|
throw err;
|
|
@@ -5664,7 +5740,7 @@ async function runAdminsRemove(email, opts) {
|
|
|
5664
5740
|
}
|
|
5665
5741
|
|
|
5666
5742
|
// src/commands/preapprove.ts
|
|
5667
|
-
var
|
|
5743
|
+
var import_chalk38 = __toESM(require("chalk"));
|
|
5668
5744
|
var import_ora20 = __toESM(require("ora"));
|
|
5669
5745
|
|
|
5670
5746
|
// src/lib/preapproval.ts
|
|
@@ -5729,14 +5805,14 @@ async function runPreapprove(who, opts) {
|
|
|
5729
5805
|
const rules = await listPreapprovalRules(tenant2);
|
|
5730
5806
|
if (opts.json) return void console.log(JSON.stringify(rules, null, 2));
|
|
5731
5807
|
if (!rules.length) {
|
|
5732
|
-
console.log(
|
|
5733
|
-
console.log(
|
|
5808
|
+
console.log(import_chalk38.default.dim(`No pre-approval rules in ${tenant2}. Anyone who signs in can access (unless access is restricted).`));
|
|
5809
|
+
console.log(import_chalk38.default.dim(`Add one: apiblaze preapprove someone@acme.com`));
|
|
5734
5810
|
return;
|
|
5735
5811
|
}
|
|
5736
|
-
console.log(
|
|
5812
|
+
console.log(import_chalk38.default.dim(`Pre-approved for ${import_chalk38.default.bold(tenant2)}:`));
|
|
5737
5813
|
for (const r of rules) {
|
|
5738
|
-
const tag = r.kind === "domain" ?
|
|
5739
|
-
const grp = r.groups?.length ?
|
|
5814
|
+
const tag = r.kind === "domain" ? import_chalk38.default.cyan("@" + r.value + " (whole domain)") : r.value;
|
|
5815
|
+
const grp = r.groups?.length ? import_chalk38.default.dim(` \u2192 groups: ${r.groups.join(", ")}`) : "";
|
|
5740
5816
|
console.log(` ${tag}${grp}`);
|
|
5741
5817
|
}
|
|
5742
5818
|
return;
|
|
@@ -5747,17 +5823,17 @@ async function runPreapprove(who, opts) {
|
|
|
5747
5823
|
if (opts.remove) {
|
|
5748
5824
|
const spinner2 = (0, import_ora20.default)(`Removing ${who} from ${tenant2}\u2026`).start();
|
|
5749
5825
|
const { removed, value } = await removePreapprovalRule(tenant2, who);
|
|
5750
|
-
if (removed) spinner2.succeed(`${
|
|
5751
|
-
else spinner2.warn(`No pre-approval rule for ${
|
|
5826
|
+
if (removed) spinner2.succeed(`${import_chalk38.default.bold(value)} is no longer pre-approved for ${tenant2}.`);
|
|
5827
|
+
else spinner2.warn(`No pre-approval rule for ${import_chalk38.default.bold(value)} in ${tenant2} \u2014 nothing to remove.`);
|
|
5752
5828
|
return;
|
|
5753
5829
|
}
|
|
5754
5830
|
const spinner = (0, import_ora20.default)(`Pre-approving ${who} for ${tenant2}\u2026`).start();
|
|
5755
5831
|
try {
|
|
5756
5832
|
const { kind, value } = await addPreapprovalRule(tenant2, who, opts.group);
|
|
5757
5833
|
const what = kind === "domain" ? `Anyone @${value}` : value;
|
|
5758
|
-
spinner.succeed(`${
|
|
5759
|
-
if (opts.group?.length) console.log(
|
|
5760
|
-
console.log(
|
|
5834
|
+
spinner.succeed(`${import_chalk38.default.bold(what)} can now sign in to ${import_chalk38.default.bold(tenant2)}.`);
|
|
5835
|
+
if (opts.group?.length) console.log(import_chalk38.default.dim(` They'll join group(s) ${opts.group.join(", ")} on first sign-in.`));
|
|
5836
|
+
console.log(import_chalk38.default.dim(` See the full list: apiblaze preapprove --list`));
|
|
5761
5837
|
} catch (err) {
|
|
5762
5838
|
spinner.fail("Could not add the rule.");
|
|
5763
5839
|
throw err;
|
|
@@ -5768,7 +5844,7 @@ async function runPreapprove(who, opts) {
|
|
|
5768
5844
|
var fs9 = __toESM(require("fs"));
|
|
5769
5845
|
var path6 = __toESM(require("path"));
|
|
5770
5846
|
var crypto2 = __toESM(require("crypto"));
|
|
5771
|
-
var
|
|
5847
|
+
var import_chalk40 = __toESM(require("chalk"));
|
|
5772
5848
|
var import_ora21 = __toESM(require("ora"));
|
|
5773
5849
|
var import_yaml2 = require("yaml");
|
|
5774
5850
|
init_auth();
|
|
@@ -5779,7 +5855,7 @@ init_admin();
|
|
|
5779
5855
|
// src/commands/llm.ts
|
|
5780
5856
|
var fs8 = __toESM(require("fs"));
|
|
5781
5857
|
var path5 = __toESM(require("path"));
|
|
5782
|
-
var
|
|
5858
|
+
var import_chalk39 = __toESM(require("chalk"));
|
|
5783
5859
|
var import_inquirer2 = __toESM(require("inquirer"));
|
|
5784
5860
|
init_auth();
|
|
5785
5861
|
var LLM_PATH = path5.join(getApiblazeDir(), "llm.json");
|
|
@@ -5823,27 +5899,27 @@ async function runLlmSetKey(keyArg, opts) {
|
|
|
5823
5899
|
}
|
|
5824
5900
|
const existing = loadLlmConfig();
|
|
5825
5901
|
saveLlmConfig({ key, provider, model: opts.model ?? existing?.model });
|
|
5826
|
-
console.log(`${
|
|
5827
|
-
console.log(
|
|
5828
|
-
if (opts.model) console.log(
|
|
5902
|
+
console.log(`${import_chalk39.default.green("\u2713")} Saved ${import_chalk39.default.bold(provider)} key ${maskSecret(key)}`);
|
|
5903
|
+
console.log(import_chalk39.default.gray(` Stored locally at ${LLM_PATH} (0600) \u2014 never sent to APIblaze except per chat turn.`));
|
|
5904
|
+
if (opts.model) console.log(import_chalk39.default.gray(` Model: ${opts.model}`));
|
|
5829
5905
|
}
|
|
5830
5906
|
async function runLlmShow() {
|
|
5831
5907
|
const cfg = loadLlmConfig();
|
|
5832
5908
|
if (!cfg) {
|
|
5833
|
-
console.log(
|
|
5909
|
+
console.log(import_chalk39.default.gray("No LLM key set. `apiblaze llm set-key sk-...` to add one (optional \u2014 chat works without it)."));
|
|
5834
5910
|
return;
|
|
5835
5911
|
}
|
|
5836
|
-
console.log(`Provider: ${
|
|
5912
|
+
console.log(`Provider: ${import_chalk39.default.bold(cfg.provider)}`);
|
|
5837
5913
|
console.log(`Key: ${maskSecret(cfg.key)}`);
|
|
5838
5914
|
if (cfg.model) console.log(`Model: ${cfg.model}`);
|
|
5839
|
-
console.log(
|
|
5915
|
+
console.log(import_chalk39.default.gray(`Stored at ${LLM_PATH}`));
|
|
5840
5916
|
}
|
|
5841
5917
|
async function runLlmClearKey() {
|
|
5842
5918
|
try {
|
|
5843
5919
|
fs8.unlinkSync(LLM_PATH);
|
|
5844
|
-
console.log(`${
|
|
5920
|
+
console.log(`${import_chalk39.default.green("\u2713")} Removed local LLM key.`);
|
|
5845
5921
|
} catch {
|
|
5846
|
-
console.log(
|
|
5922
|
+
console.log(import_chalk39.default.gray("No LLM key was set."));
|
|
5847
5923
|
}
|
|
5848
5924
|
}
|
|
5849
5925
|
|
|
@@ -5851,9 +5927,9 @@ async function runLlmClearKey() {
|
|
|
5851
5927
|
init_trace();
|
|
5852
5928
|
init_types();
|
|
5853
5929
|
function fail4(message, hint) {
|
|
5854
|
-
console.error(
|
|
5930
|
+
console.error(import_chalk40.default.red(`
|
|
5855
5931
|
Error: ${message}`));
|
|
5856
|
-
if (hint) console.error(
|
|
5932
|
+
if (hint) console.error(import_chalk40.default.dim(hint));
|
|
5857
5933
|
process.exit(1);
|
|
5858
5934
|
}
|
|
5859
5935
|
function normalizeName2(raw) {
|
|
@@ -6001,7 +6077,7 @@ async function resolveTargetAuth(spec2, opts) {
|
|
|
6001
6077
|
"Re-run with --force to provision anyway (configure target auth later with `apiblaze config`),\nor use an api_key / bearer / basic scheme."
|
|
6002
6078
|
);
|
|
6003
6079
|
}
|
|
6004
|
-
if (sawOAuth) console.log(
|
|
6080
|
+
if (sawOAuth) console.log(import_chalk40.default.yellow(" --force: skipping OAuth target auth \u2014 configure it later with `apiblaze config`."));
|
|
6005
6081
|
return null;
|
|
6006
6082
|
}
|
|
6007
6083
|
if (candidates.length === 1 && !noneAllowed) return candidates[0];
|
|
@@ -6074,7 +6150,7 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
|
|
|
6074
6150
|
const fresh = await validConsumerToken(existing);
|
|
6075
6151
|
if (fresh) {
|
|
6076
6152
|
if (fresh.accessToken !== existing.accessToken) saveConsumer({ ...fresh, resource });
|
|
6077
|
-
console.log(
|
|
6153
|
+
console.log(import_chalk40.default.dim(` Using your consumer session on ${import_chalk40.default.bold(tenant2)}${fresh.email ? ` (${fresh.email})` : ""}.`));
|
|
6078
6154
|
return fresh;
|
|
6079
6155
|
}
|
|
6080
6156
|
}
|
|
@@ -6093,13 +6169,13 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
|
|
|
6093
6169
|
);
|
|
6094
6170
|
}
|
|
6095
6171
|
const clientId = pick2.client_id ?? pick2.clientId;
|
|
6096
|
-
console.log(`${
|
|
6172
|
+
console.log(`${import_chalk40.default.cyan("\u2192")} This proxy signs consumers in with OAuth \u2014 logging you in to ${import_chalk40.default.bold(tenant2)}...`);
|
|
6097
6173
|
const result = await deviceLogin(clientId, "openid email profile offline_access", ({ verificationUri, userCode }) => {
|
|
6098
6174
|
console.log(`
|
|
6099
|
-
Open: ${
|
|
6100
|
-
console.log(` Code: ${
|
|
6175
|
+
Open: ${import_chalk40.default.underline(verificationUri)}`);
|
|
6176
|
+
console.log(` Code: ${import_chalk40.default.bold(userCode)}
|
|
6101
6177
|
`);
|
|
6102
|
-
console.log(
|
|
6178
|
+
console.log(import_chalk40.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
|
|
6103
6179
|
}, resource);
|
|
6104
6180
|
const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
|
|
6105
6181
|
const creds = {
|
|
@@ -6115,7 +6191,7 @@ async function ensureConsumerLogin(teamId, tenant2, version2) {
|
|
|
6115
6191
|
resource
|
|
6116
6192
|
};
|
|
6117
6193
|
saveConsumer(creds);
|
|
6118
|
-
console.log(` ${
|
|
6194
|
+
console.log(` ${import_chalk40.default.green("\u2714")} Signed in as${creds.email ? ` ${import_chalk40.default.bold(creds.email)}` : " a consumer"} on ${tenant2}.`);
|
|
6119
6195
|
return creds;
|
|
6120
6196
|
}
|
|
6121
6197
|
async function cpPost(anon, path8, body, summary) {
|
|
@@ -6144,13 +6220,18 @@ async function provision(spec2, target, opts) {
|
|
|
6144
6220
|
let name = opts.name ? base2 : `${base2}${salt()}`;
|
|
6145
6221
|
const access = anon ? "open" : opts.access === "open" ? "open" : "invite";
|
|
6146
6222
|
if (anon && opts.access === "invite") {
|
|
6147
|
-
console.log(
|
|
6223
|
+
console.log(import_chalk40.default.dim(" Note: --access invite needs an account to pre-approve people. Staying open for this anonymous proxy \u2014 run `apiblaze login`, then `apiblaze apichat --access invite`."));
|
|
6148
6224
|
}
|
|
6149
6225
|
const DUAL_AUTH = {
|
|
6150
6226
|
mode: "authenticate",
|
|
6151
6227
|
methods: ["api_key", "jwt"],
|
|
6152
6228
|
...access === "invite" ? { preapproved_users_only: true } : {}
|
|
6153
6229
|
};
|
|
6230
|
+
const chosenTenant = loggedIn ? await chooseTenantForCreate(loadCredentials()?.teamId, name, {
|
|
6231
|
+
tenant: opts.tenant,
|
|
6232
|
+
yes: opts.yes,
|
|
6233
|
+
json: opts.json
|
|
6234
|
+
}) : void 0;
|
|
6154
6235
|
const spinner = (0, import_ora21.default)("Provisioning an api_key proxy...").start();
|
|
6155
6236
|
let result;
|
|
6156
6237
|
for (let attempt = 0; attempt < 4; attempt++) {
|
|
@@ -6163,6 +6244,7 @@ async function provision(spec2, target, opts) {
|
|
|
6163
6244
|
auth_type: "api_key",
|
|
6164
6245
|
requests_auth: DUAL_AUTH,
|
|
6165
6246
|
team_id: creds.teamId,
|
|
6247
|
+
...chosenTenant ? { tenant: chosenTenant } : {},
|
|
6166
6248
|
...opts.apiversion ? { api_version: opts.apiversion } : {}
|
|
6167
6249
|
});
|
|
6168
6250
|
} else {
|
|
@@ -6237,7 +6319,7 @@ async function provision(spec2, target, opts) {
|
|
|
6237
6319
|
try {
|
|
6238
6320
|
await addPreapprovalRule(tenant2, email);
|
|
6239
6321
|
} catch {
|
|
6240
|
-
console.log(
|
|
6322
|
+
console.log(import_chalk40.default.dim(` (Could not auto-approve your email for sign-in \u2014 add it later: apiblaze preapprove ${email})`));
|
|
6241
6323
|
}
|
|
6242
6324
|
}
|
|
6243
6325
|
}
|
|
@@ -6281,7 +6363,7 @@ async function uploadSpec(p, specText, opts) {
|
|
|
6281
6363
|
throw err;
|
|
6282
6364
|
}
|
|
6283
6365
|
if (out && out.reused === true) {
|
|
6284
|
-
console.log(
|
|
6366
|
+
console.log(import_chalk40.default.dim(" Spec unchanged since the last provision \u2014 reusing the existing configuration."));
|
|
6285
6367
|
} else if (out && out.changed === true && out.previous_spec_hash) {
|
|
6286
6368
|
const interactive = !!process.stdin.isTTY && !opts.yes;
|
|
6287
6369
|
if (interactive) {
|
|
@@ -6289,7 +6371,7 @@ async function uploadSpec(p, specText, opts) {
|
|
|
6289
6371
|
const { go } = await inquirer3.prompt([
|
|
6290
6372
|
{ type: "confirm", name: "go", message: "The spec changed since the last provision \u2014 re-publish the MCP catalogue?", default: true }
|
|
6291
6373
|
]);
|
|
6292
|
-
if (!go) console.log(
|
|
6374
|
+
if (!go) console.log(import_chalk40.default.dim(" Keeping the existing MCP catalogue."));
|
|
6293
6375
|
}
|
|
6294
6376
|
}
|
|
6295
6377
|
}
|
|
@@ -6330,22 +6412,23 @@ var revealAuth = false;
|
|
|
6330
6412
|
function renderToolEvents(events, cred) {
|
|
6331
6413
|
for (const e of events ?? []) {
|
|
6332
6414
|
const ok = typeof e.status === "number" ? e.status < 400 : String(e.status).toLowerCase() === "ok";
|
|
6333
|
-
const mark = ok ?
|
|
6334
|
-
console.log(` ${mark} ${
|
|
6415
|
+
const mark = ok ? import_chalk40.default.green("\u2713") : import_chalk40.default.red("\u2717");
|
|
6416
|
+
console.log(` ${mark} ${import_chalk40.default.cyan(e.name)} ${import_chalk40.default.dim(`(${e.status}, ${e.ms}ms)`)}`);
|
|
6335
6417
|
if (isVerbose() && e.method && e.url) {
|
|
6336
|
-
console.log(
|
|
6418
|
+
console.log(import_chalk40.default.dim(` curl -sS -X ${e.method} '${e.url}'${cred ? " \\" : ""}`));
|
|
6337
6419
|
if (cred) {
|
|
6338
6420
|
const shown = revealAuth ? cred.value : maskKey(cred.value);
|
|
6339
6421
|
const keyLine = ` -H '${cred.header}: ${shown}'`;
|
|
6340
|
-
const hint = revealAuth ? "" :
|
|
6341
|
-
console.log(
|
|
6422
|
+
const hint = revealAuth ? "" : import_chalk40.default.yellow(" \u2190 /showauth will reveal this");
|
|
6423
|
+
console.log(import_chalk40.default.dim(keyLine) + hint);
|
|
6342
6424
|
}
|
|
6343
6425
|
}
|
|
6344
6426
|
}
|
|
6345
6427
|
}
|
|
6346
|
-
function
|
|
6347
|
-
const
|
|
6348
|
-
if (
|
|
6428
|
+
function renderToolResults(delta, events) {
|
|
6429
|
+
const anyFailed = (events ?? []).some((e) => e.status === "error");
|
|
6430
|
+
if (!anyFailed && !isVerbose()) return;
|
|
6431
|
+
const cap = anyFailed ? 24 : 12;
|
|
6349
6432
|
for (const m of delta ?? []) {
|
|
6350
6433
|
if (!m || m.role !== "tool" || typeof m.content !== "string") continue;
|
|
6351
6434
|
const body = m.content.trim();
|
|
@@ -6357,19 +6440,21 @@ function renderFailedToolResults(delta, events) {
|
|
|
6357
6440
|
return body;
|
|
6358
6441
|
}
|
|
6359
6442
|
})();
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6443
|
+
const lines = pretty.split("\n");
|
|
6444
|
+
console.log(import_chalk40.default.dim(" response:"));
|
|
6445
|
+
for (const line of lines.slice(0, cap)) {
|
|
6446
|
+
console.log(import_chalk40.default.dim(` ${line}`));
|
|
6363
6447
|
}
|
|
6448
|
+
if (lines.length > cap) console.log(import_chalk40.default.dim(` \u2026${lines.length - cap} more lines`));
|
|
6364
6449
|
}
|
|
6365
6450
|
}
|
|
6366
6451
|
function billingLine(billing) {
|
|
6367
6452
|
if (!billing || typeof billing.cents !== "number") return null;
|
|
6368
6453
|
if (typeof billing.free_turns_remaining === "number") return null;
|
|
6369
6454
|
const usd = (billing.cents / 100).toFixed(Math.abs(billing.cents - Math.round(billing.cents)) < 1e-9 ? 2 : 4);
|
|
6370
|
-
let line =
|
|
6455
|
+
let line = import_chalk40.default.magenta(` \u{1F4B3} $${usd}`) + import_chalk40.default.dim(billing.model ? ` \xB7 ${billing.model}` : "");
|
|
6371
6456
|
if (typeof billing.credits_remaining === "number") {
|
|
6372
|
-
line +=
|
|
6457
|
+
line += import_chalk40.default.dim(` \xB7 balance $${(billing.credits_remaining / 100).toFixed(2)}`);
|
|
6373
6458
|
}
|
|
6374
6459
|
return line;
|
|
6375
6460
|
}
|
|
@@ -6377,21 +6462,21 @@ function freeBudgetWarning(billing, anon) {
|
|
|
6377
6462
|
if (!anon || !billing) return null;
|
|
6378
6463
|
if (typeof billing.free_turns_remaining === "number") {
|
|
6379
6464
|
const left2 = billing.free_turns_remaining;
|
|
6380
|
-
if (left2 <= 0) return
|
|
6381
|
-
return
|
|
6465
|
+
if (left2 <= 0) return import_chalk40.default.yellow(" Free chats used up \u2014 `npx apiblaze login` (free) to keep going.");
|
|
6466
|
+
return import_chalk40.default.dim(` ${left2} free chat${left2 === 1 ? "" : "s"} left \xB7 /login to get more`);
|
|
6382
6467
|
}
|
|
6383
6468
|
if (typeof billing.free_remaining_cents !== "number") return null;
|
|
6384
6469
|
const perTurn = Math.max(billing.cents || 0, 0.02);
|
|
6385
6470
|
const left = Math.floor(billing.free_remaining_cents / perTurn);
|
|
6386
6471
|
if (left > 8) return null;
|
|
6387
|
-
if (left <= 0) return
|
|
6388
|
-
return
|
|
6472
|
+
if (left <= 0) return import_chalk40.default.yellow(" Free messages used up \u2014 `npx apiblaze login` (free) to keep chatting.");
|
|
6473
|
+
return import_chalk40.default.yellow(` \u26A0 About ${left} free message${left === 1 ? "" : "s"} left \u2014 \`npx apiblaze login\` (free) for more.`);
|
|
6389
6474
|
}
|
|
6390
6475
|
function printAssistant(delta) {
|
|
6391
6476
|
for (let i = delta.length - 1; i >= 0; i--) {
|
|
6392
6477
|
const m = delta[i];
|
|
6393
6478
|
if (m && m.role === "assistant" && typeof m.content === "string" && m.content.trim()) {
|
|
6394
|
-
console.log("\n" +
|
|
6479
|
+
console.log("\n" + import_chalk40.default.green("assistant \u203A ") + m.content + "\n");
|
|
6395
6480
|
return;
|
|
6396
6481
|
}
|
|
6397
6482
|
}
|
|
@@ -6417,7 +6502,7 @@ async function replTurn(p, messages, userText) {
|
|
|
6417
6502
|
});
|
|
6418
6503
|
} catch (err) {
|
|
6419
6504
|
spinner.fail("Network error.");
|
|
6420
|
-
console.log(
|
|
6505
|
+
console.log(import_chalk40.default.red(` Could not reach ${p.mcpHost}: ${err instanceof Error ? err.message : String(err)}`));
|
|
6421
6506
|
return;
|
|
6422
6507
|
}
|
|
6423
6508
|
let data = null;
|
|
@@ -6437,9 +6522,9 @@ async function replTurn(p, messages, userText) {
|
|
|
6437
6522
|
if (res.status === 401) {
|
|
6438
6523
|
const reason = data && (data.error || data.message) || null;
|
|
6439
6524
|
const usingKey = !p.consumerAuth;
|
|
6440
|
-
console.log(
|
|
6525
|
+
console.log(import_chalk40.default.red(` The proxy rejected the request (401)${reason ? `: ${reason}` : "."}`));
|
|
6441
6526
|
console.log(
|
|
6442
|
-
|
|
6527
|
+
import_chalk40.default.dim(
|
|
6443
6528
|
usingKey ? " Sent an API key. If the key was revoked, re-run `apiblaze apichat` to re-provision." : " Sent your consumer OAuth token. Re-run `apiblaze apichat` to sign in again."
|
|
6444
6529
|
)
|
|
6445
6530
|
);
|
|
@@ -6447,7 +6532,7 @@ async function replTurn(p, messages, userText) {
|
|
|
6447
6532
|
}
|
|
6448
6533
|
if (!res.ok || !data) {
|
|
6449
6534
|
const err = data && data.error || `HTTP ${res.status}`;
|
|
6450
|
-
console.log(
|
|
6535
|
+
console.log(import_chalk40.default.red(` Chat error: ${err}`));
|
|
6451
6536
|
return;
|
|
6452
6537
|
}
|
|
6453
6538
|
if (Array.isArray(data.delta)) {
|
|
@@ -6458,7 +6543,7 @@ async function replTurn(p, messages, userText) {
|
|
|
6458
6543
|
return t ? { header: "Authorization", value: `Bearer ${t}` } : void 0;
|
|
6459
6544
|
})() : p.dpKey ? { header: "X-API-Key", value: p.dpKey } : void 0
|
|
6460
6545
|
);
|
|
6461
|
-
|
|
6546
|
+
renderToolResults(data.delta, data.tool_events);
|
|
6462
6547
|
for (const m of data.delta) messages.push(m);
|
|
6463
6548
|
printAssistant(data.delta);
|
|
6464
6549
|
}
|
|
@@ -6468,25 +6553,25 @@ async function replTurn(p, messages, userText) {
|
|
|
6468
6553
|
if (warn) console.log(warn);
|
|
6469
6554
|
if (!data.continue) return;
|
|
6470
6555
|
}
|
|
6471
|
-
console.log(
|
|
6556
|
+
console.log(import_chalk40.default.dim(" (stopped after several tool rounds \u2014 ask again to continue)"));
|
|
6472
6557
|
}
|
|
6473
6558
|
function renderUpsell(p, upsell) {
|
|
6474
6559
|
const loggedIn = !!loadCredentials();
|
|
6475
6560
|
if (upsell.reason === "CAPPED" && !loggedIn) {
|
|
6476
|
-
console.log("\n" +
|
|
6477
|
-
console.log(
|
|
6561
|
+
console.log("\n" + import_chalk40.default.yellow(" Type `npx apiblaze login` to claim the rest of your balance."));
|
|
6562
|
+
console.log(import_chalk40.default.dim(" (or `/login` right here \u2014 your chat is preserved \u2014 or `apiblaze llm set-key` for your own model key.)"));
|
|
6478
6563
|
console.log();
|
|
6479
6564
|
return;
|
|
6480
6565
|
}
|
|
6481
|
-
console.log("\n" +
|
|
6566
|
+
console.log("\n" + import_chalk40.default.yellow(` ${upsell.message || "This turn is not available right now."}`));
|
|
6482
6567
|
if (upsell.reason === "INSUFFICIENT" || upsell.reason === "BREAKER" || upsell.reason === "CAPPED" || upsell.reason === "PAUSED") {
|
|
6483
6568
|
if (!loggedIn) {
|
|
6484
|
-
console.log(
|
|
6569
|
+
console.log(import_chalk40.default.dim(" Options: `/login` for more free chats and requests, or `apiblaze llm set-key` to bring your own model key."));
|
|
6485
6570
|
} else {
|
|
6486
|
-
console.log(
|
|
6571
|
+
console.log(import_chalk40.default.dim(" Options: top up your wallet, or `apiblaze llm set-key` to bring your own model key (bypasses platform limits)."));
|
|
6487
6572
|
}
|
|
6488
6573
|
} else if (upsell.reason === "INFLIGHT") {
|
|
6489
|
-
console.log(
|
|
6574
|
+
console.log(import_chalk40.default.dim(" Another turn is still in flight \u2014 wait a moment and try again."));
|
|
6490
6575
|
}
|
|
6491
6576
|
console.log();
|
|
6492
6577
|
}
|
|
@@ -6579,9 +6664,9 @@ async function openServerProxy(project) {
|
|
|
6579
6664
|
let consumerAuth = false;
|
|
6580
6665
|
if (acceptsApiKey) {
|
|
6581
6666
|
if (!dpKey) {
|
|
6582
|
-
console.log(
|
|
6667
|
+
console.log(import_chalk40.default.dim(` Minting an API key for tenant ${import_chalk40.default.bold(tenant2)} to query project ${import_chalk40.default.bold(project.projectName)}\u2026`));
|
|
6583
6668
|
dpKey = await mintDurableProxyKey(project.teamId, tenant2);
|
|
6584
|
-
console.log(` ${
|
|
6669
|
+
console.log(` ${import_chalk40.default.green("\u2714")} API key: ${import_chalk40.default.dim(maskKey(dpKey))}`);
|
|
6585
6670
|
}
|
|
6586
6671
|
} else {
|
|
6587
6672
|
consumerAuth = true;
|
|
@@ -6610,9 +6695,9 @@ async function openServerProxy(project) {
|
|
|
6610
6695
|
const spec2 = raw && (raw.spec ?? raw);
|
|
6611
6696
|
spinner.stop();
|
|
6612
6697
|
if (!spec2 || !(spec2.paths || spec2.openapi)) {
|
|
6613
|
-
console.log(
|
|
6698
|
+
console.log(import_chalk40.default.yellow(" This proxy has no OpenAPI spec yet \u2014 chat will have no tools. Build one with `apiblaze agent openapi`."));
|
|
6614
6699
|
} else {
|
|
6615
|
-
console.log(
|
|
6700
|
+
console.log(import_chalk40.default.dim(" Using the proxy's existing MCP catalogue (`apiblaze mcp` to rebuild it)."));
|
|
6616
6701
|
}
|
|
6617
6702
|
} catch (err) {
|
|
6618
6703
|
spinner.fail("Could not open the proxy.");
|
|
@@ -6668,7 +6753,7 @@ async function noArgsMenu(opts) {
|
|
|
6668
6753
|
const me = loadCredentials()?.apiblazeUserId;
|
|
6669
6754
|
const saved = loadApichats().filter((a) => a.anon ? true : a.ownerUserId !== void 0 && a.ownerUserId === me);
|
|
6670
6755
|
const choices = saved.map((a) => ({
|
|
6671
|
-
name: `Chat with ${
|
|
6756
|
+
name: `Chat with ${import_chalk40.default.bold(a.name)} ${import_chalk40.default.dim(`(${a.target})${a.messages && a.messages.length ? ` \xB7 ${a.messages.length} msgs` : ""}`)}`,
|
|
6672
6757
|
value: { type: "existing", a }
|
|
6673
6758
|
}));
|
|
6674
6759
|
const creds = loadCredentials();
|
|
@@ -6678,14 +6763,14 @@ async function noArgsMenu(opts) {
|
|
|
6678
6763
|
const proxies = (await getProjects(creds.teamId)).filter((pr) => !savedIds.has(pr.projectId));
|
|
6679
6764
|
for (const pr of proxies) {
|
|
6680
6765
|
choices.push({
|
|
6681
|
-
name: `Chat with ${
|
|
6766
|
+
name: `Chat with ${import_chalk40.default.bold(pr.projectName)} ${import_chalk40.default.dim(`(v${pr.apiVersion}) \xB7 your proxy`)}`,
|
|
6682
6767
|
value: { type: "server", project: pr }
|
|
6683
6768
|
});
|
|
6684
6769
|
}
|
|
6685
6770
|
} catch {
|
|
6686
6771
|
}
|
|
6687
6772
|
}
|
|
6688
|
-
choices.push({ name:
|
|
6773
|
+
choices.push({ name: import_chalk40.default.green("\uFF0B Create a new apichat"), value: { type: "new" } });
|
|
6689
6774
|
const { pick: pick2 } = await inquirer3.prompt([
|
|
6690
6775
|
{ type: "list", name: "pick", message: "What would you like to do?", choices }
|
|
6691
6776
|
]);
|
|
@@ -6788,36 +6873,36 @@ async function noArgsMenu(opts) {
|
|
|
6788
6873
|
async function runRepl(p, initialMessages) {
|
|
6789
6874
|
const { default: inquirer3 } = await import("inquirer");
|
|
6790
6875
|
const messages = initialMessages && initialMessages.length ? initialMessages.slice() : [];
|
|
6791
|
-
console.log("\n" +
|
|
6792
|
-
if (messages.length) console.log(
|
|
6876
|
+
console.log("\n" + import_chalk40.default.cyan.bold("Chat with your API") + import_chalk40.default.dim(` \xB7 ${p.mcpHost}`));
|
|
6877
|
+
if (messages.length) console.log(import_chalk40.default.dim(` Resumed \u2014 ${messages.length} prior messages.`));
|
|
6793
6878
|
const llm2 = loadLlmConfig();
|
|
6794
6879
|
console.log(
|
|
6795
|
-
|
|
6880
|
+
import_chalk40.default.dim(
|
|
6796
6881
|
llm2 ? `Using your local ${llm2.provider} key for the model. Type a question, or /exit. /login /claim manage your workspace.` : "Ask a question in plain English. /exit to quit \xB7 /login for more free chats \xB7 /claim to keep this workspace \xB7 `apiblaze llm set-key` for BYO models."
|
|
6797
6882
|
)
|
|
6798
6883
|
);
|
|
6799
6884
|
for (; ; ) {
|
|
6800
|
-
const { input } = await inquirer3.prompt([{ type: "input", name: "input", message:
|
|
6885
|
+
const { input } = await inquirer3.prompt([{ type: "input", name: "input", message: import_chalk40.default.green("you \u203A") }]);
|
|
6801
6886
|
const text = (input ?? "").trim();
|
|
6802
6887
|
if (!text) continue;
|
|
6803
6888
|
if (["/exit", "/quit", "exit", "quit", ":q"].includes(text.toLowerCase())) break;
|
|
6804
6889
|
if (text === "/login") {
|
|
6805
6890
|
try {
|
|
6806
6891
|
await runLogin();
|
|
6807
|
-
console.log(
|
|
6892
|
+
console.log(import_chalk40.default.dim(" Logged in \u2014 history preserved. Keep chatting."));
|
|
6808
6893
|
} catch (err) {
|
|
6809
|
-
console.log(
|
|
6894
|
+
console.log(import_chalk40.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
6810
6895
|
}
|
|
6811
6896
|
continue;
|
|
6812
6897
|
}
|
|
6813
6898
|
if (text === "/claim") {
|
|
6814
6899
|
const justLoggedIn = !loadCredentials();
|
|
6815
6900
|
if (justLoggedIn) {
|
|
6816
|
-
console.log(
|
|
6901
|
+
console.log(import_chalk40.default.dim(" Logging in to claim your workspace\u2026"));
|
|
6817
6902
|
try {
|
|
6818
6903
|
await runLogin();
|
|
6819
6904
|
} catch (err) {
|
|
6820
|
-
console.log(
|
|
6905
|
+
console.log(import_chalk40.default.red(` Login failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
6821
6906
|
continue;
|
|
6822
6907
|
}
|
|
6823
6908
|
if (!loadCredentials()) continue;
|
|
@@ -6828,30 +6913,30 @@ async function runRepl(p, initialMessages) {
|
|
|
6828
6913
|
p.mcpHost = p.mcpHost.replace(".mcp.tryabz.run", ".mcp.abz.run");
|
|
6829
6914
|
p.anon = false;
|
|
6830
6915
|
claimApichat(p, loadCredentials()?.apiblazeUserId);
|
|
6831
|
-
console.log(
|
|
6916
|
+
console.log(import_chalk40.default.dim(` Workspace claimed \u2014 chat now routes on ${p.mcpHost}. History preserved.`));
|
|
6832
6917
|
}
|
|
6833
6918
|
} catch (err) {
|
|
6834
|
-
console.log(
|
|
6919
|
+
console.log(import_chalk40.default.red(` Claim failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
6835
6920
|
}
|
|
6836
6921
|
continue;
|
|
6837
6922
|
}
|
|
6838
6923
|
if (text === "/showauth") {
|
|
6839
6924
|
revealAuth = !revealAuth;
|
|
6840
|
-
console.log(
|
|
6925
|
+
console.log(import_chalk40.default.dim(revealAuth ? " The real API key will be shown in the next call's curl. /showauth again to re-mask." : " API key re-masked."));
|
|
6841
6926
|
continue;
|
|
6842
6927
|
}
|
|
6843
6928
|
if (text.startsWith("/")) {
|
|
6844
|
-
console.log(
|
|
6929
|
+
console.log(import_chalk40.default.dim(" Commands: /login /claim /showauth /exit"));
|
|
6845
6930
|
continue;
|
|
6846
6931
|
}
|
|
6847
6932
|
await replTurn(p, messages, text);
|
|
6848
6933
|
saveTranscript(p, messages);
|
|
6849
6934
|
}
|
|
6850
|
-
console.log(
|
|
6935
|
+
console.log(import_chalk40.default.dim("\nBye."));
|
|
6851
6936
|
}
|
|
6852
6937
|
async function runApichat(opts) {
|
|
6853
6938
|
setVerbose(opts.verbose !== false);
|
|
6854
|
-
console.log(
|
|
6939
|
+
console.log(import_chalk40.default.bold("\napichat \u2014 turn any API into a chat\n"));
|
|
6855
6940
|
if (!opts.openapispec && !opts.target) {
|
|
6856
6941
|
if (!process.stdin.isTTY) {
|
|
6857
6942
|
fail4("No spec source. Pass --openapispec <file|url> or --target <url>.", GENERATOR_HINT);
|
|
@@ -6864,7 +6949,7 @@ async function runApichat(opts) {
|
|
|
6864
6949
|
}
|
|
6865
6950
|
const { spec: spec2, sourceUrl } = await loadSpec(opts);
|
|
6866
6951
|
const target = resolveTarget(spec2, opts, sourceUrl);
|
|
6867
|
-
console.log(` ${
|
|
6952
|
+
console.log(` ${import_chalk40.default.dim("Target:")} ${import_chalk40.default.bold(target)}`);
|
|
6868
6953
|
const auth = await resolveTargetAuth(spec2, opts);
|
|
6869
6954
|
if (auth && !process.stdin.isTTY && !opts.targetAuthEnv) {
|
|
6870
6955
|
fail4(
|
|
@@ -6873,7 +6958,7 @@ async function runApichat(opts) {
|
|
|
6873
6958
|
);
|
|
6874
6959
|
}
|
|
6875
6960
|
const p = await provision(spec2, target, opts);
|
|
6876
|
-
console.log(` ${
|
|
6961
|
+
console.log(` ${import_chalk40.default.dim("Proxy: ")} ${import_chalk40.default.bold(p.proxyUrl || `${p.projectId} v${p.version}`)}`);
|
|
6877
6962
|
upsertApichat({
|
|
6878
6963
|
name: p.projectId,
|
|
6879
6964
|
target,
|
|
@@ -6893,30 +6978,30 @@ async function runApichat(opts) {
|
|
|
6893
6978
|
const secret = await captureTargetSecret(auth, opts);
|
|
6894
6979
|
if (secret) await writeTargetAuth(p, auth, secret);
|
|
6895
6980
|
} else {
|
|
6896
|
-
console.log(
|
|
6981
|
+
console.log(import_chalk40.default.dim(" Target auth: none required."));
|
|
6897
6982
|
}
|
|
6898
6983
|
const specText = JSON.stringify(spec2);
|
|
6899
6984
|
await uploadSpec(p, specText, opts);
|
|
6900
6985
|
const mcpUrl = await publishMcp(p, spec2);
|
|
6901
6986
|
console.log();
|
|
6902
|
-
if (p.proxyUrl) console.log(` ${
|
|
6987
|
+
if (p.proxyUrl) console.log(` ${import_chalk40.default.green("\u2713")} proxy ${import_chalk40.default.bold(p.proxyUrl)}`);
|
|
6903
6988
|
if (mcpUrl) {
|
|
6904
|
-
console.log(` ${
|
|
6989
|
+
console.log(` ${import_chalk40.default.green("\u2713")} mcp ${import_chalk40.default.bold(mcpUrl)}`);
|
|
6905
6990
|
if (p.access === "invite") {
|
|
6906
|
-
console.log(
|
|
6907
|
-
console.log(
|
|
6991
|
+
console.log(import_chalk40.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: invite \u2014 only you + emails you pre-approve"));
|
|
6992
|
+
console.log(import_chalk40.default.dim(` Let others in: apiblaze preapprove someone@company.com${p.tenant ? ` --tenant ${p.tenant}` : ""} (or re-run with --access open)`));
|
|
6908
6993
|
} else {
|
|
6909
|
-
console.log(
|
|
6994
|
+
console.log(import_chalk40.default.dim(" Claude/ChatGPT-connectable (GitHub sign-in) \xB7 access: open \u2014 anyone who signs in can call this API"));
|
|
6910
6995
|
}
|
|
6911
6996
|
}
|
|
6912
6997
|
if (p.anon) {
|
|
6913
|
-
console.log(
|
|
6998
|
+
console.log(import_chalk40.default.dim("\n Anonymous workspace \u2014 /claim inside the chat to log in and keep it beyond 30 days."));
|
|
6914
6999
|
}
|
|
6915
7000
|
await runRepl(p);
|
|
6916
7001
|
}
|
|
6917
7002
|
|
|
6918
7003
|
// src/commands/consumer.ts
|
|
6919
|
-
var
|
|
7004
|
+
var import_chalk41 = __toESM(require("chalk"));
|
|
6920
7005
|
var import_ora22 = __toESM(require("ora"));
|
|
6921
7006
|
init_admin();
|
|
6922
7007
|
init_resolve();
|
|
@@ -6938,7 +7023,7 @@ async function consumerFetch(creds, suffix, init) {
|
|
|
6938
7023
|
function requireConsumer() {
|
|
6939
7024
|
const c = loadConsumer();
|
|
6940
7025
|
if (!c) {
|
|
6941
|
-
console.error(
|
|
7026
|
+
console.error(import_chalk41.default.red("Not logged in as a consumer. Run `apiblaze consumer login` first."));
|
|
6942
7027
|
process.exit(1);
|
|
6943
7028
|
}
|
|
6944
7029
|
return c;
|
|
@@ -6949,7 +7034,7 @@ async function runConsumerLogin(opts) {
|
|
|
6949
7034
|
let clientId = opts.client;
|
|
6950
7035
|
if (clientId) {
|
|
6951
7036
|
if (!tenant2) {
|
|
6952
|
-
console.error(
|
|
7037
|
+
console.error(import_chalk41.default.red("When using --client, also pass --tenant <slug> (it sets which portal/keys host to use)."));
|
|
6953
7038
|
process.exit(1);
|
|
6954
7039
|
}
|
|
6955
7040
|
} else {
|
|
@@ -6967,19 +7052,19 @@ async function runConsumerLogin(opts) {
|
|
|
6967
7052
|
const usable = (Array.isArray(clients) ? clients : []).filter((c) => c && (c.client_id || c.clientId));
|
|
6968
7053
|
const pick2 = usable.find((c) => c.is_default || c.default) ?? usable.find((c) => c.verified !== false) ?? usable[0];
|
|
6969
7054
|
if (!pick2) {
|
|
6970
|
-
console.error(
|
|
7055
|
+
console.error(import_chalk41.default.red(`Tenant "${tenant2}" has no login app configured. Set one up in the dashboard (or \`apiblaze create\` with auth).`));
|
|
6971
7056
|
process.exit(1);
|
|
6972
7057
|
}
|
|
6973
7058
|
clientId = pick2.client_id ?? pick2.clientId;
|
|
6974
7059
|
}
|
|
6975
7060
|
const portalResource = `https://${tenant2}.portal.apiblaze.com/1.0.0`;
|
|
6976
|
-
console.log(`${
|
|
7061
|
+
console.log(`${import_chalk41.default.cyan("\u2192")} Logging in to ${import_chalk41.default.bold(tenant2)} as a consumer...`);
|
|
6977
7062
|
const result = await deviceLogin(clientId, DEFAULT_SCOPE, ({ verificationUri, userCode }) => {
|
|
6978
7063
|
console.log(`
|
|
6979
|
-
Open: ${
|
|
6980
|
-
console.log(` Code: ${
|
|
7064
|
+
Open: ${import_chalk41.default.underline(verificationUri)}`);
|
|
7065
|
+
console.log(` Code: ${import_chalk41.default.bold(userCode)}
|
|
6981
7066
|
`);
|
|
6982
|
-
console.log(
|
|
7067
|
+
console.log(import_chalk41.default.dim(" (opening your browser\u2026 waiting for you to finish)"));
|
|
6983
7068
|
}, portalResource);
|
|
6984
7069
|
const claims = result.idToken && decodeJwt2(result.idToken) || (decodeJwt2(result.accessToken) ?? {});
|
|
6985
7070
|
const creds = {
|
|
@@ -6994,7 +7079,7 @@ async function runConsumerLogin(opts) {
|
|
|
6994
7079
|
obtainedAt: Date.now()
|
|
6995
7080
|
};
|
|
6996
7081
|
saveConsumer(creds);
|
|
6997
|
-
console.log(
|
|
7082
|
+
console.log(import_chalk41.default.green(`\u2714 Logged in as consumer${creds.email ? ` ${creds.email}` : ""} on ${tenant2}.`));
|
|
6998
7083
|
}
|
|
6999
7084
|
async function runConsumerTokens(opts) {
|
|
7000
7085
|
const creds = requireConsumer();
|
|
@@ -7007,18 +7092,18 @@ async function runConsumerTokens(opts) {
|
|
|
7007
7092
|
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));
|
|
7008
7093
|
return;
|
|
7009
7094
|
}
|
|
7010
|
-
console.log(`${
|
|
7095
|
+
console.log(`${import_chalk41.default.cyan("Consumer")} ${import_chalk41.default.bold(fresh.email ?? fresh.tenant)} on ${import_chalk41.default.bold(fresh.tenant)}
|
|
7011
7096
|
`);
|
|
7012
|
-
console.log(`${
|
|
7097
|
+
console.log(`${import_chalk41.default.bold("access_token")} ${import_chalk41.default.dim("exp " + (exp(fresh.accessToken) ?? "?"))}
|
|
7013
7098
|
${fresh.accessToken}
|
|
7014
7099
|
`);
|
|
7015
|
-
if (fresh.idToken) console.log(`${
|
|
7100
|
+
if (fresh.idToken) console.log(`${import_chalk41.default.bold("id_token")} ${import_chalk41.default.dim("exp " + (exp(fresh.idToken) ?? "?"))}
|
|
7016
7101
|
${fresh.idToken}
|
|
7017
7102
|
`);
|
|
7018
|
-
if (fresh.refreshToken) console.log(`${
|
|
7103
|
+
if (fresh.refreshToken) console.log(`${import_chalk41.default.bold("refresh_token")}
|
|
7019
7104
|
${fresh.refreshToken}
|
|
7020
7105
|
`);
|
|
7021
|
-
console.log(
|
|
7106
|
+
console.log(import_chalk41.default.dim("These are your own tokens \u2014 keep them secret."));
|
|
7022
7107
|
}
|
|
7023
7108
|
async function runConsumerApikeys(opts) {
|
|
7024
7109
|
const creds = requireConsumer();
|
|
@@ -7028,8 +7113,8 @@ async function runConsumerApikeys(opts) {
|
|
|
7028
7113
|
const revealed = await consumerFetch(list.creds, "/apikeys/reveal").catch(() => ({ status: 0, data: null, creds: list.creds }));
|
|
7029
7114
|
spinner.stop();
|
|
7030
7115
|
if (list.status >= 400) {
|
|
7031
|
-
console.error(
|
|
7032
|
-
if (list.status === 401) console.error(
|
|
7116
|
+
console.error(import_chalk41.default.red(`Failed to list keys (${list.status}): ${list.data?.error ?? ""}`));
|
|
7117
|
+
if (list.status === 401) console.error(import_chalk41.default.dim("Your consumer session may have expired \u2014 run `apiblaze consumer login` again."));
|
|
7033
7118
|
process.exit(1);
|
|
7034
7119
|
}
|
|
7035
7120
|
const keys = list.data?.keys ?? [];
|
|
@@ -7037,16 +7122,16 @@ async function runConsumerApikeys(opts) {
|
|
|
7037
7122
|
if (opts.json) {
|
|
7038
7123
|
console.log(JSON.stringify({ keys, revealed: revealMap }, null, 2));
|
|
7039
7124
|
} else if (!keys.length) {
|
|
7040
|
-
console.log(
|
|
7125
|
+
console.log(import_chalk41.default.yellow("No API keys yet."));
|
|
7041
7126
|
} else {
|
|
7042
7127
|
for (const k of keys) {
|
|
7043
7128
|
const clear = revealMap[k.environment]?.key;
|
|
7044
|
-
const shown = clear ?
|
|
7045
|
-
const exp = k.expires_at ?
|
|
7046
|
-
console.log(` ${
|
|
7129
|
+
const shown = clear ? import_chalk41.default.green(clear) : import_chalk41.default.dim(`${k.key_prefix ?? ""}\u2026${k.key_suffix ?? ""}`);
|
|
7130
|
+
const exp = k.expires_at ? import_chalk41.default.dim(`exp ${k.expires_at}`) : import_chalk41.default.dim("no expiry");
|
|
7131
|
+
console.log(` ${import_chalk41.default.bold(k.environment ?? "")} ${shown} ${exp} ${import_chalk41.default.dim(k.description ?? "")}`);
|
|
7047
7132
|
}
|
|
7048
7133
|
if (Object.keys(revealMap).length === 0 && keys.some((k) => !k.expires_at)) {
|
|
7049
|
-
console.log(
|
|
7134
|
+
console.log(import_chalk41.default.dim("\n(Only expiring keys can be shown in clear; non-expiring keys show a prefix only.)"));
|
|
7050
7135
|
}
|
|
7051
7136
|
}
|
|
7052
7137
|
if (opts.json) return;
|
|
@@ -7068,12 +7153,12 @@ async function runConsumerApikeys(opts) {
|
|
|
7068
7153
|
}
|
|
7069
7154
|
s2.succeed("Key created.");
|
|
7070
7155
|
const key = created.data?.key ?? created.data?.fullKey;
|
|
7071
|
-
if (key) console.log(` ${
|
|
7072
|
-
else console.log(
|
|
7156
|
+
if (key) console.log(` ${import_chalk41.default.green(key)} ${import_chalk41.default.dim("(shown once \u2014 store it now)")}`);
|
|
7157
|
+
else console.log(import_chalk41.default.dim(" Key created; run `apiblaze consumer apikeys` to reveal it if it expires."));
|
|
7073
7158
|
}
|
|
7074
7159
|
|
|
7075
7160
|
// src/commands/sidecar.ts
|
|
7076
|
-
var
|
|
7161
|
+
var import_chalk42 = __toESM(require("chalk"));
|
|
7077
7162
|
var import_ora23 = __toESM(require("ora"));
|
|
7078
7163
|
var fs10 = __toESM(require("fs"));
|
|
7079
7164
|
var path7 = __toESM(require("path"));
|
|
@@ -7116,7 +7201,7 @@ function upsertEnvLocal(root, token) {
|
|
|
7116
7201
|
}
|
|
7117
7202
|
function installSidecarPackage(root) {
|
|
7118
7203
|
if (fs10.existsSync(path7.join(root, "node_modules", "apiblaze", "package.json"))) {
|
|
7119
|
-
console.log(` ${
|
|
7204
|
+
console.log(` ${import_chalk42.default.green("\u2713")} apiblaze package already installed`);
|
|
7120
7205
|
return;
|
|
7121
7206
|
}
|
|
7122
7207
|
const has = (f) => fs10.existsSync(path7.join(root, f));
|
|
@@ -7127,7 +7212,7 @@ function installSidecarPackage(root) {
|
|
|
7127
7212
|
execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
|
|
7128
7213
|
spinner.succeed("Installed apiblaze (the sidecar runtime).");
|
|
7129
7214
|
} catch {
|
|
7130
|
-
spinner.warn(`Couldn't auto-install \u2014 run ${
|
|
7215
|
+
spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk42.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk42.default.cyan("npm run dev")}.`);
|
|
7131
7216
|
}
|
|
7132
7217
|
}
|
|
7133
7218
|
function readEnvKey(root) {
|
|
@@ -7278,29 +7363,29 @@ async function runAnonymousInit(root, router, opts) {
|
|
|
7278
7363
|
if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
|
|
7279
7364
|
const envState = upsertEnvLocal(root, out.token);
|
|
7280
7365
|
ensureGitignored(root);
|
|
7281
|
-
console.log(` ${
|
|
7282
|
-
console.log(` ${
|
|
7366
|
+
console.log(` ${import_chalk42.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
|
|
7367
|
+
console.log(` ${import_chalk42.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
|
|
7283
7368
|
installSidecarPackage(root);
|
|
7284
7369
|
let inspectorPath = null;
|
|
7285
7370
|
if (!opts.noInspector) {
|
|
7286
7371
|
inspectorPath = generateInspector(root, router);
|
|
7287
|
-
if (inspectorPath) console.log(` ${
|
|
7372
|
+
if (inspectorPath) console.log(` ${import_chalk42.default.green("\u2713")} inspector at ${inspectorPath}`);
|
|
7288
7373
|
}
|
|
7289
7374
|
console.log("");
|
|
7290
|
-
console.log(
|
|
7291
|
-
console.log(` 1. ${
|
|
7375
|
+
console.log(import_chalk42.default.bold("Done (no account needed). What happens next:"));
|
|
7376
|
+
console.log(` 1. ${import_chalk42.default.cyan("npm run dev")} and use your app.`);
|
|
7292
7377
|
console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
|
|
7293
|
-
console.log(` ${
|
|
7378
|
+
console.log(` ${import_chalk42.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
|
|
7294
7379
|
console.log("");
|
|
7295
|
-
console.log(
|
|
7296
|
-
console.log(` ${
|
|
7297
|
-
console.log(
|
|
7380
|
+
console.log(import_chalk42.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
|
|
7381
|
+
console.log(` ${import_chalk42.default.cyan("apiblaze login")} then ${import_chalk42.default.cyan("apiblaze claim")} ${import_chalk42.default.dim("(no code needed here)")}`);
|
|
7382
|
+
console.log(import_chalk42.default.dim(` From another machine: apiblaze claim ${out.claim_code} \xB7 expires in 30 days`));
|
|
7298
7383
|
}
|
|
7299
7384
|
async function runSidecar(opts) {
|
|
7300
7385
|
const root = path7.resolve(opts.dir ?? process.cwd());
|
|
7301
7386
|
const detected = detectNextProject(root);
|
|
7302
7387
|
if (!detected.found) {
|
|
7303
|
-
console.log(
|
|
7388
|
+
console.log(import_chalk42.default.yellow(`No Next.js project detected in ${root}.`));
|
|
7304
7389
|
console.log("Create one (e.g. `npx create-next-app`) and re-run `apiblaze init` inside it.");
|
|
7305
7390
|
return;
|
|
7306
7391
|
}
|
|
@@ -7311,10 +7396,10 @@ async function runSidecar(opts) {
|
|
|
7311
7396
|
if (!loadCredentials()) {
|
|
7312
7397
|
upsertEnvLocal(root, readEnvKey(root));
|
|
7313
7398
|
ensureGitignored(root);
|
|
7314
|
-
console.log(` ${
|
|
7315
|
-
console.log(` ${
|
|
7399
|
+
console.log(` ${import_chalk42.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
|
|
7400
|
+
console.log(` ${import_chalk42.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
|
|
7316
7401
|
installSidecarPackage(root);
|
|
7317
|
-
console.log(
|
|
7402
|
+
console.log(import_chalk42.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
|
|
7318
7403
|
return;
|
|
7319
7404
|
}
|
|
7320
7405
|
const { teamId, teamName } = await resolveTeam(opts.team);
|
|
@@ -7337,38 +7422,38 @@ async function runSidecar(opts) {
|
|
|
7337
7422
|
throw err;
|
|
7338
7423
|
}
|
|
7339
7424
|
} else {
|
|
7340
|
-
console.log(
|
|
7425
|
+
console.log(import_chalk42.default.dim(` Reusing the existing APIBLAZE_API_KEY (run with --rotate to mint a fresh one, or --team <name> to switch teams).`));
|
|
7341
7426
|
}
|
|
7342
7427
|
const envState = upsertEnvLocal(root, token);
|
|
7343
7428
|
ensureGitignored(root);
|
|
7344
|
-
console.log(` ${
|
|
7429
|
+
console.log(` ${import_chalk42.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
|
|
7345
7430
|
const wireState = wireInstrumentation(root);
|
|
7346
|
-
console.log(` ${
|
|
7431
|
+
console.log(` ${import_chalk42.default.green("\u2713")} instrumentation.ts ${wireState}`);
|
|
7347
7432
|
installSidecarPackage(root);
|
|
7348
7433
|
let inspectorPath = null;
|
|
7349
7434
|
if (!opts.noInspector) {
|
|
7350
7435
|
inspectorPath = generateInspector(root, detected.router);
|
|
7351
|
-
if (inspectorPath) console.log(` ${
|
|
7436
|
+
if (inspectorPath) console.log(` ${import_chalk42.default.green("\u2713")} inspector at ${inspectorPath}`);
|
|
7352
7437
|
}
|
|
7353
7438
|
console.log("");
|
|
7354
|
-
console.log(
|
|
7355
|
-
console.log(` 1. ${
|
|
7356
|
-
console.log(` 2. The origins your app calls appear as ${
|
|
7357
|
-
console.log(` 3. Approve the ones to route: ${
|
|
7439
|
+
console.log(import_chalk42.default.bold("Done. What happens next:"));
|
|
7440
|
+
console.log(` 1. ${import_chalk42.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
|
|
7441
|
+
console.log(` 2. The origins your app calls appear as ${import_chalk42.default.bold("candidates")} \u2014 list them: ${import_chalk42.default.cyan("apiblaze sidecar")}`);
|
|
7442
|
+
console.log(` 3. Approve the ones to route: ${import_chalk42.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
|
|
7358
7443
|
console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
|
|
7359
|
-
if (inspectorPath) console.log(` \u2022 Try it now: open ${
|
|
7360
|
-
if (switchingTeam) console.log(
|
|
7444
|
+
if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk42.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path7.dirname(inspectorPath)} before shipping)`);
|
|
7445
|
+
if (switchingTeam) console.log(import_chalk42.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
|
|
7361
7446
|
console.log("");
|
|
7362
|
-
console.log(
|
|
7363
|
-
console.log(
|
|
7364
|
-
console.log(
|
|
7447
|
+
console.log(import_chalk42.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
|
|
7448
|
+
console.log(import_chalk42.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
|
|
7449
|
+
console.log(import_chalk42.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
|
|
7365
7450
|
console.log("");
|
|
7366
|
-
console.log(
|
|
7367
|
-
console.log(
|
|
7451
|
+
console.log(import_chalk42.default.yellow(" \u26A0 APIBLAZE_API_KEY is long-lived and lets a holder call your team's proxies. Never commit it."));
|
|
7452
|
+
console.log(import_chalk42.default.dim(" Your control-plane login stays in ~/.apiblaze \u2014 it never entered this project."));
|
|
7368
7453
|
}
|
|
7369
7454
|
|
|
7370
7455
|
// src/commands/origins.ts
|
|
7371
|
-
var
|
|
7456
|
+
var import_chalk43 = __toESM(require("chalk"));
|
|
7372
7457
|
var import_ora24 = __toESM(require("ora"));
|
|
7373
7458
|
init_admin();
|
|
7374
7459
|
init_resolve();
|
|
@@ -7379,7 +7464,7 @@ async function runOriginsList(opts) {
|
|
|
7379
7464
|
if (!loadCredentials()) {
|
|
7380
7465
|
const cred = loadAnonCred();
|
|
7381
7466
|
if (!cred) {
|
|
7382
|
-
console.log(
|
|
7467
|
+
console.log(import_chalk43.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
|
|
7383
7468
|
return;
|
|
7384
7469
|
}
|
|
7385
7470
|
out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
|
|
@@ -7397,27 +7482,27 @@ async function runOriginsList(opts) {
|
|
|
7397
7482
|
}
|
|
7398
7483
|
const routed = out.routed ?? [];
|
|
7399
7484
|
const candidates = out.candidates ?? [];
|
|
7400
|
-
console.log(
|
|
7485
|
+
console.log(import_chalk43.default.bold(`
|
|
7401
7486
|
Routed through APIblaze (${routed.length})`));
|
|
7402
|
-
if (!routed.length) console.log(
|
|
7403
|
-
for (const r of routed) console.log(` ${
|
|
7404
|
-
console.log(
|
|
7487
|
+
if (!routed.length) console.log(import_chalk43.default.dim(" none yet"));
|
|
7488
|
+
for (const r of routed) console.log(` ${import_chalk43.default.green("\u25CF")} ${r.sidecar_origin} ${import_chalk43.default.dim(`\u2192 ${r.project_id}`)}`);
|
|
7489
|
+
console.log(import_chalk43.default.bold(`
|
|
7405
7490
|
Candidates \u2014 going direct, not yet approved (${candidates.length})`));
|
|
7406
|
-
if (!candidates.length) console.log(
|
|
7491
|
+
if (!candidates.length) console.log(import_chalk43.default.dim(" none \u2014 run your app to discover the origins it calls"));
|
|
7407
7492
|
for (const c of candidates) {
|
|
7408
|
-
console.log(` ${
|
|
7493
|
+
console.log(` ${import_chalk43.default.yellow("\u25CB")} ${c.origin} ${import_chalk43.default.dim(`seen ${c.request_count}\xD7, last ${c.last_seen}`)}`);
|
|
7409
7494
|
}
|
|
7410
7495
|
if (candidates.length) {
|
|
7411
|
-
console.log(
|
|
7496
|
+
console.log(import_chalk43.default.dim(`
|
|
7412
7497
|
Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
|
|
7413
|
-
console.log(
|
|
7498
|
+
console.log(import_chalk43.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
|
|
7414
7499
|
}
|
|
7415
7500
|
}
|
|
7416
7501
|
async function runOriginsApprove(origin, opts) {
|
|
7417
7502
|
if (!loadCredentials()) {
|
|
7418
7503
|
const cred = loadAnonCred();
|
|
7419
7504
|
if (!cred) {
|
|
7420
|
-
console.error(
|
|
7505
|
+
console.error(import_chalk43.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
|
|
7421
7506
|
process.exit(1);
|
|
7422
7507
|
}
|
|
7423
7508
|
const spinner2 = (0, import_ora24.default)(`Approving ${origin} (anonymous)...`).start();
|
|
@@ -7470,7 +7555,7 @@ async function runOriginsRemove(origin, opts) {
|
|
|
7470
7555
|
}
|
|
7471
7556
|
|
|
7472
7557
|
// src/commands/op.ts
|
|
7473
|
-
var
|
|
7558
|
+
var import_chalk44 = __toESM(require("chalk"));
|
|
7474
7559
|
init_auth();
|
|
7475
7560
|
init_trace();
|
|
7476
7561
|
init_types();
|
|
@@ -7503,82 +7588,82 @@ function printResidue(report, applied) {
|
|
|
7503
7588
|
const up = report?.upstash ?? {};
|
|
7504
7589
|
const fga = report?.fga ?? {};
|
|
7505
7590
|
const ghosts = report?.ghosts ?? {};
|
|
7506
|
-
console.log(
|
|
7507
|
-
console.log(
|
|
7591
|
+
console.log(import_chalk44.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
|
|
7592
|
+
console.log(import_chalk44.default.bold("\n Upstash"));
|
|
7508
7593
|
const orphans = up.orphans ?? [];
|
|
7509
|
-
if (orphans.length === 0) console.log(
|
|
7510
|
-
for (const o of orphans) console.log(` ${
|
|
7511
|
-
console.log(
|
|
7594
|
+
if (orphans.length === 0) console.log(import_chalk44.default.green(" no orphaned keys"));
|
|
7595
|
+
for (const o of orphans) console.log(` ${import_chalk44.default.yellow(o.key)} ${import_chalk44.default.dim(`\u2014 ${o.reason}`)}`);
|
|
7596
|
+
console.log(import_chalk44.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
|
|
7512
7597
|
if (up.anon_wallet_detail) {
|
|
7513
7598
|
const d = up.anon_wallet_detail;
|
|
7514
|
-
console.log(
|
|
7599
|
+
console.log(import_chalk44.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)"}`));
|
|
7515
7600
|
}
|
|
7516
7601
|
if (up.keyspace_census) {
|
|
7517
7602
|
const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
|
|
7518
|
-
console.log(
|
|
7603
|
+
console.log(import_chalk44.default.dim(` keyspace: ${census}`));
|
|
7519
7604
|
}
|
|
7520
|
-
if (up.unknown?.length) console.log(
|
|
7521
|
-
if (applied) console.log(` ${
|
|
7522
|
-
for (const e of up.errors ?? []) console.log(
|
|
7523
|
-
console.log(
|
|
7605
|
+
if (up.unknown?.length) console.log(import_chalk44.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
|
|
7606
|
+
if (applied) console.log(` ${import_chalk44.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
|
|
7607
|
+
for (const e of up.errors ?? []) console.log(import_chalk44.default.red(` error: ${e}`));
|
|
7608
|
+
console.log(import_chalk44.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
|
|
7524
7609
|
if (applied) {
|
|
7525
7610
|
const swept = fga?.swept ?? [];
|
|
7526
|
-
if (swept.length === 0) console.log(
|
|
7611
|
+
if (swept.length === 0) console.log(import_chalk44.default.green(" no orphaned stores"));
|
|
7527
7612
|
for (const s of swept) {
|
|
7528
7613
|
console.log(
|
|
7529
|
-
` ${
|
|
7614
|
+
` ${import_chalk44.default.yellow(s.store_id)} ${import_chalk44.default.dim(`\u2014 store ${s.openfga_deleted ? "deleted" : "DEFERRED"}, ${s.neon_deleted} Neon tuple(s) purged`)}`
|
|
7530
7615
|
);
|
|
7531
7616
|
}
|
|
7532
|
-
if (fga?.remaining) console.log(
|
|
7617
|
+
if (fga?.remaining) console.log(import_chalk44.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
|
|
7533
7618
|
const st = fga?.side_tables;
|
|
7534
|
-
if (st) console.log(
|
|
7619
|
+
if (st) console.log(import_chalk44.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})` : ""}`));
|
|
7535
7620
|
} else {
|
|
7536
7621
|
const fgaOrphans = fga?.orphans ?? [];
|
|
7537
|
-
if (fgaOrphans.length === 0) console.log(
|
|
7622
|
+
if (fgaOrphans.length === 0) console.log(import_chalk44.default.green(" no orphaned stores"));
|
|
7538
7623
|
for (const s of fgaOrphans) {
|
|
7539
7624
|
const src = s.in_openfga ? "live in OpenFGA" : "Neon tuples only";
|
|
7540
|
-
console.log(` ${
|
|
7625
|
+
console.log(` ${import_chalk44.default.yellow(s.store_id)} ${import_chalk44.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
|
|
7541
7626
|
}
|
|
7542
|
-
console.log(
|
|
7627
|
+
console.log(import_chalk44.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
|
|
7543
7628
|
const st = fga?.side_tables;
|
|
7544
|
-
if (st) console.log(
|
|
7629
|
+
if (st) console.log(import_chalk44.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`));
|
|
7545
7630
|
}
|
|
7546
|
-
for (const e of fga?.errors ?? []) console.log(
|
|
7547
|
-
console.log(
|
|
7631
|
+
for (const e of fga?.errors ?? []) console.log(import_chalk44.default.red(` error: ${e}`));
|
|
7632
|
+
console.log(import_chalk44.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
|
|
7548
7633
|
if (applied) {
|
|
7549
|
-
if ((ghosts?.ghost_count ?? 0) === 0) console.log(
|
|
7550
|
-
else console.log(` ${
|
|
7634
|
+
if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk44.default.green(" no ghost tuples"));
|
|
7635
|
+
else console.log(` ${import_chalk44.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk44.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
|
|
7551
7636
|
} else {
|
|
7552
7637
|
const n = ghosts?.ghost_count ?? 0;
|
|
7553
|
-
if (n === 0) console.log(
|
|
7638
|
+
if (n === 0) console.log(import_chalk44.default.green(` no ghost tuples ${import_chalk44.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
|
|
7554
7639
|
else {
|
|
7555
|
-
console.log(
|
|
7640
|
+
console.log(import_chalk44.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
|
|
7556
7641
|
for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
|
|
7557
|
-
console.log(
|
|
7642
|
+
console.log(import_chalk44.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
|
|
7558
7643
|
}
|
|
7559
|
-
if (n > 20) console.log(
|
|
7644
|
+
if (n > 20) console.log(import_chalk44.default.dim(` \u2026 and ${n - 20} more`));
|
|
7560
7645
|
}
|
|
7561
7646
|
}
|
|
7562
|
-
for (const e of ghosts?.errors ?? []) console.log(
|
|
7647
|
+
for (const e of ghosts?.errors ?? []) console.log(import_chalk44.default.red(` error: ${e}`));
|
|
7563
7648
|
console.log();
|
|
7564
7649
|
}
|
|
7565
7650
|
async function runOp(sub, opts = {}) {
|
|
7566
7651
|
if (!loadCredentials()) {
|
|
7567
|
-
console.log(
|
|
7652
|
+
console.log(import_chalk44.default.dim("Not logged in. Run `apiblaze login`."));
|
|
7568
7653
|
return;
|
|
7569
7654
|
}
|
|
7570
7655
|
if (!isOperatorLogin()) {
|
|
7571
|
-
console.log(
|
|
7656
|
+
console.log(import_chalk44.default.dim("`apiblaze op` is only available to platform operators."));
|
|
7572
7657
|
return;
|
|
7573
7658
|
}
|
|
7574
7659
|
switch (sub) {
|
|
7575
7660
|
case void 0:
|
|
7576
7661
|
case "menu": {
|
|
7577
|
-
console.log(
|
|
7578
|
-
console.log(` ${
|
|
7579
|
-
console.log(` ${
|
|
7580
|
-
console.log(` ${
|
|
7581
|
-
console.log(
|
|
7662
|
+
console.log(import_chalk44.default.bold("\nOperator menu"));
|
|
7663
|
+
console.log(` ${import_chalk44.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
|
|
7664
|
+
console.log(` ${import_chalk44.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk44.default.dim("-y to skip")})`);
|
|
7665
|
+
console.log(` ${import_chalk44.default.cyan("apiblaze op credits")} list credit wallets`);
|
|
7666
|
+
console.log(import_chalk44.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
|
|
7582
7667
|
`));
|
|
7583
7668
|
return;
|
|
7584
7669
|
}
|
|
@@ -7597,17 +7682,17 @@ async function runOp(sub, opts = {}) {
|
|
|
7597
7682
|
const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
|
|
7598
7683
|
printResidue(report, false);
|
|
7599
7684
|
if (nUp + nFga + nGhost + nSide === 0) {
|
|
7600
|
-
console.log(
|
|
7685
|
+
console.log(import_chalk44.default.green("Nothing to sweep."));
|
|
7601
7686
|
return;
|
|
7602
7687
|
}
|
|
7603
7688
|
if (!opts.yes) {
|
|
7604
7689
|
const readline2 = await import("readline/promises");
|
|
7605
7690
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
7606
7691
|
const answer = await rl.question(
|
|
7607
|
-
|
|
7692
|
+
import_chalk44.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: `)
|
|
7608
7693
|
);
|
|
7609
7694
|
rl.close();
|
|
7610
|
-
if (answer.trim() !== "sweep") return void console.log(
|
|
7695
|
+
if (answer.trim() !== "sweep") return void console.log(import_chalk44.default.dim("Aborted."));
|
|
7611
7696
|
}
|
|
7612
7697
|
const result = await opCall({ method: "POST", path: "/operator/external-residue/sweep", summary: "external residue sweep" });
|
|
7613
7698
|
if (opts.json) return void console.log(JSON.stringify(result, null, 2));
|
|
@@ -7618,15 +7703,15 @@ async function runOp(sub, opts = {}) {
|
|
|
7618
7703
|
const data = await opCall({ method: "GET", path: "/operator/credits", summary: "list credit wallets" });
|
|
7619
7704
|
if (opts.json) return void console.log(JSON.stringify(data, null, 2));
|
|
7620
7705
|
const accounts = data?.accounts ?? [];
|
|
7621
|
-
if (accounts.length === 0) return void console.log(
|
|
7706
|
+
if (accounts.length === 0) return void console.log(import_chalk44.default.dim("No credit wallets."));
|
|
7622
7707
|
for (const a of accounts) {
|
|
7623
7708
|
const bal = typeof a.balance_cents === "number" ? `$${(a.balance_cents / 100).toFixed(2)}` : "?";
|
|
7624
|
-
console.log(` ${
|
|
7709
|
+
console.log(` ${import_chalk44.default.bold(bal.padStart(9))} ${a.walletId}${a.owner_email ? import_chalk44.default.dim(` \u2014 ${a.owner_email}`) : a.anon ? import_chalk44.default.dim(" \u2014 anon") : ""}`);
|
|
7625
7710
|
}
|
|
7626
7711
|
return;
|
|
7627
7712
|
}
|
|
7628
7713
|
default:
|
|
7629
|
-
console.log(
|
|
7714
|
+
console.log(import_chalk44.default.red(`Unknown op subcommand '${sub}'. Run \`apiblaze op\` for the menu.`));
|
|
7630
7715
|
}
|
|
7631
7716
|
}
|
|
7632
7717
|
|
|
@@ -7672,7 +7757,7 @@ agent.command("authz").description("Chat to design and turn on access rules for
|
|
|
7672
7757
|
program.command("rule").description("Author an object-level access rule in plain English, in one shot (billed per turn)").argument("<rule>", 'The rule in plain English, e.g. "users see only their own rows"').argument("<project>", "Project name or id").option("--enforce", "Turn enforcement on immediately (default: shadow-publish only)").option("--apiversion <version>", "API version (defaults to the project's)").action(action((rule, project, opts) => runRule(rule, project, opts)));
|
|
7673
7758
|
agent.command("openapi").description("Chat to build your API spec from real traffic").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").action(action((project, apiVersion) => runOpenapi(project, apiVersion)));
|
|
7674
7759
|
agent.command("mcp").description("Chat to build an MCP server for an API").argument("<project>", "Project name or id").argument("[apiVersion]", "API version (defaults to the project's)").option("--environment <env>", "Environment to publish (default: prod)").action(action((project, apiVersion, opts) => runMcp(project, apiVersion, opts)));
|
|
7675
|
-
program.command("apichat").description("Turn any API into a chat: point at an OpenAPI spec and start asking questions (no login needed)").option("--openapi <file|url>", "OpenAPI/Swagger spec to build from (JSON or YAML; file path or URL)").option("--openapispec <file|url>", "Alias for --openapi").option("--target <url>", "Upstream base URL (overrides servers[0].url; enables spec discovery when --openapi is omitted)").option("--name <name>", "Proxy name (defaults to the target host)").option("--apiversion <version>", "API version to create (e.g. 1.0.0)").option("--environment <env>", "Environment to chat against (default: prod anonymous / dev logged-in)").option("--access <mode>", 'Who can call this API once connected (e.g. via Claude): "open" = anyone who signs in, "invite" = only you + emails you pre-approve. Default: invite when logged in, open when anonymous.').option("--target-auth-env <ENV_VAR>", "Read the upstream credential from this env var (CI-safe; required when there is no TTY and the API needs auth)").option("--force", "Proceed even if the API uses oauth2/openIdConnect target auth (you configure target auth yourself later)").option("-y, --yes", "Skip confirmation prompts").option("--no-verbose", "Hide the per-turn proxy curl trace (shown by default for apichat)").action(action((opts) => runApichat({ ...opts, openapispec: opts.openapispec ?? opts.openapi })));
|
|
7760
|
+
program.command("apichat").description("Turn any API into a chat: point at an OpenAPI spec and start asking questions (no login needed)").option("--openapi <file|url>", "OpenAPI/Swagger spec to build from (JSON or YAML; file path or URL)").option("--openapispec <file|url>", "Alias for --openapi").option("--target <url>", "Upstream base URL (overrides servers[0].url; enables spec discovery when --openapi is omitted)").option("--name <name>", "Proxy name (defaults to the target host)").option("--apiversion <version>", "API version to create (e.g. 1.0.0)").option("--environment <env>", "Environment to chat against (default: prod anonymous / dev logged-in)").option("--access <mode>", 'Who can call this API once connected (e.g. via Claude): "open" = anyone who signs in, "invite" = only you + emails you pre-approve. Default: invite when logged in, open when anonymous.').option("--target-auth-env <ENV_VAR>", "Read the upstream credential from this env var (CI-safe; required when there is no TTY and the API needs auth)").option("--force", "Proceed even if the API uses oauth2/openIdConnect target auth (you configure target auth yourself later)").option("-y, --yes", "Skip confirmation prompts").option("--tenant <slug>", "Tenant (consumer namespace: portal, login, users) for the new proxy; omit to be asked").option("--no-verbose", "Hide the per-turn proxy curl trace (shown by default for apichat)").action(action((opts) => runApichat({ ...opts, openapispec: opts.openapispec ?? opts.openapi })));
|
|
7676
7761
|
var llm = program.command("llm").description("Manage a local LLM provider key for chat (optional \u2014 lifts model quality, bills your key)");
|
|
7677
7762
|
llm.command("set-key").description("Store an LLM provider key locally (OpenRouter/Anthropic/DeepSeek/OpenAI)").argument("[key]", "The API key (omit to enter it hidden at a prompt)").option("--model <id>", "Model id to use with this key (e.g. anthropic/claude-haiku-4.5)").action(action((key, opts) => runLlmSetKey(key, opts)));
|
|
7678
7763
|
llm.command("show").description("Show the locally stored LLM key (masked)").action(action(() => runLlmShow()));
|
|
@@ -7689,7 +7774,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
|
|
|
7689
7774
|
try {
|
|
7690
7775
|
const resolved = parseInt(port ?? opts.port, 10);
|
|
7691
7776
|
if (Number.isNaN(resolved)) {
|
|
7692
|
-
console.error(
|
|
7777
|
+
console.error(import_chalk45.default.red(`Invalid port: ${port ?? opts.port}`));
|
|
7693
7778
|
process.exit(1);
|
|
7694
7779
|
}
|
|
7695
7780
|
await runDev({ port: resolved, project: opts.project, yes: opts.yes, captureFile: opts.captureFile, newSession: opts.newSession });
|
|
@@ -7808,7 +7893,7 @@ function groupedCommandHelp() {
|
|
|
7808
7893
|
const sub = byName.get(e.parent)?.commands.find((s) => s.name() === e.sub);
|
|
7809
7894
|
return sub ? ` ${helpLabel(e).padEnd(width)}${sub.description()}` : "";
|
|
7810
7895
|
}).filter(Boolean).join("\n");
|
|
7811
|
-
return `${
|
|
7896
|
+
return `${import_chalk45.default.bold(g.title)}
|
|
7812
7897
|
${rows}`;
|
|
7813
7898
|
}).join("\n\n");
|
|
7814
7899
|
}
|
|
@@ -7843,14 +7928,14 @@ async function recoverStaleTeam() {
|
|
|
7843
7928
|
const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
|
|
7844
7929
|
const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
|
|
7845
7930
|
if (!linked) {
|
|
7846
|
-
console.error(
|
|
7931
|
+
console.error(import_chalk45.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
|
|
7847
7932
|
return;
|
|
7848
7933
|
}
|
|
7849
7934
|
if (linked.teamId === creds.teamId) return;
|
|
7850
7935
|
const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
|
|
7851
7936
|
delete next.activeTenant;
|
|
7852
7937
|
saveCredentials(next);
|
|
7853
|
-
console.error(
|
|
7938
|
+
console.error(import_chalk45.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk45.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
|
|
7854
7939
|
} catch {
|
|
7855
7940
|
}
|
|
7856
7941
|
}
|
|
@@ -7858,16 +7943,16 @@ async function printError(err) {
|
|
|
7858
7943
|
if (err instanceof ApiError) {
|
|
7859
7944
|
const data = err.body;
|
|
7860
7945
|
const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
|
|
7861
|
-
console.error(
|
|
7946
|
+
console.error(import_chalk45.default.red(`
|
|
7862
7947
|
API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
|
|
7863
7948
|
if (err.status === 403 || err.status === 404) {
|
|
7864
7949
|
await recoverStaleTeam();
|
|
7865
7950
|
}
|
|
7866
7951
|
} else if (err instanceof Error) {
|
|
7867
|
-
console.error(
|
|
7952
|
+
console.error(import_chalk45.default.red(`
|
|
7868
7953
|
Error: ${err.message}`));
|
|
7869
7954
|
} else {
|
|
7870
|
-
console.error(
|
|
7955
|
+
console.error(import_chalk45.default.red("\nUnknown error"));
|
|
7871
7956
|
}
|
|
7872
7957
|
}
|
|
7873
7958
|
program.parse(process.argv);
|