apiblaze 0.7.2 → 0.8.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.
Files changed (2) hide show
  1. package/dist/index.js +141 -87
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31,6 +31,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
31
  ));
32
32
 
33
33
  // src/types.ts
34
+ var types_exports = {};
35
+ __export(types_exports, {
36
+ ApiError: () => ApiError
37
+ });
34
38
  var ApiError;
35
39
  var init_types = __esm({
36
40
  "src/types.ts"() {
@@ -104,13 +108,12 @@ __export(api_exports, {
104
108
  getProjects: () => getProjects,
105
109
  getTeams: () => getTeams,
106
110
  putDevTunnel: () => putDevTunnel,
107
- sidecarApproveAnonymous: () => sidecarApproveAnonymous,
108
111
  sidecarInitAnonymous: () => sidecarInitAnonymous
109
112
  });
110
- async function createProxyAnonymous(body, anonSession) {
113
+ async function createProxyAnonymous(body) {
111
114
  const res = await fetch(`${PUBLIC_API_BASE}/proxy`, {
112
115
  method: "POST",
113
- headers: { "Content-Type": "application/json", ...anonSession ? { "X-Abz-Anon-Session": anonSession } : {} },
116
+ headers: { "Content-Type": "application/json" },
114
117
  body: JSON.stringify(body)
115
118
  });
116
119
  if (!res.ok) {
@@ -124,9 +127,9 @@ async function createProxyAnonymous(body, anonSession) {
124
127
  }
125
128
  return res.json();
126
129
  }
127
- async function apiFetch(path6, options = {}) {
130
+ async function apiFetch(path5, options = {}) {
128
131
  const token = getAccessToken();
129
- const url = `${DASHBOARD_BASE}${path6}`;
132
+ const url = `${DASHBOARD_BASE}${path5}`;
130
133
  const res = await fetch(url, {
131
134
  ...options,
132
135
  headers: {
@@ -152,12 +155,12 @@ async function apiFetch(path6, options = {}) {
152
155
  }
153
156
  return res.json();
154
157
  }
155
- async function agentCall(path6, method, body) {
158
+ async function agentCall(path5, method, body) {
156
159
  const token = getAccessToken();
157
160
  const res = await fetch(`${DASHBOARD_BASE}/api/cli/agents`, {
158
161
  method: "POST",
159
162
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
160
- body: JSON.stringify({ path: path6, method, body })
163
+ body: JSON.stringify({ path: path5, method, body })
161
164
  });
162
165
  let data = null;
163
166
  try {
@@ -203,26 +206,16 @@ async function claimTeam(code) {
203
206
  body: JSON.stringify({ code })
204
207
  });
205
208
  }
206
- async function sidecarInitAnonymous(anonSession) {
209
+ async function sidecarInitAnonymous() {
207
210
  const res = await fetch(`${PUBLIC_API_BASE}/sidecar/init`, {
208
211
  method: "POST",
209
- headers: { "content-type": "application/json", ...anonSession ? { "X-Abz-Anon-Session": anonSession } : {} },
212
+ headers: { "content-type": "application/json" },
210
213
  body: "{}"
211
214
  });
212
215
  const data = await res.json().catch(() => ({}));
213
216
  if (!res.ok) throw new ApiError(res.status, data?.error ?? "init_failed", data);
214
217
  return data;
215
218
  }
216
- async function sidecarApproveAnonymous(invokeKey, origin) {
217
- const res = await fetch(`${PUBLIC_API_BASE}/sidecar/approve`, {
218
- method: "POST",
219
- headers: { "content-type": "application/json", "x-abz-sidecar-key": invokeKey },
220
- body: JSON.stringify({ origin })
221
- });
222
- const data = await res.json().catch(() => ({}));
223
- if (!res.ok) throw new ApiError(res.status, data?.detail ?? data?.error ?? "approve_failed", data);
224
- return data;
225
- }
226
219
  async function putDevTunnel(payload) {
227
220
  return apiFetch("/api/cli/dev-tunnel", {
228
221
  method: "PUT",
@@ -246,49 +239,71 @@ var init_api = __esm({
246
239
  }
247
240
  });
248
241
 
249
- // src/lib/anon-session.ts
250
- var anon_session_exports = {};
251
- __export(anon_session_exports, {
252
- clearAnonSession: () => clearAnonSession,
253
- loadAnonSession: () => loadAnonSession,
254
- saveAnonSession: () => saveAnonSession
242
+ // src/lib/anon-cred.ts
243
+ var anon_cred_exports = {};
244
+ __export(anon_cred_exports, {
245
+ clearAnonCred: () => clearAnonCred,
246
+ cpFetch: () => cpFetch,
247
+ loadAnonCred: () => loadAnonCred,
248
+ saveAnonCred: () => saveAnonCred
255
249
  });
256
- function loadAnonSession() {
250
+ function loadAnonCred() {
257
251
  try {
258
- const s = JSON.parse(fs3.readFileSync(SESSION_PATH, "utf8"));
259
- return s?.anon_session ? s : null;
252
+ const c = JSON.parse(fs2.readFileSync(FILE, "utf8"));
253
+ return c?.cp_key ? c : null;
260
254
  } catch {
261
255
  return null;
262
256
  }
263
257
  }
264
- function saveAnonSession(anon_session, claim_code) {
258
+ function saveAnonCred(cp_key, team_id, claim_code) {
265
259
  try {
266
- fs3.mkdirSync(DIR, { recursive: true });
267
- const prev = loadAnonSession();
260
+ fs2.mkdirSync(DIR, { recursive: true });
261
+ const prev = loadAnonCred();
268
262
  const merged = {
269
- anon_session,
263
+ cp_key,
264
+ team_id,
270
265
  claim_code: claim_code ?? prev?.claim_code,
271
266
  created_at: prev?.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
272
267
  };
273
- fs3.writeFileSync(SESSION_PATH, JSON.stringify(merged, null, 2));
268
+ fs2.writeFileSync(FILE, JSON.stringify(merged, null, 2));
274
269
  } catch {
275
270
  }
276
271
  }
277
- function clearAnonSession() {
272
+ function clearAnonCred() {
278
273
  try {
279
- fs3.unlinkSync(SESSION_PATH);
274
+ fs2.unlinkSync(FILE);
280
275
  } catch {
281
276
  }
282
277
  }
283
- var fs3, path2, os2, DIR, SESSION_PATH;
284
- var init_anon_session = __esm({
285
- "src/lib/anon-session.ts"() {
278
+ async function cpFetch(cpKey, apiPath, opts = {}) {
279
+ const res = await fetch(`${CP_EDGE}${apiPath}`, {
280
+ ...opts,
281
+ headers: { "Content-Type": "application/json", "X-API-Key": cpKey, ...opts.headers ?? {} }
282
+ });
283
+ const text = await res.text();
284
+ let parsed;
285
+ try {
286
+ parsed = text ? JSON.parse(text) : void 0;
287
+ } catch {
288
+ parsed = text;
289
+ }
290
+ if (!res.ok) {
291
+ const msg = parsed && typeof parsed === "object" && (parsed.details ?? parsed.error) || res.statusText;
292
+ throw new ApiError(res.status, typeof msg === "string" ? msg : JSON.stringify(msg), parsed);
293
+ }
294
+ return parsed;
295
+ }
296
+ var fs2, path2, os2, DIR, FILE, CP_EDGE;
297
+ var init_anon_cred = __esm({
298
+ "src/lib/anon-cred.ts"() {
286
299
  "use strict";
287
- fs3 = __toESM(require("fs"));
300
+ fs2 = __toESM(require("fs"));
288
301
  path2 = __toESM(require("path"));
289
302
  os2 = __toESM(require("os"));
303
+ init_types();
290
304
  DIR = path2.join(os2.homedir(), ".apiblaze");
291
- SESSION_PATH = path2.join(DIR, "anon.json");
305
+ FILE = path2.join(DIR, "anon.json");
306
+ CP_EDGE = process.env.APIBLAZE_API_BASE ? `${process.env.APIBLAZE_API_BASE}/1.0.0/prod` : "https://api.apiblaze.com/1.0.0/prod";
292
307
  }
293
308
  });
294
309
 
@@ -297,7 +312,7 @@ var import_commander = require("commander");
297
312
  var import_chalk30 = __toESM(require("chalk"));
298
313
 
299
314
  // package.json
300
- var version = "0.7.2";
315
+ var version = "0.8.0";
301
316
 
302
317
  // src/index.ts
303
318
  init_types();
@@ -438,6 +453,37 @@ ${import_chalk2.default.cyan("\u2192")} Team: ${import_chalk2.default.bold(teamN
438
453
  teamName
439
454
  });
440
455
  console.log(import_chalk2.default.green("\n\u2714 Logged in successfully!"));
456
+ await offerClaimPendingAnon();
457
+ }
458
+ async function offerClaimPendingAnon() {
459
+ const { loadAnonCred: loadAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
460
+ const cred = loadAnonCred2();
461
+ if (!cred?.claim_code) return;
462
+ let doClaim = true;
463
+ if (process.stdin.isTTY) {
464
+ const { default: inquirer2 } = await import("inquirer");
465
+ const { yes } = await inquirer2.prompt([{
466
+ type: "confirm",
467
+ name: "yes",
468
+ message: "You created proxies anonymously before logging in. Claim them into this account?",
469
+ default: true
470
+ }]);
471
+ doClaim = yes;
472
+ }
473
+ if (!doClaim) {
474
+ console.log(import_chalk2.default.dim(" Left unclaimed \u2014 run `apiblaze claim` anytime to keep them (they GC after inactivity)."));
475
+ return;
476
+ }
477
+ try {
478
+ const { claimTeam: claimTeam2 } = await Promise.resolve().then(() => (init_api(), api_exports));
479
+ const t = await claimTeam2(cred.claim_code);
480
+ clearAnonCred2();
481
+ console.log(import_chalk2.default.green(` \u2714 Claimed your anonymous proxies into your account (team ${import_chalk2.default.bold(t.team_id)}).`));
482
+ } catch (err) {
483
+ const { ApiError: ApiError2 } = await Promise.resolve().then(() => (init_types(), types_exports));
484
+ const why = err instanceof ApiError2 ? err.message : err instanceof Error ? err.message : "error";
485
+ console.log(import_chalk2.default.yellow(` Couldn't auto-claim (${why}). Run \`apiblaze claim\` to retry.`));
486
+ }
441
487
  }
442
488
 
443
489
  // src/commands/dev.ts
@@ -541,11 +587,11 @@ function decodeJwt(token) {
541
587
  return null;
542
588
  }
543
589
  }
544
- function maskPath(path6) {
545
- const q = path6.indexOf("?");
546
- if (q < 0) return path6;
547
- const base = path6.slice(0, q);
548
- const query = path6.slice(q + 1);
590
+ function maskPath(path5) {
591
+ const q = path5.indexOf("?");
592
+ if (q < 0) return path5;
593
+ const base = path5.slice(0, q);
594
+ const query = path5.slice(q + 1);
549
595
  const masked = query.split("&").map((pair) => {
550
596
  const eq = pair.indexOf("=");
551
597
  if (eq < 0) return pair;
@@ -1470,19 +1516,28 @@ async function runAnonymousCreate(opts) {
1470
1516
  if (opts.displayName) body.display_name = opts.displayName;
1471
1517
  if (opts.apiversion) body.api_version = opts.apiversion;
1472
1518
  if (opts.auth && opts.auth !== "api_key") body.auth_type = opts.auth;
1473
- const { loadAnonSession: loadAnonSession2, saveAnonSession: saveAnonSession2, clearAnonSession: clearAnonSession2 } = await Promise.resolve().then(() => (init_anon_session(), anon_session_exports));
1474
- if (opts.newSession) clearAnonSession2();
1475
- const prior = loadAnonSession2();
1476
- const spinner = !opts.json ? (0, import_ora4.default)(prior ? "Creating proxy (adding to your anonymous session)..." : "Creating proxy...").start() : null;
1519
+ const { loadAnonCred: loadAnonCred2, saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2, cpFetch: cpFetch2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
1520
+ if (opts.newSession) clearAnonCred2();
1521
+ const cred = loadAnonCred2();
1522
+ const spinner = !opts.json ? (0, import_ora4.default)(cred ? "Creating proxy (in your anonymous workspace)..." : "Creating proxy...").start() : null;
1477
1523
  let result;
1478
1524
  try {
1479
- result = await createProxyAnonymous(body, prior?.anon_session);
1525
+ if (cred) {
1526
+ result = await cpFetch2(cred.cp_key, "/projects", { method: "POST", body: JSON.stringify(body) });
1527
+ if (Array.isArray(result.endpoints)) {
1528
+ result.endpoints = result.endpoints.map((e) => e.replace(/:\/\/[^/]+/, `://${result.project_id}.tryabz.run`));
1529
+ }
1530
+ } else {
1531
+ result = await createProxyAnonymous(body);
1532
+ if (result.cp_key && result.team_id) {
1533
+ saveAnonCred2(result.cp_key, result.team_id, result.team_claim_code);
1534
+ }
1535
+ }
1480
1536
  spinner?.succeed(import_chalk6.default.green("Proxy created!"));
1481
1537
  } catch (err) {
1482
1538
  spinner?.fail("Failed to create proxy.");
1483
1539
  throw err;
1484
1540
  }
1485
- if (result.anon_session) saveAnonSession2(result.anon_session, result.team_claim_code);
1486
1541
  const version2 = result.api_version || "1.0.0";
1487
1542
  const keys = result.api_keys ?? {};
1488
1543
  const apiKey = result.apiKey ?? keys.prod ?? Object.values(keys)[0];
@@ -1509,12 +1564,13 @@ async function runAnonymousCreate(opts) {
1509
1564
  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."));
1510
1565
  }
1511
1566
  if (prodEndpoint) printCurlExample(prodEndpoint, opts.auth || "api_key", apiKey, result.portal);
1512
- if (result.team_claim_code) {
1567
+ const claimCode = result.team_claim_code || cred?.claim_code;
1568
+ if (claimCode) {
1513
1569
  console.log();
1514
1570
  console.log(` ${import_chalk6.default.yellow("\u26A0 Anonymous \u2014 claim within 30 days or it expires.")} All your anonymous proxies`);
1515
- console.log(` on this machine share ONE team. To keep them all:`);
1516
- console.log(` ${import_chalk6.default.cyan("apiblaze login")} then ${import_chalk6.default.cyan("apiblaze claim")} ${import_chalk6.default.dim("(no code needed here)")}`);
1517
- console.log(import_chalk6.default.dim(` From another machine: apiblaze claim ${result.team_claim_code}`));
1571
+ console.log(` on this machine share ONE workspace. To keep them all:`);
1572
+ console.log(` ${import_chalk6.default.cyan("apiblaze login")} ${import_chalk6.default.dim("(prompts to claim them into your account)")}`);
1573
+ console.log(import_chalk6.default.dim(` From another machine: apiblaze claim ${claimCode}`));
1518
1574
  } else if (result.claim_url) {
1519
1575
  console.log();
1520
1576
  console.log(` ${import_chalk6.default.yellow("\u26A0 Anonymous proxy \u2014 claim it to your account within 30 days or it expires:")}`);
@@ -1526,7 +1582,7 @@ async function runAnonymousCreate(opts) {
1526
1582
  // src/commands/claim.ts
1527
1583
  var import_chalk7 = __toESM(require("chalk"));
1528
1584
  init_auth();
1529
- init_anon_session();
1585
+ init_anon_cred();
1530
1586
  init_api();
1531
1587
  init_types();
1532
1588
  function fail2(message) {
@@ -1541,7 +1597,7 @@ async function runClaim(claimCodeArg, opts) {
1541
1597
  let claimCode = (claimCodeArg ?? "").trim();
1542
1598
  let fromLocalSession = false;
1543
1599
  if (!claimCode) {
1544
- const sess = loadAnonSession();
1600
+ const sess = loadAnonCred();
1545
1601
  if (sess?.claim_code) {
1546
1602
  claimCode = sess.claim_code;
1547
1603
  fromLocalSession = true;
@@ -1561,7 +1617,7 @@ async function runClaim(claimCodeArg, opts) {
1561
1617
  }
1562
1618
  try {
1563
1619
  const t = await claimTeam(claimCode);
1564
- if (fromLocalSession) clearAnonSession();
1620
+ if (fromLocalSession) clearAnonCred();
1565
1621
  if (opts.json) {
1566
1622
  console.log(JSON.stringify(t, null, 2));
1567
1623
  return;
@@ -3358,19 +3414,18 @@ function generateInspector(root, router) {
3358
3414
  }
3359
3415
  async function runAnonymousInit(root, router, opts) {
3360
3416
  const { sidecarInitAnonymous: sidecarInitAnonymous2 } = await Promise.resolve().then(() => (init_api(), api_exports));
3361
- const { loadAnonSession: loadAnonSession2, saveAnonSession: saveAnonSession2, clearAnonSession: clearAnonSession2 } = await Promise.resolve().then(() => (init_anon_session(), anon_session_exports));
3362
- if (opts.newSession) clearAnonSession2();
3363
- const prior = loadAnonSession2();
3364
- const spinner = (0, import_ora13.default)(prior ? "Adding to your anonymous session..." : "Setting up a sidecar (no login needed)...").start();
3417
+ const { saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
3418
+ if (opts.newSession) clearAnonCred2();
3419
+ const spinner = (0, import_ora13.default)("Setting up a sidecar (no login needed)...").start();
3365
3420
  let out;
3366
3421
  try {
3367
- out = await sidecarInitAnonymous2(prior?.anon_session);
3422
+ out = await sidecarInitAnonymous2();
3368
3423
  spinner.succeed("Sidecar ready (anonymous trial).");
3369
3424
  } catch (err) {
3370
3425
  spinner.fail("Setup failed.");
3371
3426
  throw err;
3372
3427
  }
3373
- if (out.anon_session) saveAnonSession2(out.anon_session, out.claim_code);
3428
+ if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
3374
3429
  const envState = upsertEnvLocal(root, out.token);
3375
3430
  ensureGitignored(root);
3376
3431
  console.log(` ${import_chalk28.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
@@ -3463,26 +3518,25 @@ async function runSidecar(opts) {
3463
3518
  // src/commands/origins.ts
3464
3519
  var import_chalk29 = __toESM(require("chalk"));
3465
3520
  var import_ora14 = __toESM(require("ora"));
3466
- var fs8 = __toESM(require("fs"));
3467
- var path5 = __toESM(require("path"));
3468
3521
  init_auth();
3469
- init_api();
3470
- function readEnvKey2() {
3471
- try {
3472
- const s = fs8.readFileSync(path5.join(process.cwd(), ".env.local"), "utf8");
3473
- const m = s.match(/^APIBLAZE_API_KEY=(.+)$/m) ?? s.match(/^APIBLAZE_TOKEN=(.+)$/m);
3474
- return m ? m[1].trim() : null;
3475
- } catch {
3476
- return null;
3477
- }
3478
- }
3522
+ init_anon_cred();
3479
3523
  async function runOriginsList(opts) {
3480
- const { teamId, teamName } = await resolveTeam(opts.team);
3481
- const out = await admin({
3482
- method: "GET",
3483
- path: `/teams/${encodeURIComponent(teamId)}/sidecar/candidates`,
3484
- summary: `List sidecar origins for team ${teamName ?? teamId}`
3485
- });
3524
+ let out;
3525
+ if (!loadCredentials()) {
3526
+ const cred = loadAnonCred();
3527
+ if (!cred) {
3528
+ console.log(import_chalk29.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
3529
+ return;
3530
+ }
3531
+ out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
3532
+ } else {
3533
+ const { teamId, teamName } = await resolveTeam(opts.team);
3534
+ out = await admin({
3535
+ method: "GET",
3536
+ path: `/teams/${encodeURIComponent(teamId)}/sidecar/candidates`,
3537
+ summary: `List sidecar origins for team ${teamName ?? teamId}`
3538
+ });
3539
+ }
3486
3540
  if (opts.json) {
3487
3541
  console.log(JSON.stringify(out));
3488
3542
  return;
@@ -3507,14 +3561,14 @@ Candidates \u2014 going direct, not yet approved (${candidates.length})`));
3507
3561
  }
3508
3562
  async function runOriginsApprove(origin, opts) {
3509
3563
  if (!loadCredentials()) {
3510
- const key = readEnvKey2();
3511
- if (!key) {
3512
- console.error(import_chalk29.default.red("Not logged in and no .env.local APIBLAZE_API_KEY found. Run `apiblaze init` first."));
3564
+ const cred = loadAnonCred();
3565
+ if (!cred) {
3566
+ console.error(import_chalk29.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
3513
3567
  process.exit(1);
3514
3568
  }
3515
3569
  const spinner2 = (0, import_ora14.default)(`Approving ${origin} (anonymous)...`).start();
3516
3570
  try {
3517
- const out = await sidecarApproveAnonymous(key, origin.replace(/^https?:\/\//, ""));
3571
+ const out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/approve`, { method: "POST", body: JSON.stringify({ origin }) });
3518
3572
  spinner2.succeed(`Approved ${origin} \u2192 proxy ${out.project_id}. Routing within ~5 min.`);
3519
3573
  } catch (err) {
3520
3574
  spinner2.fail("Approve failed.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "APIblaze CLI + sidecar — manage API proxies, run dev tunnels, and route a Next.js app's egress through APIblaze with one command",
5
5
  "keywords": [
6
6
  "apiblaze",