apiblaze 0.8.0 → 0.10.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 +114 -114
- package/dist/sidecar/index.js +7 -6
- package/dist/sidecar/index.mjs +7 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -99,7 +99,6 @@ var api_exports = {};
|
|
|
99
99
|
__export(api_exports, {
|
|
100
100
|
agentCall: () => agentCall,
|
|
101
101
|
checkProxyName: () => checkProxyName,
|
|
102
|
-
claimProxy: () => claimProxy,
|
|
103
102
|
claimTeam: () => claimTeam,
|
|
104
103
|
createProxy: () => createProxy,
|
|
105
104
|
createProxyAnonymous: () => createProxyAnonymous,
|
|
@@ -194,16 +193,10 @@ async function createProxy(payload) {
|
|
|
194
193
|
body: JSON.stringify(payload)
|
|
195
194
|
});
|
|
196
195
|
}
|
|
197
|
-
async function
|
|
198
|
-
return apiFetch("/api/cli/claim", {
|
|
199
|
-
method: "POST",
|
|
200
|
-
body: JSON.stringify({ claimCode, team_id: teamId })
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
async function claimTeam(code) {
|
|
196
|
+
async function claimTeam(code, teamId) {
|
|
204
197
|
return apiFetch("/api/cli/claim-team", {
|
|
205
198
|
method: "POST",
|
|
206
|
-
body: JSON.stringify({ code })
|
|
199
|
+
body: JSON.stringify({ code, ...teamId ? { team_id: teamId } : {} })
|
|
207
200
|
});
|
|
208
201
|
}
|
|
209
202
|
async function sidecarInitAnonymous() {
|
|
@@ -312,7 +305,7 @@ var import_commander = require("commander");
|
|
|
312
305
|
var import_chalk30 = __toESM(require("chalk"));
|
|
313
306
|
|
|
314
307
|
// package.json
|
|
315
|
-
var version = "0.
|
|
308
|
+
var version = "0.10.0";
|
|
316
309
|
|
|
317
310
|
// src/index.ts
|
|
318
311
|
init_types();
|
|
@@ -1530,7 +1523,7 @@ async function runAnonymousCreate(opts) {
|
|
|
1530
1523
|
} else {
|
|
1531
1524
|
result = await createProxyAnonymous(body);
|
|
1532
1525
|
if (result.cp_key && result.team_id) {
|
|
1533
|
-
saveAnonCred2(result.cp_key, result.team_id, result.
|
|
1526
|
+
saveAnonCred2(result.cp_key, result.team_id, result.claim_code);
|
|
1534
1527
|
}
|
|
1535
1528
|
}
|
|
1536
1529
|
spinner?.succeed(import_chalk6.default.green("Proxy created!"));
|
|
@@ -1564,13 +1557,13 @@ async function runAnonymousCreate(opts) {
|
|
|
1564
1557
|
console.log(import_chalk6.default.dim("\n Save this now \u2014 send it as the X-API-Key header. It may not be shown again."));
|
|
1565
1558
|
}
|
|
1566
1559
|
if (prodEndpoint) printCurlExample(prodEndpoint, opts.auth || "api_key", apiKey, result.portal);
|
|
1567
|
-
const claimCode = result.
|
|
1560
|
+
const claimCode = result.claim_code || cred?.claim_code;
|
|
1568
1561
|
if (claimCode) {
|
|
1569
1562
|
console.log();
|
|
1570
|
-
console.log(` ${import_chalk6.default.yellow("\u26A0 Anonymous \u2014 claim within 30 days or it expires.")}
|
|
1571
|
-
console.log(`
|
|
1572
|
-
console.log(` ${import_chalk6.default.cyan("apiblaze login")} ${import_chalk6.default.dim("(prompts to claim
|
|
1573
|
-
console.log(import_chalk6.default.dim(` From another machine: apiblaze claim ${claimCode}`));
|
|
1563
|
+
console.log(` ${import_chalk6.default.yellow("\u26A0 Anonymous \u2014 claim within 30 days or it expires.")} Everything you create`);
|
|
1564
|
+
console.log(` with the CP key shares ONE workspace. To keep it all in one shot:`);
|
|
1565
|
+
console.log(` ${import_chalk6.default.cyan("apiblaze login")} ${import_chalk6.default.dim("(prompts to claim your workspace into your account)")}`);
|
|
1566
|
+
console.log(import_chalk6.default.dim(` From another machine: apiblaze claim ${claimCode} (add --team <name> to merge into an existing team)`));
|
|
1574
1567
|
} else if (result.claim_url) {
|
|
1575
1568
|
console.log();
|
|
1576
1569
|
console.log(` ${import_chalk6.default.yellow("\u26A0 Anonymous proxy \u2014 claim it to your account within 30 days or it expires:")}`);
|
|
@@ -1591,100 +1584,55 @@ function fail2(message) {
|
|
|
1591
1584
|
}
|
|
1592
1585
|
async function runClaim(claimCodeArg, opts) {
|
|
1593
1586
|
const creds = loadCredentials();
|
|
1594
|
-
if (!creds)
|
|
1595
|
-
fail2("Not logged in. Run `apiblaze login` first, then claim.");
|
|
1596
|
-
}
|
|
1587
|
+
if (!creds) fail2("Not logged in. Run `apiblaze login` first, then claim.");
|
|
1597
1588
|
let claimCode = (claimCodeArg ?? "").trim();
|
|
1598
|
-
let
|
|
1589
|
+
let fromLocal = false;
|
|
1599
1590
|
if (!claimCode) {
|
|
1600
|
-
const
|
|
1601
|
-
if (
|
|
1602
|
-
claimCode =
|
|
1603
|
-
|
|
1591
|
+
const c = loadAnonCred();
|
|
1592
|
+
if (c?.claim_code) {
|
|
1593
|
+
claimCode = c.claim_code;
|
|
1594
|
+
fromLocal = true;
|
|
1604
1595
|
}
|
|
1605
1596
|
}
|
|
1606
1597
|
if (!claimCode && process.stdin.isTTY) {
|
|
1607
1598
|
const { default: inquirer2 } = await import("inquirer");
|
|
1608
|
-
const { code } = await inquirer2.prompt([{
|
|
1609
|
-
type: "input",
|
|
1610
|
-
name: "code",
|
|
1611
|
-
message: "Claim code (from the create output / claim URL):"
|
|
1612
|
-
}]);
|
|
1599
|
+
const { code } = await inquirer2.prompt([{ type: "input", name: "code", message: "Claim code:" }]);
|
|
1613
1600
|
claimCode = (code ?? "").trim();
|
|
1614
1601
|
}
|
|
1615
|
-
if (!claimCode)
|
|
1616
|
-
|
|
1602
|
+
if (!claimCode) fail2("Nothing to claim on this machine. Run `apiblaze claim <code>`, or `apiblaze create`/`init` first.");
|
|
1603
|
+
let targetTeamId;
|
|
1604
|
+
if (opts.team) {
|
|
1605
|
+
const teams = await getTeams().catch(() => []);
|
|
1606
|
+
const match = teams.find((t) => t.teamId === opts.team || t.name.toLowerCase() === opts.team.toLowerCase());
|
|
1607
|
+
if (!match) fail2(`Team "${opts.team}" not found. Available: ${teams.map((t) => t.name).join(", ") || "(none)"}.`);
|
|
1608
|
+
targetTeamId = match.teamId;
|
|
1617
1609
|
}
|
|
1610
|
+
let res;
|
|
1618
1611
|
try {
|
|
1619
|
-
|
|
1620
|
-
if (fromLocalSession) clearAnonCred();
|
|
1621
|
-
if (opts.json) {
|
|
1622
|
-
console.log(JSON.stringify(t, null, 2));
|
|
1623
|
-
return;
|
|
1624
|
-
}
|
|
1625
|
-
console.log(import_chalk7.default.green(`
|
|
1626
|
-
\u2714 Claimed the whole team into your account.`));
|
|
1627
|
-
console.log(` Team: ${import_chalk7.default.bold(t.team_id)}`);
|
|
1628
|
-
console.log(` Its proxies + keys are now yours. Switch to it with ${import_chalk7.default.cyan(`apiblaze team ${t.team_id}`)}.`);
|
|
1629
|
-
console.log(`
|
|
1630
|
-
Manage it at ${import_chalk7.default.cyan("https://dashboard.apiblaze.com/dashboard")}`);
|
|
1631
|
-
return;
|
|
1612
|
+
res = await claimTeam(claimCode, targetTeamId);
|
|
1632
1613
|
} catch (err) {
|
|
1633
|
-
if (err instanceof ApiError
|
|
1634
|
-
const
|
|
1635
|
-
if (
|
|
1636
|
-
if (
|
|
1637
|
-
if (
|
|
1614
|
+
if (err instanceof ApiError) {
|
|
1615
|
+
const c = typeof err.body === "object" && err.body ? err.body.error : void 0;
|
|
1616
|
+
if (c === "already_claimed") fail2("That claim code has already been used.");
|
|
1617
|
+
if (c === "expired") fail2("That claim code has expired. Create a fresh setup with `apiblaze create`/`init`.");
|
|
1618
|
+
if (c === "not_claimable") fail2("That workspace can no longer be claimed (it already belongs to an account).");
|
|
1619
|
+
if (err.status === 404) fail2("That claim code isn't valid \u2014 check it and try again.");
|
|
1620
|
+
if (err.status === 403) fail2(`You're not a member of team "${opts.team}".`);
|
|
1638
1621
|
fail2(`Could not claim: ${err.message}`);
|
|
1639
1622
|
}
|
|
1640
|
-
}
|
|
1641
|
-
const teams = await getTeams().catch(() => []);
|
|
1642
|
-
if (teams.length === 0) {
|
|
1643
|
-
fail2("No teams found for your account.");
|
|
1644
|
-
}
|
|
1645
|
-
let teamId;
|
|
1646
|
-
if (opts.team) {
|
|
1647
|
-
const match = teams.find(
|
|
1648
|
-
(t) => t.teamId === opts.team || t.name.toLowerCase() === opts.team.toLowerCase()
|
|
1649
|
-
);
|
|
1650
|
-
if (!match) {
|
|
1651
|
-
fail2(`Team "${opts.team}" not found. Available: ${teams.map((t) => t.name).join(", ")}.`);
|
|
1652
|
-
}
|
|
1653
|
-
teamId = match.teamId;
|
|
1654
|
-
} else if (creds.teamId && teams.some((t) => t.teamId === creds.teamId)) {
|
|
1655
|
-
teamId = creds.teamId;
|
|
1656
|
-
} else if (teams.length === 1) {
|
|
1657
|
-
teamId = teams[0].teamId;
|
|
1658
|
-
} else if (process.stdin.isTTY) {
|
|
1659
|
-
const { default: inquirer2 } = await import("inquirer");
|
|
1660
|
-
const { picked } = await inquirer2.prompt([{
|
|
1661
|
-
type: "list",
|
|
1662
|
-
name: "picked",
|
|
1663
|
-
message: "Claim into which team?",
|
|
1664
|
-
choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
|
|
1665
|
-
}]);
|
|
1666
|
-
teamId = picked;
|
|
1667
|
-
} else {
|
|
1668
|
-
fail2(`Specify a team: \`apiblaze claim ${claimCode} --team <name|id>\`. Available: ${teams.map((t) => t.name).join(", ")}.`);
|
|
1669
|
-
}
|
|
1670
|
-
const teamName = teams.find((t) => t.teamId === teamId)?.name ?? teamId;
|
|
1671
|
-
let result;
|
|
1672
|
-
try {
|
|
1673
|
-
result = await claimProxy(claimCode, teamId);
|
|
1674
|
-
} catch (err) {
|
|
1675
|
-
if (err instanceof ApiError) fail2(`That claim code isn't valid \u2014 it may be mistyped, already claimed, or expired.`);
|
|
1676
1623
|
throw err;
|
|
1677
1624
|
}
|
|
1625
|
+
if (fromLocal) clearAnonCred();
|
|
1678
1626
|
if (opts.json) {
|
|
1679
|
-
console.log(JSON.stringify(
|
|
1627
|
+
console.log(JSON.stringify(res, null, 2));
|
|
1680
1628
|
return;
|
|
1681
1629
|
}
|
|
1682
|
-
console.log(import_chalk7.default.green(
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
console.log(
|
|
1687
|
-
|
|
1630
|
+
console.log(import_chalk7.default.green("\n\u2714 Claimed your anonymous workspace into your account."));
|
|
1631
|
+
if (res.merged) {
|
|
1632
|
+
console.log(` Merged ${import_chalk7.default.bold(String(res.proxy_count ?? ""))} prox${res.proxy_count === 1 ? "y" : "ies"} into team ${import_chalk7.default.bold(res.team_id)}.`);
|
|
1633
|
+
} else {
|
|
1634
|
+
console.log(` It's now your team ${import_chalk7.default.bold(res.team_id)}. Switch to it with ${import_chalk7.default.cyan(`apiblaze team ${res.team_id}`)}.`);
|
|
1635
|
+
console.log(import_chalk7.default.dim(` (Tip: re-run with --team <name> to merge into an existing team instead.)`));
|
|
1688
1636
|
}
|
|
1689
1637
|
console.log(`
|
|
1690
1638
|
Manage it at ${import_chalk7.default.cyan("https://dashboard.apiblaze.com/dashboard")}`);
|
|
@@ -3318,11 +3266,31 @@ function upsertEnvLocal(root, token) {
|
|
|
3318
3266
|
`;
|
|
3319
3267
|
if (!/^APIBLAZE_SIDECAR=/m.test(next)) {
|
|
3320
3268
|
next = (next.endsWith("\n") ? next : next + "\n") + `APIBLAZE_SIDECAR=on
|
|
3269
|
+
`;
|
|
3270
|
+
}
|
|
3271
|
+
if (!/^APIBLAZE_SIDECAR_VERBOSE=/m.test(next)) {
|
|
3272
|
+
next = (next.endsWith("\n") ? next : next + "\n") + `APIBLAZE_SIDECAR_VERBOSE=true
|
|
3321
3273
|
`;
|
|
3322
3274
|
}
|
|
3323
3275
|
fs7.writeFileSync(p, next);
|
|
3324
3276
|
return had ? "rotated" : "created";
|
|
3325
3277
|
}
|
|
3278
|
+
function installSidecarPackage(root) {
|
|
3279
|
+
if (fs7.existsSync(path4.join(root, "node_modules", "apiblaze", "package.json"))) {
|
|
3280
|
+
console.log(` ${import_chalk28.default.green("\u2713")} apiblaze package already installed`);
|
|
3281
|
+
return;
|
|
3282
|
+
}
|
|
3283
|
+
const has = (f) => fs7.existsSync(path4.join(root, f));
|
|
3284
|
+
const pm = has("bun.lockb") || has("bun.lock") ? { cmd: "bun", add: "add" } : has("pnpm-lock.yaml") ? { cmd: "pnpm", add: "add" } : has("yarn.lock") ? { cmd: "yarn", add: "add" } : { cmd: "npm", add: "install" };
|
|
3285
|
+
const spinner = (0, import_ora13.default)(`Installing the apiblaze package (${pm.cmd})\u2026`).start();
|
|
3286
|
+
try {
|
|
3287
|
+
const { execSync } = require("child_process");
|
|
3288
|
+
execSync(`${pm.cmd} ${pm.add} apiblaze`, { cwd: root, stdio: "ignore" });
|
|
3289
|
+
spinner.succeed("Installed apiblaze (the sidecar runtime).");
|
|
3290
|
+
} catch {
|
|
3291
|
+
spinner.warn(`Couldn't auto-install \u2014 run ${import_chalk28.default.cyan(`${pm.cmd} ${pm.add} apiblaze`)} yourself before ${import_chalk28.default.cyan("npm run dev")}.`);
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3326
3294
|
function readEnvKey(root) {
|
|
3327
3295
|
try {
|
|
3328
3296
|
const s = fs7.readFileSync(path4.join(root, ".env.local"), "utf8");
|
|
@@ -3380,16 +3348,46 @@ async function probe(u: string) {
|
|
|
3380
3348
|
}
|
|
3381
3349
|
|
|
3382
3350
|
export default async function Page() {
|
|
3383
|
-
if (process.env.NODE_ENV === "production") return <main style={{padding:24}}>Inspector disabled in production.</main>;
|
|
3384
|
-
const r = await probe("https://httpbingo.org/headers");
|
|
3351
|
+
if (process.env.NODE_ENV === "production") return <main style={{ padding: 24 }}>Inspector disabled in production.</main>;
|
|
3352
|
+
const r: any = await probe("https://httpbingo.org/headers");
|
|
3353
|
+
const hdrs = (r && r.echo && r.echo.headers) || {};
|
|
3354
|
+
// The sidecar sets X-Abz-Fwd-X-Api-Key ONLY when it routes a call through a proxy.
|
|
3355
|
+
const routed = Boolean(hdrs["X-Abz-Fwd-X-Api-Key"] || hdrs["x-abz-fwd-x-api-key"]);
|
|
3356
|
+
const card: any = { background: "#0b0f17", border: "1px solid #232a36", borderRadius: 14, padding: 20 };
|
|
3357
|
+
const pill: any = { display: "inline-block", padding: "4px 10px", borderRadius: 999, fontSize: 12, fontWeight: 700 };
|
|
3385
3358
|
return (
|
|
3386
|
-
<main style={{ fontFamily: "ui-monospace, monospace", padding:
|
|
3387
|
-
<
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3359
|
+
<main style={{ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", background: "#070a10", minHeight: "100vh", padding: 32, color: "#e6e9ef", lineHeight: 1.6 }}>
|
|
3360
|
+
<div style={{ maxWidth: 720, margin: "0 auto" }}>
|
|
3361
|
+
<h1 style={{ fontSize: 20, margin: "0 0 6px" }}>APIblaze sidecar \u2014 live inspector</h1>
|
|
3362
|
+
<p style={{ color: "#9aa4b2", margin: "0 0 20px", fontSize: 14 }}>
|
|
3363
|
+
This dev-only page makes one real call to <b style={{ color: "#e6e9ef" }}>httpbingo.org</b> from your server so you can watch the sidecar work. Every external fetch your app makes either <b>routes</b> through APIblaze (once you approve that origin) or goes <b>direct</b>, untouched.
|
|
3364
|
+
</p>
|
|
3365
|
+
<div style={card}>
|
|
3366
|
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, marginBottom: 14, flexWrap: "wrap" }}>
|
|
3367
|
+
<span style={{ fontSize: 15 }}>GET https://httpbingo.org/headers</span>
|
|
3368
|
+
{routed
|
|
3369
|
+
? <span style={{ ...pill, background: "#0f2e20", color: "#4ade80" }}>\u25CF routed through APIblaze</span>
|
|
3370
|
+
: <span style={{ ...pill, background: "#33280c", color: "#fbbf24" }}>\u25CB going direct \u2014 not approved</span>}
|
|
3371
|
+
</div>
|
|
3372
|
+
{routed ? (
|
|
3373
|
+
<p style={{ color: "#9aa4b2", fontSize: 14, margin: 0 }}>
|
|
3374
|
+
This request <b style={{ color: "#4ade80" }}>routed through your APIblaze proxy</b> \u2014 with auth, rate limits, and observability \u2014 and your app code never changed. The proxy swapped in your invoke key and preserved your original one (see <code>X-Abz-Fwd-X-Api-Key</code> in the raw response).
|
|
3375
|
+
</p>
|
|
3376
|
+
) : (
|
|
3377
|
+
<div style={{ color: "#9aa4b2", fontSize: 14 }}>
|
|
3378
|
+
<p style={{ margin: "0 0 10px" }}>This call went <b style={{ color: "#fbbf24" }}>direct</b> \u2014 httpbingo.org isn't approved yet, so the sidecar left it untouched and reported it as a candidate.</p>
|
|
3379
|
+
<p style={{ margin: "0 0 6px", color: "#e6e9ef" }}>Route it through APIblaze:</p>
|
|
3380
|
+
<pre style={{ background: "#070a10", border: "1px solid #232a36", borderRadius: 8, padding: 12, margin: 0, color: "#8ab4ff", overflowX: "auto" }}>npx apiblaze sidecar approve httpbingo.org</pre>
|
|
3381
|
+
<p style={{ margin: "10px 0 0" }}>\u2026wait ~5 min, then <b style={{ color: "#e6e9ef" }}>reload</b>. The badge above turns green.</p>
|
|
3382
|
+
</div>
|
|
3383
|
+
)}
|
|
3384
|
+
</div>
|
|
3385
|
+
<details style={{ marginTop: 16, color: "#9aa4b2", fontSize: 13 }}>
|
|
3386
|
+
<summary style={{ cursor: "pointer" }}>Raw response {r && r.status ? "(HTTP " + r.status + ")" : "(error)"}</summary>
|
|
3387
|
+
<pre style={{ background: "#0b0f17", border: "1px solid #232a36", borderRadius: 10, padding: 14, overflowX: "auto", marginTop: 8 }}>{JSON.stringify(r, null, 2)}</pre>
|
|
3388
|
+
</details>
|
|
3389
|
+
<p style={{ color: "#5b6472", fontSize: 12, marginTop: 20 }}>Dev-only \u2014 delete <code>app/abz-inspector</code> before shipping.</p>
|
|
3390
|
+
</div>
|
|
3393
3391
|
</main>
|
|
3394
3392
|
);
|
|
3395
3393
|
}
|
|
@@ -3430,6 +3428,7 @@ async function runAnonymousInit(root, router, opts) {
|
|
|
3430
3428
|
ensureGitignored(root);
|
|
3431
3429
|
console.log(` ${import_chalk28.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
|
|
3432
3430
|
console.log(` ${import_chalk28.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
|
|
3431
|
+
installSidecarPackage(root);
|
|
3433
3432
|
let inspectorPath = null;
|
|
3434
3433
|
if (!opts.noInspector) {
|
|
3435
3434
|
inspectorPath = generateInspector(root, router);
|
|
@@ -3437,9 +3436,9 @@ async function runAnonymousInit(root, router, opts) {
|
|
|
3437
3436
|
}
|
|
3438
3437
|
console.log("");
|
|
3439
3438
|
console.log(import_chalk28.default.bold("Done (no account needed). What happens next:"));
|
|
3440
|
-
console.log(` 1. ${import_chalk28.default.cyan("npm
|
|
3439
|
+
console.log(` 1. ${import_chalk28.default.cyan("npm run dev")} and use your app.`);
|
|
3441
3440
|
console.log(` 2. Each external origin your app calls is logged in the console \u2014 approve one with:`);
|
|
3442
|
-
console.log(` ${import_chalk28.default.cyan("apiblaze
|
|
3441
|
+
console.log(` ${import_chalk28.default.cyan("apiblaze sidecar approve api.stripe.com")} (no login needed)`);
|
|
3443
3442
|
console.log("");
|
|
3444
3443
|
console.log(import_chalk28.default.bold(" \u{1F511} Keep your setup \u2014 claim it into an account:"));
|
|
3445
3444
|
console.log(` ${import_chalk28.default.cyan("apiblaze login")} then ${import_chalk28.default.cyan("apiblaze claim")} ${import_chalk28.default.dim("(no code needed here)")}`);
|
|
@@ -3462,6 +3461,7 @@ async function runSidecar(opts) {
|
|
|
3462
3461
|
ensureGitignored(root);
|
|
3463
3462
|
console.log(` ${import_chalk28.default.green("\u2713")} .env.local present (APIBLAZE_API_KEY) \u2014 reusing`);
|
|
3464
3463
|
console.log(` ${import_chalk28.default.green("\u2713")} instrumentation.ts ${wireInstrumentation(root)}`);
|
|
3464
|
+
installSidecarPackage(root);
|
|
3465
3465
|
console.log(import_chalk28.default.dim(" Log in and run `apiblaze claim <code>` to keep this setup, or `apiblaze login` to manage it."));
|
|
3466
3466
|
return;
|
|
3467
3467
|
}
|
|
@@ -3492,6 +3492,7 @@ async function runSidecar(opts) {
|
|
|
3492
3492
|
console.log(` ${import_chalk28.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
|
|
3493
3493
|
const wireState = wireInstrumentation(root);
|
|
3494
3494
|
console.log(` ${import_chalk28.default.green("\u2713")} instrumentation.ts ${wireState}`);
|
|
3495
|
+
installSidecarPackage(root);
|
|
3495
3496
|
let inspectorPath = null;
|
|
3496
3497
|
if (!opts.noInspector) {
|
|
3497
3498
|
inspectorPath = generateInspector(root, detected.router);
|
|
@@ -3499,15 +3500,14 @@ async function runSidecar(opts) {
|
|
|
3499
3500
|
}
|
|
3500
3501
|
console.log("");
|
|
3501
3502
|
console.log(import_chalk28.default.bold("Done. What happens next:"));
|
|
3502
|
-
console.log(` 1. ${import_chalk28.default.cyan("npm
|
|
3503
|
-
console.log(` 2. ${import_chalk28.default.
|
|
3504
|
-
console.log(` 3.
|
|
3505
|
-
console.log(` 4. Approve the ones to route: ${import_chalk28.default.cyan("apiblaze origins approve api.stripe.com")} (or in the dashboard)`);
|
|
3503
|
+
console.log(` 1. ${import_chalk28.default.cyan("npm run dev")} and use your app \u2014 it works exactly as before (all calls go direct).`);
|
|
3504
|
+
console.log(` 2. The origins your app calls appear as ${import_chalk28.default.bold("candidates")} \u2014 list them: ${import_chalk28.default.cyan("apiblaze sidecar")}`);
|
|
3505
|
+
console.log(` 3. Approve the ones to route: ${import_chalk28.default.cyan("apiblaze sidecar approve api.stripe.com")} (or in the dashboard)`);
|
|
3506
3506
|
console.log(` \u2026within ~5 min your app starts routing that origin through APIblaze.`);
|
|
3507
3507
|
if (inspectorPath) console.log(` \u2022 Try it now: open ${import_chalk28.default.underline("http://localhost:3000/abz-inspector")} (dev only; rm ${path4.dirname(inspectorPath)} before shipping)`);
|
|
3508
|
-
if (switchingTeam) console.log(import_chalk28.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze
|
|
3508
|
+
if (switchingTeam) console.log(import_chalk28.default.dim(` \u2022 Approved origins are per-team \u2014 re-approve them on ${teamName ?? teamId} with \`apiblaze sidecar approve <origin>\`.`));
|
|
3509
3509
|
console.log("");
|
|
3510
|
-
console.log(import_chalk28.default.dim(" Manage: apiblaze
|
|
3510
|
+
console.log(import_chalk28.default.dim(" Manage: apiblaze sidecar (list/approve/deny/remove)"));
|
|
3511
3511
|
console.log(import_chalk28.default.dim(" Rotate: apiblaze init --rotate \xB7 Switch team: apiblaze init --team <name>"));
|
|
3512
3512
|
console.log(import_chalk28.default.dim(" Turn off: set APIBLAZE_SIDECAR=off in .env.local (flip back to on anytime; key stays put)."));
|
|
3513
3513
|
console.log("");
|
|
@@ -3555,8 +3555,8 @@ Candidates \u2014 going direct, not yet approved (${candidates.length})`));
|
|
|
3555
3555
|
}
|
|
3556
3556
|
if (candidates.length) {
|
|
3557
3557
|
console.log(import_chalk29.default.dim(`
|
|
3558
|
-
Approve: apiblaze
|
|
3559
|
-
console.log(import_chalk29.default.dim(` Dismiss: apiblaze
|
|
3558
|
+
Approve: apiblaze sidecar approve ${candidates[0].origin.replace("https://", "")}`));
|
|
3559
|
+
console.log(import_chalk29.default.dim(` Dismiss: apiblaze sidecar deny ${candidates[0].origin.replace("https://", "")}`));
|
|
3560
3560
|
}
|
|
3561
3561
|
}
|
|
3562
3562
|
async function runOriginsApprove(origin, opts) {
|
|
@@ -3655,7 +3655,7 @@ agent.command("authz").description("Chat to design and turn on access rules for
|
|
|
3655
3655
|
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)));
|
|
3656
3656
|
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)));
|
|
3657
3657
|
program.command("init").aliases(["sidecar"]).description("Wire a Next.js app to route its external fetches through APIblaze (one command)").option("--team <id|name>", "Team to set up under (defaults to your active team)").option("--dir <path>", "Project directory (defaults to cwd)").option("--no-inspector", "Skip generating the dev-only /abz-inspector page").option("--rotate", "Mint a fresh invoke key even if one already exists").option("--new-session", "Start a fresh anonymous session (logged-out only)").option("-y, --yes", "Skip prompts").action(action((opts) => runSidecar({ team: opts.team, dir: opts.dir, yes: opts.yes, noInspector: opts.inspector === false, rotate: opts.rotate, newSession: opts.newSession })));
|
|
3658
|
-
var origins = program.command("origins").description("See which external origins your app calls; approve the ones to route through APIblaze").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Machine-readable output").action(action((opts) => runOriginsList(opts)));
|
|
3658
|
+
var origins = program.command("sidecar").alias("origins").description("See which external origins your app calls; approve the ones to route through APIblaze").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Machine-readable output").action(action((opts) => runOriginsList(opts)));
|
|
3659
3659
|
origins.command("approve").description("Route an origin through APIblaze (creates its proxy)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").option("--json", "Machine-readable output").action(action((origin, opts) => runOriginsApprove(origin, opts)));
|
|
3660
3660
|
origins.command("deny").description("Dismiss a candidate origin so it stops being suggested").argument("<origin>", "Origin, e.g. sentry.io").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts) => runOriginsDeny(origin, opts)));
|
|
3661
3661
|
origins.command("remove").description("Un-route an approved origin (deletes its proxy; the app goes direct again)").argument("<origin>", "Origin, e.g. api.stripe.com").option("--team <id|name>", "Team (defaults to active team)").action(action((origin, opts) => runOriginsRemove(origin, opts)));
|
|
@@ -3685,7 +3685,7 @@ program.command("whoami").description("Show who you are \u2014 both API Producer
|
|
|
3685
3685
|
process.exit(1);
|
|
3686
3686
|
}
|
|
3687
3687
|
});
|
|
3688
|
-
program.command("claim").description("Claim
|
|
3688
|
+
program.command("claim").description("Claim your anonymous workspace into your account (requires login)").argument("[code]", "Claim code from `create`/`init` output (omit to claim this machine's workspace)").option("--team <id|name>", "Merge into this existing team (default: promote to a new team)").option("--json", "Output machine-readable JSON (non-interactive)").action(async (code, opts) => {
|
|
3689
3689
|
try {
|
|
3690
3690
|
await runClaim(code, opts);
|
|
3691
3691
|
} catch (err) {
|
|
@@ -3736,7 +3736,7 @@ spec.command("get").description("Print the current OpenAPI document").argument("
|
|
|
3736
3736
|
spec.command("set").description("Replace the stored OpenAPI spec from a local file").argument("<project>", "Project name or id").requiredOption("--file <path>", "OpenAPI JSON or YAML file to upload").option("--team <id|name>", "Team the project is in").option("--apiversion <version>", "API version").option("--json", "Output machine-readable JSON").action(action((project, opts) => runSpecSet(project, opts)));
|
|
3737
3737
|
var HELP_GROUPS = [
|
|
3738
3738
|
{ title: "Chat", commands: ["agent"] },
|
|
3739
|
-
{ title: "Setup", commands: ["login", "create", "init", "
|
|
3739
|
+
{ title: "Setup", commands: ["login", "create", "init", "sidecar", "dev", "claim", "team", "whoami", "logout"] },
|
|
3740
3740
|
{ title: "Control plane commands", commands: ["projects", "tenant", "domain", "delete", "target", "throttle", "rename", "spec", "export"] },
|
|
3741
3741
|
{ title: "Data plane commands", commands: [
|
|
3742
3742
|
{ parent: "consumer", sub: "login" },
|
package/dist/sidecar/index.js
CHANGED
|
@@ -84,14 +84,15 @@ function isPrivateOrLocal(host) {
|
|
|
84
84
|
}
|
|
85
85
|
function register(opts) {
|
|
86
86
|
if (installed) return;
|
|
87
|
+
const quiet = opts?.quiet ?? (process.env.APIBLAZE_SIDECAR_VERBOSE ?? "true").trim().toLowerCase() === "false";
|
|
87
88
|
const off = opts?.enabled === false || opts?.enabled === void 0 && OFF_VALUES.has((process.env.APIBLAZE_SIDECAR ?? "").trim().toLowerCase());
|
|
88
89
|
if (off) {
|
|
89
|
-
if (!
|
|
90
|
+
if (!quiet) console.log("[apiblaze/sidecar] off (APIBLAZE_SIDECAR=off) \u2014 fetches go direct.");
|
|
90
91
|
return;
|
|
91
92
|
}
|
|
92
93
|
const token = opts?.token ?? process.env.APIBLAZE_API_KEY ?? process.env.APIBLAZE_TOKEN;
|
|
93
94
|
if (!token) {
|
|
94
|
-
if (!
|
|
95
|
+
if (!quiet) console.log("[apiblaze/sidecar] off (no APIBLAZE_API_KEY set) \u2014 fetches go direct.");
|
|
95
96
|
return;
|
|
96
97
|
}
|
|
97
98
|
const original = globalThis.fetch;
|
|
@@ -145,7 +146,7 @@ function register(opts) {
|
|
|
145
146
|
if (base) {
|
|
146
147
|
if (!seen.has(origin)) {
|
|
147
148
|
seen.add(origin);
|
|
148
|
-
if (!
|
|
149
|
+
if (!quiet) console.log(`[apiblaze/sidecar] routed \u2192 ${origin}`);
|
|
149
150
|
}
|
|
150
151
|
const isReq = input instanceof Request;
|
|
151
152
|
const headers = new Headers(isReq ? input.headers : void 0);
|
|
@@ -168,21 +169,21 @@ function register(opts) {
|
|
|
168
169
|
}
|
|
169
170
|
if (!seen.has(origin)) {
|
|
170
171
|
seen.add(origin);
|
|
171
|
-
if (!
|
|
172
|
+
if (!quiet) console.log(`[apiblaze/sidecar] direct (not approved) \u2192 ${origin} \xB7 approve to route it: npx apiblaze sidecar approve ${url.hostname}`);
|
|
172
173
|
reportObserved(origin);
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
} catch (err) {
|
|
178
|
-
if (!
|
|
179
|
+
if (!quiet) console.warn("[apiblaze/sidecar] passthrough after sidecar error:", err?.message);
|
|
179
180
|
}
|
|
180
181
|
return original(input, init);
|
|
181
182
|
};
|
|
182
183
|
wrapped.__apiblaze = true;
|
|
183
184
|
globalThis.fetch = wrapped;
|
|
184
185
|
installed = true;
|
|
185
|
-
if (!
|
|
186
|
+
if (!quiet) console.log("[apiblaze/sidecar] active \u2014 approved origins route through APIblaze; the rest go direct.");
|
|
186
187
|
}
|
|
187
188
|
function withApiblaze(nextConfig = {}) {
|
|
188
189
|
register();
|
package/dist/sidecar/index.mjs
CHANGED
|
@@ -58,14 +58,15 @@ function isPrivateOrLocal(host) {
|
|
|
58
58
|
}
|
|
59
59
|
function register(opts) {
|
|
60
60
|
if (installed) return;
|
|
61
|
+
const quiet = opts?.quiet ?? (process.env.APIBLAZE_SIDECAR_VERBOSE ?? "true").trim().toLowerCase() === "false";
|
|
61
62
|
const off = opts?.enabled === false || opts?.enabled === void 0 && OFF_VALUES.has((process.env.APIBLAZE_SIDECAR ?? "").trim().toLowerCase());
|
|
62
63
|
if (off) {
|
|
63
|
-
if (!
|
|
64
|
+
if (!quiet) console.log("[apiblaze/sidecar] off (APIBLAZE_SIDECAR=off) \u2014 fetches go direct.");
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
const token = opts?.token ?? process.env.APIBLAZE_API_KEY ?? process.env.APIBLAZE_TOKEN;
|
|
67
68
|
if (!token) {
|
|
68
|
-
if (!
|
|
69
|
+
if (!quiet) console.log("[apiblaze/sidecar] off (no APIBLAZE_API_KEY set) \u2014 fetches go direct.");
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
72
|
const original = globalThis.fetch;
|
|
@@ -119,7 +120,7 @@ function register(opts) {
|
|
|
119
120
|
if (base) {
|
|
120
121
|
if (!seen.has(origin)) {
|
|
121
122
|
seen.add(origin);
|
|
122
|
-
if (!
|
|
123
|
+
if (!quiet) console.log(`[apiblaze/sidecar] routed \u2192 ${origin}`);
|
|
123
124
|
}
|
|
124
125
|
const isReq = input instanceof Request;
|
|
125
126
|
const headers = new Headers(isReq ? input.headers : void 0);
|
|
@@ -142,21 +143,21 @@ function register(opts) {
|
|
|
142
143
|
}
|
|
143
144
|
if (!seen.has(origin)) {
|
|
144
145
|
seen.add(origin);
|
|
145
|
-
if (!
|
|
146
|
+
if (!quiet) console.log(`[apiblaze/sidecar] direct (not approved) \u2192 ${origin} \xB7 approve to route it: npx apiblaze sidecar approve ${url.hostname}`);
|
|
146
147
|
reportObserved(origin);
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
151
|
}
|
|
151
152
|
} catch (err) {
|
|
152
|
-
if (!
|
|
153
|
+
if (!quiet) console.warn("[apiblaze/sidecar] passthrough after sidecar error:", err?.message);
|
|
153
154
|
}
|
|
154
155
|
return original(input, init);
|
|
155
156
|
};
|
|
156
157
|
wrapped.__apiblaze = true;
|
|
157
158
|
globalThis.fetch = wrapped;
|
|
158
159
|
installed = true;
|
|
159
|
-
if (!
|
|
160
|
+
if (!quiet) console.log("[apiblaze/sidecar] active \u2014 approved origins route through APIblaze; the rest go direct.");
|
|
160
161
|
}
|
|
161
162
|
function withApiblaze(nextConfig = {}) {
|
|
162
163
|
register();
|
package/package.json
CHANGED