apiblaze 0.12.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +168 -57
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -51,6 +51,14 @@ var init_types = __esm({
|
|
|
51
51
|
});
|
|
52
52
|
|
|
53
53
|
// src/lib/auth.ts
|
|
54
|
+
var auth_exports = {};
|
|
55
|
+
__export(auth_exports, {
|
|
56
|
+
clearCredentials: () => clearCredentials,
|
|
57
|
+
getAccessToken: () => getAccessToken,
|
|
58
|
+
getApiblazeDir: () => getApiblazeDir,
|
|
59
|
+
loadCredentials: () => loadCredentials,
|
|
60
|
+
saveCredentials: () => saveCredentials
|
|
61
|
+
});
|
|
54
62
|
function saveCredentials(creds) {
|
|
55
63
|
fs.mkdirSync(APIBLAZE_DIR, { recursive: true });
|
|
56
64
|
fs.writeFileSync(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), "utf-8");
|
|
@@ -82,6 +90,9 @@ function getAccessToken() {
|
|
|
82
90
|
}
|
|
83
91
|
return creds.accessToken;
|
|
84
92
|
}
|
|
93
|
+
function getApiblazeDir() {
|
|
94
|
+
return APIBLAZE_DIR;
|
|
95
|
+
}
|
|
85
96
|
var fs, os, path, APIBLAZE_DIR, CREDENTIALS_PATH;
|
|
86
97
|
var init_auth = __esm({
|
|
87
98
|
"src/lib/auth.ts"() {
|
|
@@ -232,6 +243,65 @@ var init_api = __esm({
|
|
|
232
243
|
}
|
|
233
244
|
});
|
|
234
245
|
|
|
246
|
+
// src/lib/team.ts
|
|
247
|
+
var team_exports = {};
|
|
248
|
+
__export(team_exports, {
|
|
249
|
+
resolveLinkedTeam: () => resolveLinkedTeam
|
|
250
|
+
});
|
|
251
|
+
async function resolveLinkedTeam(opts) {
|
|
252
|
+
let teams;
|
|
253
|
+
try {
|
|
254
|
+
teams = await getTeams();
|
|
255
|
+
} catch {
|
|
256
|
+
return opts.preferredId ? { teamId: opts.preferredId } : null;
|
|
257
|
+
}
|
|
258
|
+
if (teams.length === 0) return null;
|
|
259
|
+
const preferred = opts.preferredId ? teams.find((t) => t.teamId === opts.preferredId) : void 0;
|
|
260
|
+
if (preferred && !(opts.promptWhenMultiple && opts.interactive && teams.length > 1)) {
|
|
261
|
+
return { teamId: preferred.teamId, teamName: preferred.name };
|
|
262
|
+
}
|
|
263
|
+
if (preferred) {
|
|
264
|
+
const { default: inquirer3 } = await import("inquirer");
|
|
265
|
+
const { chosen: chosen2 } = await inquirer3.prompt([{
|
|
266
|
+
type: "list",
|
|
267
|
+
name: "chosen",
|
|
268
|
+
message: "Which team do you want to work in?",
|
|
269
|
+
default: preferred.teamId,
|
|
270
|
+
choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
|
|
271
|
+
}]);
|
|
272
|
+
const picked2 = teams.find((t) => t.teamId === chosen2);
|
|
273
|
+
return { teamId: picked2.teamId, teamName: picked2.name };
|
|
274
|
+
}
|
|
275
|
+
if (opts.preferredId) {
|
|
276
|
+
console.log(import_chalk.default.yellow("\nYour previously linked team is no longer available."));
|
|
277
|
+
}
|
|
278
|
+
if (teams.length === 1) {
|
|
279
|
+
console.log(`${import_chalk.default.cyan("\u2192")} Linking to your team ${import_chalk.default.bold(teams[0].name)}.`);
|
|
280
|
+
return { teamId: teams[0].teamId, teamName: teams[0].name };
|
|
281
|
+
}
|
|
282
|
+
if (!opts.interactive) {
|
|
283
|
+
console.log(import_chalk.default.yellow(`Linking to "${teams[0].name}" \u2014 pass --team to choose another.`));
|
|
284
|
+
return { teamId: teams[0].teamId, teamName: teams[0].name };
|
|
285
|
+
}
|
|
286
|
+
const { default: inquirer2 } = await import("inquirer");
|
|
287
|
+
const { chosen } = await inquirer2.prompt([{
|
|
288
|
+
type: "list",
|
|
289
|
+
name: "chosen",
|
|
290
|
+
message: "Which team do you want to link to?",
|
|
291
|
+
choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
|
|
292
|
+
}]);
|
|
293
|
+
const picked = teams.find((t) => t.teamId === chosen);
|
|
294
|
+
return { teamId: picked.teamId, teamName: picked.name };
|
|
295
|
+
}
|
|
296
|
+
var import_chalk;
|
|
297
|
+
var init_team = __esm({
|
|
298
|
+
"src/lib/team.ts"() {
|
|
299
|
+
"use strict";
|
|
300
|
+
import_chalk = __toESM(require("chalk"));
|
|
301
|
+
init_api();
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
235
305
|
// src/lib/anon-cred.ts
|
|
236
306
|
var anon_cred_exports = {};
|
|
237
307
|
__export(anon_cred_exports, {
|
|
@@ -492,7 +562,7 @@ var import_commander = require("commander");
|
|
|
492
562
|
var import_chalk34 = __toESM(require("chalk"));
|
|
493
563
|
|
|
494
564
|
// package.json
|
|
495
|
-
var version = "0.
|
|
565
|
+
var version = "0.14.0";
|
|
496
566
|
|
|
497
567
|
// src/index.ts
|
|
498
568
|
init_types();
|
|
@@ -501,43 +571,7 @@ init_types();
|
|
|
501
571
|
var import_chalk2 = __toESM(require("chalk"));
|
|
502
572
|
var import_ora = __toESM(require("ora"));
|
|
503
573
|
init_auth();
|
|
504
|
-
|
|
505
|
-
// src/lib/team.ts
|
|
506
|
-
var import_chalk = __toESM(require("chalk"));
|
|
507
|
-
init_api();
|
|
508
|
-
async function resolveLinkedTeam(opts) {
|
|
509
|
-
let teams;
|
|
510
|
-
try {
|
|
511
|
-
teams = await getTeams();
|
|
512
|
-
} catch {
|
|
513
|
-
return opts.preferredId ? { teamId: opts.preferredId } : null;
|
|
514
|
-
}
|
|
515
|
-
if (teams.length === 0) return null;
|
|
516
|
-
const preferred = opts.preferredId ? teams.find((t) => t.teamId === opts.preferredId) : void 0;
|
|
517
|
-
if (preferred) return { teamId: preferred.teamId, teamName: preferred.name };
|
|
518
|
-
if (opts.preferredId) {
|
|
519
|
-
console.log(import_chalk.default.yellow("\nYour previously linked team is no longer available."));
|
|
520
|
-
}
|
|
521
|
-
if (teams.length === 1) {
|
|
522
|
-
console.log(`${import_chalk.default.cyan("\u2192")} Linking to your team ${import_chalk.default.bold(teams[0].name)}.`);
|
|
523
|
-
return { teamId: teams[0].teamId, teamName: teams[0].name };
|
|
524
|
-
}
|
|
525
|
-
if (!opts.interactive) {
|
|
526
|
-
console.log(import_chalk.default.yellow(`Linking to "${teams[0].name}" \u2014 pass --team to choose another.`));
|
|
527
|
-
return { teamId: teams[0].teamId, teamName: teams[0].name };
|
|
528
|
-
}
|
|
529
|
-
const { default: inquirer2 } = await import("inquirer");
|
|
530
|
-
const { chosen } = await inquirer2.prompt([{
|
|
531
|
-
type: "list",
|
|
532
|
-
name: "chosen",
|
|
533
|
-
message: "Which team do you want to link to?",
|
|
534
|
-
choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
|
|
535
|
-
}]);
|
|
536
|
-
const picked = teams.find((t) => t.teamId === chosen);
|
|
537
|
-
return { teamId: picked.teamId, teamName: picked.name };
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
// src/commands/login.ts
|
|
574
|
+
init_team();
|
|
541
575
|
var DASHBOARD_BASE2 = "https://dashboard.apiblaze.com";
|
|
542
576
|
function openBrowser(url) {
|
|
543
577
|
const { exec } = require("child_process");
|
|
@@ -613,7 +647,12 @@ async function runLogin() {
|
|
|
613
647
|
}
|
|
614
648
|
let teamId = defaultTeamId ?? void 0;
|
|
615
649
|
let teamName;
|
|
616
|
-
const linked = await resolveLinkedTeam({
|
|
650
|
+
const linked = await resolveLinkedTeam({
|
|
651
|
+
preferredId: defaultTeamId ?? void 0,
|
|
652
|
+
interactive: !!process.stdin.isTTY,
|
|
653
|
+
// >1 team → ASK (JWT default is just the cursor). One team → link silently.
|
|
654
|
+
promptWhenMultiple: true
|
|
655
|
+
});
|
|
617
656
|
if (linked) {
|
|
618
657
|
teamId = linked.teamId;
|
|
619
658
|
teamName = linked.teamName;
|
|
@@ -838,6 +877,9 @@ function formatCapturedRequest(req, note) {
|
|
|
838
877
|
].join("\n");
|
|
839
878
|
}
|
|
840
879
|
|
|
880
|
+
// src/commands/dev.ts
|
|
881
|
+
init_team();
|
|
882
|
+
|
|
841
883
|
// src/lib/random-name.ts
|
|
842
884
|
var ADJECTIVES = [
|
|
843
885
|
"amber",
|
|
@@ -2858,13 +2900,28 @@ var trailingComma = /\s*,\s*/;
|
|
|
2858
2900
|
var parseList = (s) => s.split(trailingComma).map((x) => x.trim()).filter(Boolean);
|
|
2859
2901
|
async function runTenantManage(query, opts) {
|
|
2860
2902
|
const { teamId } = await resolveTeam(opts.team);
|
|
2861
|
-
const slug = opts.tenant ??
|
|
2903
|
+
const slug = opts.tenant ?? await validScopedTenant(teamId, query) ?? await pickTenant(teamId, { message: "Manage which tenant?", initialQuery: query, allowCreate: true });
|
|
2862
2904
|
if (!slug) return;
|
|
2863
2905
|
await tenantHome(teamId, slug);
|
|
2864
2906
|
}
|
|
2865
|
-
function
|
|
2907
|
+
async function validScopedTenant(teamId, query) {
|
|
2866
2908
|
if (query) return void 0;
|
|
2867
|
-
|
|
2909
|
+
const creds = loadCredentials();
|
|
2910
|
+
const scoped = creds?.activeTenant;
|
|
2911
|
+
if (!scoped) return void 0;
|
|
2912
|
+
const out = await admin({
|
|
2913
|
+
method: "GET",
|
|
2914
|
+
path: `/teams/${encodeURIComponent(teamId)}/tenants?q=${encodeURIComponent(scoped)}&limit=15`,
|
|
2915
|
+
summary: `Verify tenant scope ${scoped}`
|
|
2916
|
+
}).catch(() => null);
|
|
2917
|
+
const names = (out?.tenants ?? []).map((t) => typeof t === "string" ? t : t.tenant_name);
|
|
2918
|
+
if (names.includes(scoped)) return scoped;
|
|
2919
|
+
const { saveCredentials: saveCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
2920
|
+
const next = { ...creds };
|
|
2921
|
+
delete next.activeTenant;
|
|
2922
|
+
saveCredentials2(next);
|
|
2923
|
+
console.log(import_chalk24.default.yellow(`Tenant scope "${scoped}" no longer exists in this team \u2014 cleared.`));
|
|
2924
|
+
return void 0;
|
|
2868
2925
|
}
|
|
2869
2926
|
async function tenantHome(teamId, tenant2) {
|
|
2870
2927
|
const { default: inquirer2 } = await import("inquirer");
|
|
@@ -5050,16 +5107,25 @@ async function opCall(call) {
|
|
|
5050
5107
|
function printResidue(report, applied) {
|
|
5051
5108
|
const up = report?.upstash ?? {};
|
|
5052
5109
|
const fga = report?.fga ?? {};
|
|
5110
|
+
const ghosts = report?.ghosts ?? {};
|
|
5053
5111
|
console.log(import_chalk33.default.bold(applied ? "\nExternal-residue sweep" : "\nExternal residue (dry-run \u2014 nothing deleted)"));
|
|
5054
5112
|
console.log(import_chalk33.default.bold("\n Upstash"));
|
|
5055
5113
|
const orphans = up.orphans ?? [];
|
|
5056
5114
|
if (orphans.length === 0) console.log(import_chalk33.default.green(" no orphaned keys"));
|
|
5057
5115
|
for (const o of orphans) console.log(` ${import_chalk33.default.yellow(o.key)} ${import_chalk33.default.dim(`\u2014 ${o.reason}`)}`);
|
|
5058
5116
|
console.log(import_chalk33.default.dim(` kept (live principals): ${up.kept ?? 0} \xB7 anon wallets (untouched): ${up.anon_wallets ?? 0}`));
|
|
5117
|
+
if (up.anon_wallet_detail) {
|
|
5118
|
+
const d = up.anon_wallet_detail;
|
|
5119
|
+
console.log(import_chalk33.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)"}`));
|
|
5120
|
+
}
|
|
5121
|
+
if (up.keyspace_census) {
|
|
5122
|
+
const census = Object.entries(up.keyspace_census).map(([k, v]) => `${k}=${v}`).join(" \xB7 ");
|
|
5123
|
+
console.log(import_chalk33.default.dim(` keyspace: ${census}`));
|
|
5124
|
+
}
|
|
5059
5125
|
if (up.unknown?.length) console.log(import_chalk33.default.dim(` unknown (never deleted): ${up.unknown.join(", ")}`));
|
|
5060
5126
|
if (applied) console.log(` ${import_chalk33.default.bold(String(up.deleted ?? 0))} key(s) deleted`);
|
|
5061
5127
|
for (const e of up.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
|
|
5062
|
-
console.log(import_chalk33.default.bold("\n OpenFGA / Neon"));
|
|
5128
|
+
console.log(import_chalk33.default.bold("\n OpenFGA / Neon \u2014 orphan stores"));
|
|
5063
5129
|
if (applied) {
|
|
5064
5130
|
const swept = fga?.swept ?? [];
|
|
5065
5131
|
if (swept.length === 0) console.log(import_chalk33.default.green(" no orphaned stores"));
|
|
@@ -5069,6 +5135,8 @@ function printResidue(report, applied) {
|
|
|
5069
5135
|
);
|
|
5070
5136
|
}
|
|
5071
5137
|
if (fga?.remaining) console.log(import_chalk33.default.yellow(` ${fga.remaining} more orphan store(s) \u2014 re-run to drain`));
|
|
5138
|
+
const st = fga?.side_tables;
|
|
5139
|
+
if (st) console.log(import_chalk33.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})` : ""}`));
|
|
5072
5140
|
} else {
|
|
5073
5141
|
const fgaOrphans = fga?.orphans ?? [];
|
|
5074
5142
|
if (fgaOrphans.length === 0) console.log(import_chalk33.default.green(" no orphaned stores"));
|
|
@@ -5077,8 +5145,26 @@ function printResidue(report, applied) {
|
|
|
5077
5145
|
console.log(` ${import_chalk33.default.yellow(s.store_id)} ${import_chalk33.default.dim(`\u2014 ${src}${s.name ? ` (${s.name})` : ""}, ${s.neon_tuples} Neon tuple(s)`)}`);
|
|
5078
5146
|
}
|
|
5079
5147
|
console.log(import_chalk33.default.dim(` kept stores: ${(fga?.kept_store_ids ?? []).length}`));
|
|
5148
|
+
const st = fga?.side_tables;
|
|
5149
|
+
if (st) console.log(import_chalk33.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`));
|
|
5080
5150
|
}
|
|
5081
5151
|
for (const e of fga?.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
|
|
5152
|
+
console.log(import_chalk33.default.bold("\n OpenFGA \u2014 ghost tuples in surviving stores"));
|
|
5153
|
+
if (applied) {
|
|
5154
|
+
if ((ghosts?.ghost_count ?? 0) === 0) console.log(import_chalk33.default.green(" no ghost tuples"));
|
|
5155
|
+
else console.log(` ${import_chalk33.default.bold(String(ghosts.deleted ?? 0))} ghost tuple(s) deleted ${import_chalk33.default.dim(`(of ${ghosts.ghost_count} found, ${ghosts.scanned_tuples} scanned across ${ghosts.live_stores} live stores)`)}`);
|
|
5156
|
+
} else {
|
|
5157
|
+
const n = ghosts?.ghost_count ?? 0;
|
|
5158
|
+
if (n === 0) console.log(import_chalk33.default.green(` no ghost tuples ${import_chalk33.default.dim(`(${ghosts.scanned_tuples ?? 0} scanned across ${ghosts.live_stores ?? 0} live stores)`)}`));
|
|
5159
|
+
else {
|
|
5160
|
+
console.log(import_chalk33.default.yellow(` ${n} ghost tuple(s) referencing entities absent from D1:`));
|
|
5161
|
+
for (const g of (ghosts.ghosts ?? []).slice(0, 20)) {
|
|
5162
|
+
console.log(import_chalk33.default.dim(` ${g.object_type}:${g.object_id} ${g.relation} ${g._user}`));
|
|
5163
|
+
}
|
|
5164
|
+
if (n > 20) console.log(import_chalk33.default.dim(` \u2026 and ${n - 20} more`));
|
|
5165
|
+
}
|
|
5166
|
+
}
|
|
5167
|
+
for (const e of ghosts?.errors ?? []) console.log(import_chalk33.default.red(` error: ${e}`));
|
|
5082
5168
|
console.log();
|
|
5083
5169
|
}
|
|
5084
5170
|
async function runOp(sub, opts = {}) {
|
|
@@ -5096,8 +5182,9 @@ async function runOp(sub, opts = {}) {
|
|
|
5096
5182
|
console.log(import_chalk33.default.bold("\nOperator menu"));
|
|
5097
5183
|
console.log(` ${import_chalk33.default.cyan("apiblaze op residue")} external-store residue report (Upstash + Neon/OpenFGA, dry-run)`);
|
|
5098
5184
|
console.log(` ${import_chalk33.default.cyan("apiblaze op sweep")} delete the orphans the report shows (asks first; ${import_chalk33.default.dim("-y to skip")})`);
|
|
5099
|
-
console.log(` ${import_chalk33.default.cyan("apiblaze op credits")} list credit wallets
|
|
5100
|
-
`)
|
|
5185
|
+
console.log(` ${import_chalk33.default.cyan("apiblaze op credits")} list credit wallets`);
|
|
5186
|
+
console.log(import_chalk33.default.dim(` (to prune all non-CP data: run scripts/nuke-but-cp.sh --apply --sweep in the repo)
|
|
5187
|
+
`));
|
|
5101
5188
|
return;
|
|
5102
5189
|
}
|
|
5103
5190
|
case "residue": {
|
|
@@ -5110,15 +5197,20 @@ async function runOp(sub, opts = {}) {
|
|
|
5110
5197
|
const report = await opCall({ method: "GET", path: "/operator/external-residue", summary: "external residue report" });
|
|
5111
5198
|
const nUp = report?.upstash?.orphans?.length ?? 0;
|
|
5112
5199
|
const nFga = report?.fga?.orphans?.length ?? 0;
|
|
5200
|
+
const nGhost = report?.ghosts?.ghost_count ?? 0;
|
|
5201
|
+
const st = report?.fga?.side_tables ?? {};
|
|
5202
|
+
const nSide = (st.soft_deleted_stores ?? 0) + (st.orphan_models ?? 0) + (st.orphan_changelog ?? 0);
|
|
5113
5203
|
printResidue(report, false);
|
|
5114
|
-
if (nUp + nFga === 0) {
|
|
5204
|
+
if (nUp + nFga + nGhost + nSide === 0) {
|
|
5115
5205
|
console.log(import_chalk33.default.green("Nothing to sweep."));
|
|
5116
5206
|
return;
|
|
5117
5207
|
}
|
|
5118
5208
|
if (!opts.yes) {
|
|
5119
5209
|
const readline2 = await import("readline/promises");
|
|
5120
5210
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
5121
|
-
const answer = await rl.question(
|
|
5211
|
+
const answer = await rl.question(
|
|
5212
|
+
import_chalk33.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: `)
|
|
5213
|
+
);
|
|
5122
5214
|
rl.close();
|
|
5123
5215
|
if (answer.trim() !== "sweep") return void console.log(import_chalk33.default.dim("Aborted."));
|
|
5124
5216
|
}
|
|
@@ -5145,6 +5237,7 @@ async function runOp(sub, opts = {}) {
|
|
|
5145
5237
|
|
|
5146
5238
|
// src/index.ts
|
|
5147
5239
|
init_trace();
|
|
5240
|
+
init_auth();
|
|
5148
5241
|
var program = new import_commander.Command();
|
|
5149
5242
|
program.name("apiblaze").description("APIblaze CLI \u2014 create & manage API proxies and run dev tunnels").version(version).option("-v, --verbose", "Print the exact series of API calls each command makes (curl-equivalent you could run yourself)");
|
|
5150
5243
|
program.hook("preAction", () => {
|
|
@@ -5158,7 +5251,7 @@ function action(fn) {
|
|
|
5158
5251
|
renderTrace();
|
|
5159
5252
|
} catch (err) {
|
|
5160
5253
|
renderTrace();
|
|
5161
|
-
printError(err);
|
|
5254
|
+
await printError(err);
|
|
5162
5255
|
process.exit(1);
|
|
5163
5256
|
}
|
|
5164
5257
|
};
|
|
@@ -5167,7 +5260,7 @@ program.command("login").description("Authenticate with APIblaze").action(async
|
|
|
5167
5260
|
try {
|
|
5168
5261
|
await runLogin();
|
|
5169
5262
|
} catch (err) {
|
|
5170
|
-
printError(err);
|
|
5263
|
+
await printError(err);
|
|
5171
5264
|
process.exit(1);
|
|
5172
5265
|
}
|
|
5173
5266
|
});
|
|
@@ -5175,7 +5268,7 @@ program.command("create").description("Create a new API proxy (no login needed \
|
|
|
5175
5268
|
try {
|
|
5176
5269
|
await runCreate(opts);
|
|
5177
5270
|
} catch (err) {
|
|
5178
|
-
printError(err);
|
|
5271
|
+
await printError(err);
|
|
5179
5272
|
process.exit(1);
|
|
5180
5273
|
}
|
|
5181
5274
|
});
|
|
@@ -5200,7 +5293,7 @@ program.command("dev").description("Put your localhost behind a public URL (dev
|
|
|
5200
5293
|
}
|
|
5201
5294
|
await runDev({ port: resolved, captureFile: opts.captureFile });
|
|
5202
5295
|
} catch (err) {
|
|
5203
|
-
printError(err);
|
|
5296
|
+
await printError(err);
|
|
5204
5297
|
process.exit(1);
|
|
5205
5298
|
}
|
|
5206
5299
|
});
|
|
@@ -5213,7 +5306,7 @@ program.command("whoami").description("Show who you are \u2014 both API Producer
|
|
|
5213
5306
|
try {
|
|
5214
5307
|
await runWhoami(opts);
|
|
5215
5308
|
} catch (err) {
|
|
5216
|
-
printError(err);
|
|
5309
|
+
await printError(err);
|
|
5217
5310
|
process.exit(1);
|
|
5218
5311
|
}
|
|
5219
5312
|
});
|
|
@@ -5221,7 +5314,7 @@ program.command("claim").description("Claim your anonymous workspace into your a
|
|
|
5221
5314
|
try {
|
|
5222
5315
|
await runClaim(code, opts);
|
|
5223
5316
|
} catch (err) {
|
|
5224
|
-
printError(err);
|
|
5317
|
+
await printError(err);
|
|
5225
5318
|
process.exit(1);
|
|
5226
5319
|
}
|
|
5227
5320
|
});
|
|
@@ -5229,7 +5322,7 @@ program.command("team").description("Switch the active team").argument("[team]",
|
|
|
5229
5322
|
try {
|
|
5230
5323
|
await runTeam(team);
|
|
5231
5324
|
} catch (err) {
|
|
5232
|
-
printError(err);
|
|
5325
|
+
await printError(err);
|
|
5233
5326
|
process.exit(1);
|
|
5234
5327
|
}
|
|
5235
5328
|
});
|
|
@@ -5237,7 +5330,7 @@ program.command("projects").description("List the projects in your team").action
|
|
|
5237
5330
|
try {
|
|
5238
5331
|
await runProjects();
|
|
5239
5332
|
} catch (err) {
|
|
5240
|
-
printError(err);
|
|
5333
|
+
await printError(err);
|
|
5241
5334
|
process.exit(1);
|
|
5242
5335
|
}
|
|
5243
5336
|
});
|
|
@@ -5319,14 +5412,32 @@ Examples:
|
|
|
5319
5412
|
$ npx apiblaze throttle myapi --rate 50 --verbose # configure + show the API call
|
|
5320
5413
|
$ npx apiblaze consumer login # act as a consumer of your API
|
|
5321
5414
|
`);
|
|
5322
|
-
function
|
|
5415
|
+
async function recoverStaleTeam() {
|
|
5416
|
+
try {
|
|
5417
|
+
const creds = loadCredentials();
|
|
5418
|
+
if (!creds?.teamId) return;
|
|
5419
|
+
const { resolveLinkedTeam: resolveLinkedTeam2 } = await Promise.resolve().then(() => (init_team(), team_exports));
|
|
5420
|
+
const linked = await resolveLinkedTeam2({ preferredId: creds.teamId, interactive: !!process.stdin.isTTY });
|
|
5421
|
+
if (!linked) {
|
|
5422
|
+
console.error(import_chalk34.default.yellow("Your account has no teams anymore (deleted?). Run `apiblaze login` or `apiblaze create` to get a workspace."));
|
|
5423
|
+
return;
|
|
5424
|
+
}
|
|
5425
|
+
if (linked.teamId === creds.teamId) return;
|
|
5426
|
+
const next = { ...creds, teamId: linked.teamId, teamName: linked.teamName };
|
|
5427
|
+
delete next.activeTenant;
|
|
5428
|
+
saveCredentials(next);
|
|
5429
|
+
console.error(import_chalk34.default.yellow(`Your previous team no longer exists \u2014 relinked to ${import_chalk34.default.bold(linked.teamName ?? linked.teamId)}. Re-run your command.`));
|
|
5430
|
+
} catch {
|
|
5431
|
+
}
|
|
5432
|
+
}
|
|
5433
|
+
async function printError(err) {
|
|
5323
5434
|
if (err instanceof ApiError) {
|
|
5324
5435
|
const data = err.body;
|
|
5325
5436
|
const extra = [data?.body?.reason, data?.body?.details, data?.details, data?.body?.error].find((x) => typeof x === "string" && x && x !== err.message);
|
|
5326
5437
|
console.error(import_chalk34.default.red(`
|
|
5327
5438
|
API error (${err.status}): ${err.message}${extra ? ` \u2014 ${extra}` : ""}`));
|
|
5328
5439
|
if (err.status === 403 || err.status === 404) {
|
|
5329
|
-
|
|
5440
|
+
await recoverStaleTeam();
|
|
5330
5441
|
}
|
|
5331
5442
|
} else if (err instanceof Error) {
|
|
5332
5443
|
console.error(import_chalk34.default.red(`
|
package/package.json
CHANGED