apiblaze 0.7.2 → 0.9.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 +174 -172
  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"() {
@@ -95,7 +99,6 @@ var api_exports = {};
95
99
  __export(api_exports, {
96
100
  agentCall: () => agentCall,
97
101
  checkProxyName: () => checkProxyName,
98
- claimProxy: () => claimProxy,
99
102
  claimTeam: () => claimTeam,
100
103
  createProxy: () => createProxy,
101
104
  createProxyAnonymous: () => createProxyAnonymous,
@@ -104,13 +107,12 @@ __export(api_exports, {
104
107
  getProjects: () => getProjects,
105
108
  getTeams: () => getTeams,
106
109
  putDevTunnel: () => putDevTunnel,
107
- sidecarApproveAnonymous: () => sidecarApproveAnonymous,
108
110
  sidecarInitAnonymous: () => sidecarInitAnonymous
109
111
  });
110
- async function createProxyAnonymous(body, anonSession) {
112
+ async function createProxyAnonymous(body) {
111
113
  const res = await fetch(`${PUBLIC_API_BASE}/proxy`, {
112
114
  method: "POST",
113
- headers: { "Content-Type": "application/json", ...anonSession ? { "X-Abz-Anon-Session": anonSession } : {} },
115
+ headers: { "Content-Type": "application/json" },
114
116
  body: JSON.stringify(body)
115
117
  });
116
118
  if (!res.ok) {
@@ -124,9 +126,9 @@ async function createProxyAnonymous(body, anonSession) {
124
126
  }
125
127
  return res.json();
126
128
  }
127
- async function apiFetch(path6, options = {}) {
129
+ async function apiFetch(path5, options = {}) {
128
130
  const token = getAccessToken();
129
- const url = `${DASHBOARD_BASE}${path6}`;
131
+ const url = `${DASHBOARD_BASE}${path5}`;
130
132
  const res = await fetch(url, {
131
133
  ...options,
132
134
  headers: {
@@ -152,12 +154,12 @@ async function apiFetch(path6, options = {}) {
152
154
  }
153
155
  return res.json();
154
156
  }
155
- async function agentCall(path6, method, body) {
157
+ async function agentCall(path5, method, body) {
156
158
  const token = getAccessToken();
157
159
  const res = await fetch(`${DASHBOARD_BASE}/api/cli/agents`, {
158
160
  method: "POST",
159
161
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
160
- body: JSON.stringify({ path: path6, method, body })
162
+ body: JSON.stringify({ path: path5, method, body })
161
163
  });
162
164
  let data = null;
163
165
  try {
@@ -191,38 +193,22 @@ async function createProxy(payload) {
191
193
  body: JSON.stringify(payload)
192
194
  });
193
195
  }
194
- async function claimProxy(claimCode, teamId) {
195
- return apiFetch("/api/cli/claim", {
196
- method: "POST",
197
- body: JSON.stringify({ claimCode, team_id: teamId })
198
- });
199
- }
200
- async function claimTeam(code) {
196
+ async function claimTeam(code, teamId) {
201
197
  return apiFetch("/api/cli/claim-team", {
202
198
  method: "POST",
203
- body: JSON.stringify({ code })
199
+ body: JSON.stringify({ code, ...teamId ? { team_id: teamId } : {} })
204
200
  });
205
201
  }
206
- async function sidecarInitAnonymous(anonSession) {
202
+ async function sidecarInitAnonymous() {
207
203
  const res = await fetch(`${PUBLIC_API_BASE}/sidecar/init`, {
208
204
  method: "POST",
209
- headers: { "content-type": "application/json", ...anonSession ? { "X-Abz-Anon-Session": anonSession } : {} },
205
+ headers: { "content-type": "application/json" },
210
206
  body: "{}"
211
207
  });
212
208
  const data = await res.json().catch(() => ({}));
213
209
  if (!res.ok) throw new ApiError(res.status, data?.error ?? "init_failed", data);
214
210
  return data;
215
211
  }
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
212
  async function putDevTunnel(payload) {
227
213
  return apiFetch("/api/cli/dev-tunnel", {
228
214
  method: "PUT",
@@ -246,49 +232,71 @@ var init_api = __esm({
246
232
  }
247
233
  });
248
234
 
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
235
+ // src/lib/anon-cred.ts
236
+ var anon_cred_exports = {};
237
+ __export(anon_cred_exports, {
238
+ clearAnonCred: () => clearAnonCred,
239
+ cpFetch: () => cpFetch,
240
+ loadAnonCred: () => loadAnonCred,
241
+ saveAnonCred: () => saveAnonCred
255
242
  });
256
- function loadAnonSession() {
243
+ function loadAnonCred() {
257
244
  try {
258
- const s = JSON.parse(fs3.readFileSync(SESSION_PATH, "utf8"));
259
- return s?.anon_session ? s : null;
245
+ const c = JSON.parse(fs2.readFileSync(FILE, "utf8"));
246
+ return c?.cp_key ? c : null;
260
247
  } catch {
261
248
  return null;
262
249
  }
263
250
  }
264
- function saveAnonSession(anon_session, claim_code) {
251
+ function saveAnonCred(cp_key, team_id, claim_code) {
265
252
  try {
266
- fs3.mkdirSync(DIR, { recursive: true });
267
- const prev = loadAnonSession();
253
+ fs2.mkdirSync(DIR, { recursive: true });
254
+ const prev = loadAnonCred();
268
255
  const merged = {
269
- anon_session,
256
+ cp_key,
257
+ team_id,
270
258
  claim_code: claim_code ?? prev?.claim_code,
271
259
  created_at: prev?.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
272
260
  };
273
- fs3.writeFileSync(SESSION_PATH, JSON.stringify(merged, null, 2));
261
+ fs2.writeFileSync(FILE, JSON.stringify(merged, null, 2));
262
+ } catch {
263
+ }
264
+ }
265
+ function clearAnonCred() {
266
+ try {
267
+ fs2.unlinkSync(FILE);
274
268
  } catch {
275
269
  }
276
270
  }
277
- function clearAnonSession() {
271
+ async function cpFetch(cpKey, apiPath, opts = {}) {
272
+ const res = await fetch(`${CP_EDGE}${apiPath}`, {
273
+ ...opts,
274
+ headers: { "Content-Type": "application/json", "X-API-Key": cpKey, ...opts.headers ?? {} }
275
+ });
276
+ const text = await res.text();
277
+ let parsed;
278
278
  try {
279
- fs3.unlinkSync(SESSION_PATH);
279
+ parsed = text ? JSON.parse(text) : void 0;
280
280
  } catch {
281
+ parsed = text;
282
+ }
283
+ if (!res.ok) {
284
+ const msg = parsed && typeof parsed === "object" && (parsed.details ?? parsed.error) || res.statusText;
285
+ throw new ApiError(res.status, typeof msg === "string" ? msg : JSON.stringify(msg), parsed);
281
286
  }
287
+ return parsed;
282
288
  }
283
- var fs3, path2, os2, DIR, SESSION_PATH;
284
- var init_anon_session = __esm({
285
- "src/lib/anon-session.ts"() {
289
+ var fs2, path2, os2, DIR, FILE, CP_EDGE;
290
+ var init_anon_cred = __esm({
291
+ "src/lib/anon-cred.ts"() {
286
292
  "use strict";
287
- fs3 = __toESM(require("fs"));
293
+ fs2 = __toESM(require("fs"));
288
294
  path2 = __toESM(require("path"));
289
295
  os2 = __toESM(require("os"));
296
+ init_types();
290
297
  DIR = path2.join(os2.homedir(), ".apiblaze");
291
- SESSION_PATH = path2.join(DIR, "anon.json");
298
+ FILE = path2.join(DIR, "anon.json");
299
+ 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
300
  }
293
301
  });
294
302
 
@@ -297,7 +305,7 @@ var import_commander = require("commander");
297
305
  var import_chalk30 = __toESM(require("chalk"));
298
306
 
299
307
  // package.json
300
- var version = "0.7.2";
308
+ var version = "0.9.0";
301
309
 
302
310
  // src/index.ts
303
311
  init_types();
@@ -438,6 +446,37 @@ ${import_chalk2.default.cyan("\u2192")} Team: ${import_chalk2.default.bold(teamN
438
446
  teamName
439
447
  });
440
448
  console.log(import_chalk2.default.green("\n\u2714 Logged in successfully!"));
449
+ await offerClaimPendingAnon();
450
+ }
451
+ async function offerClaimPendingAnon() {
452
+ const { loadAnonCred: loadAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
453
+ const cred = loadAnonCred2();
454
+ if (!cred?.claim_code) return;
455
+ let doClaim = true;
456
+ if (process.stdin.isTTY) {
457
+ const { default: inquirer2 } = await import("inquirer");
458
+ const { yes } = await inquirer2.prompt([{
459
+ type: "confirm",
460
+ name: "yes",
461
+ message: "You created proxies anonymously before logging in. Claim them into this account?",
462
+ default: true
463
+ }]);
464
+ doClaim = yes;
465
+ }
466
+ if (!doClaim) {
467
+ console.log(import_chalk2.default.dim(" Left unclaimed \u2014 run `apiblaze claim` anytime to keep them (they GC after inactivity)."));
468
+ return;
469
+ }
470
+ try {
471
+ const { claimTeam: claimTeam2 } = await Promise.resolve().then(() => (init_api(), api_exports));
472
+ const t = await claimTeam2(cred.claim_code);
473
+ clearAnonCred2();
474
+ console.log(import_chalk2.default.green(` \u2714 Claimed your anonymous proxies into your account (team ${import_chalk2.default.bold(t.team_id)}).`));
475
+ } catch (err) {
476
+ const { ApiError: ApiError2 } = await Promise.resolve().then(() => (init_types(), types_exports));
477
+ const why = err instanceof ApiError2 ? err.message : err instanceof Error ? err.message : "error";
478
+ console.log(import_chalk2.default.yellow(` Couldn't auto-claim (${why}). Run \`apiblaze claim\` to retry.`));
479
+ }
441
480
  }
442
481
 
443
482
  // src/commands/dev.ts
@@ -541,11 +580,11 @@ function decodeJwt(token) {
541
580
  return null;
542
581
  }
543
582
  }
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);
583
+ function maskPath(path5) {
584
+ const q = path5.indexOf("?");
585
+ if (q < 0) return path5;
586
+ const base = path5.slice(0, q);
587
+ const query = path5.slice(q + 1);
549
588
  const masked = query.split("&").map((pair) => {
550
589
  const eq = pair.indexOf("=");
551
590
  if (eq < 0) return pair;
@@ -1470,19 +1509,28 @@ async function runAnonymousCreate(opts) {
1470
1509
  if (opts.displayName) body.display_name = opts.displayName;
1471
1510
  if (opts.apiversion) body.api_version = opts.apiversion;
1472
1511
  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;
1512
+ const { loadAnonCred: loadAnonCred2, saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2, cpFetch: cpFetch2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
1513
+ if (opts.newSession) clearAnonCred2();
1514
+ const cred = loadAnonCred2();
1515
+ const spinner = !opts.json ? (0, import_ora4.default)(cred ? "Creating proxy (in your anonymous workspace)..." : "Creating proxy...").start() : null;
1477
1516
  let result;
1478
1517
  try {
1479
- result = await createProxyAnonymous(body, prior?.anon_session);
1518
+ if (cred) {
1519
+ result = await cpFetch2(cred.cp_key, "/projects", { method: "POST", body: JSON.stringify(body) });
1520
+ if (Array.isArray(result.endpoints)) {
1521
+ result.endpoints = result.endpoints.map((e) => e.replace(/:\/\/[^/]+/, `://${result.project_id}.tryabz.run`));
1522
+ }
1523
+ } else {
1524
+ result = await createProxyAnonymous(body);
1525
+ if (result.cp_key && result.team_id) {
1526
+ saveAnonCred2(result.cp_key, result.team_id, result.claim_code);
1527
+ }
1528
+ }
1480
1529
  spinner?.succeed(import_chalk6.default.green("Proxy created!"));
1481
1530
  } catch (err) {
1482
1531
  spinner?.fail("Failed to create proxy.");
1483
1532
  throw err;
1484
1533
  }
1485
- if (result.anon_session) saveAnonSession2(result.anon_session, result.team_claim_code);
1486
1534
  const version2 = result.api_version || "1.0.0";
1487
1535
  const keys = result.api_keys ?? {};
1488
1536
  const apiKey = result.apiKey ?? keys.prod ?? Object.values(keys)[0];
@@ -1509,12 +1557,13 @@ async function runAnonymousCreate(opts) {
1509
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."));
1510
1558
  }
1511
1559
  if (prodEndpoint) printCurlExample(prodEndpoint, opts.auth || "api_key", apiKey, result.portal);
1512
- if (result.team_claim_code) {
1560
+ const claimCode = result.claim_code || cred?.claim_code;
1561
+ if (claimCode) {
1513
1562
  console.log();
1514
- 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}`));
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)`));
1518
1567
  } else if (result.claim_url) {
1519
1568
  console.log();
1520
1569
  console.log(` ${import_chalk6.default.yellow("\u26A0 Anonymous proxy \u2014 claim it to your account within 30 days or it expires:")}`);
@@ -1526,7 +1575,7 @@ async function runAnonymousCreate(opts) {
1526
1575
  // src/commands/claim.ts
1527
1576
  var import_chalk7 = __toESM(require("chalk"));
1528
1577
  init_auth();
1529
- init_anon_session();
1578
+ init_anon_cred();
1530
1579
  init_api();
1531
1580
  init_types();
1532
1581
  function fail2(message) {
@@ -1535,100 +1584,55 @@ function fail2(message) {
1535
1584
  }
1536
1585
  async function runClaim(claimCodeArg, opts) {
1537
1586
  const creds = loadCredentials();
1538
- if (!creds) {
1539
- fail2("Not logged in. Run `apiblaze login` first, then claim.");
1540
- }
1587
+ if (!creds) fail2("Not logged in. Run `apiblaze login` first, then claim.");
1541
1588
  let claimCode = (claimCodeArg ?? "").trim();
1542
- let fromLocalSession = false;
1589
+ let fromLocal = false;
1543
1590
  if (!claimCode) {
1544
- const sess = loadAnonSession();
1545
- if (sess?.claim_code) {
1546
- claimCode = sess.claim_code;
1547
- fromLocalSession = true;
1591
+ const c = loadAnonCred();
1592
+ if (c?.claim_code) {
1593
+ claimCode = c.claim_code;
1594
+ fromLocal = true;
1548
1595
  }
1549
1596
  }
1550
1597
  if (!claimCode && process.stdin.isTTY) {
1551
1598
  const { default: inquirer2 } = await import("inquirer");
1552
- const { code } = await inquirer2.prompt([{
1553
- type: "input",
1554
- name: "code",
1555
- message: "Claim code (from the create output / claim URL):"
1556
- }]);
1599
+ const { code } = await inquirer2.prompt([{ type: "input", name: "code", message: "Claim code:" }]);
1557
1600
  claimCode = (code ?? "").trim();
1558
1601
  }
1559
- if (!claimCode) {
1560
- fail2("Nothing to claim on this machine. Run `apiblaze claim <code>` with a code, or `apiblaze create`/`init` first.");
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;
1561
1609
  }
1610
+ let res;
1562
1611
  try {
1563
- const t = await claimTeam(claimCode);
1564
- if (fromLocalSession) clearAnonSession();
1565
- if (opts.json) {
1566
- console.log(JSON.stringify(t, null, 2));
1567
- return;
1568
- }
1569
- console.log(import_chalk7.default.green(`
1570
- \u2714 Claimed the whole team into your account.`));
1571
- console.log(` Team: ${import_chalk7.default.bold(t.team_id)}`);
1572
- console.log(` Its proxies + keys are now yours. Switch to it with ${import_chalk7.default.cyan(`apiblaze team ${t.team_id}`)}.`);
1573
- console.log(`
1574
- Manage it at ${import_chalk7.default.cyan("https://dashboard.apiblaze.com/dashboard")}`);
1575
- return;
1612
+ res = await claimTeam(claimCode, targetTeamId);
1576
1613
  } catch (err) {
1577
- if (err instanceof ApiError && err.status !== 404) {
1578
- const code = typeof err.body === "object" && err.body ? err.body.error : void 0;
1579
- if (code === "already_claimed") fail2("That claim code has already been used.");
1580
- if (code === "expired") fail2("That claim code has expired. Create a fresh setup with `apiblaze init`.");
1581
- if (code === "not_claimable") fail2("That team can no longer be claimed (it already belongs to an account).");
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}".`);
1582
1621
  fail2(`Could not claim: ${err.message}`);
1583
1622
  }
1584
- }
1585
- const teams = await getTeams().catch(() => []);
1586
- if (teams.length === 0) {
1587
- fail2("No teams found for your account.");
1588
- }
1589
- let teamId;
1590
- if (opts.team) {
1591
- const match = teams.find(
1592
- (t) => t.teamId === opts.team || t.name.toLowerCase() === opts.team.toLowerCase()
1593
- );
1594
- if (!match) {
1595
- fail2(`Team "${opts.team}" not found. Available: ${teams.map((t) => t.name).join(", ")}.`);
1596
- }
1597
- teamId = match.teamId;
1598
- } else if (creds.teamId && teams.some((t) => t.teamId === creds.teamId)) {
1599
- teamId = creds.teamId;
1600
- } else if (teams.length === 1) {
1601
- teamId = teams[0].teamId;
1602
- } else if (process.stdin.isTTY) {
1603
- const { default: inquirer2 } = await import("inquirer");
1604
- const { picked } = await inquirer2.prompt([{
1605
- type: "list",
1606
- name: "picked",
1607
- message: "Claim into which team?",
1608
- choices: teams.map((t) => ({ name: t.name, value: t.teamId }))
1609
- }]);
1610
- teamId = picked;
1611
- } else {
1612
- fail2(`Specify a team: \`apiblaze claim ${claimCode} --team <name|id>\`. Available: ${teams.map((t) => t.name).join(", ")}.`);
1613
- }
1614
- const teamName = teams.find((t) => t.teamId === teamId)?.name ?? teamId;
1615
- let result;
1616
- try {
1617
- result = await claimProxy(claimCode, teamId);
1618
- } catch (err) {
1619
- if (err instanceof ApiError) fail2(`That claim code isn't valid \u2014 it may be mistyped, already claimed, or expired.`);
1620
1623
  throw err;
1621
1624
  }
1625
+ if (fromLocal) clearAnonCred();
1622
1626
  if (opts.json) {
1623
- console.log(JSON.stringify(result, null, 2));
1627
+ console.log(JSON.stringify(res, null, 2));
1624
1628
  return;
1625
1629
  }
1626
- console.log(import_chalk7.default.green(`
1627
- \u2714 Claimed into ${import_chalk7.default.bold(teamName)}.`));
1628
- if (result.project_id) console.log(` Project: ${import_chalk7.default.bold(result.project_id)}`);
1629
- if (result.endpoints?.length) {
1630
- console.log(" Endpoints:");
1631
- for (const e of result.endpoints) console.log(` ${e}`);
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.)`));
1632
1636
  }
1633
1637
  console.log(`
1634
1638
  Manage it at ${import_chalk7.default.cyan("https://dashboard.apiblaze.com/dashboard")}`);
@@ -3358,19 +3362,18 @@ function generateInspector(root, router) {
3358
3362
  }
3359
3363
  async function runAnonymousInit(root, router, opts) {
3360
3364
  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();
3365
+ const { saveAnonCred: saveAnonCred2, clearAnonCred: clearAnonCred2 } = await Promise.resolve().then(() => (init_anon_cred(), anon_cred_exports));
3366
+ if (opts.newSession) clearAnonCred2();
3367
+ const spinner = (0, import_ora13.default)("Setting up a sidecar (no login needed)...").start();
3365
3368
  let out;
3366
3369
  try {
3367
- out = await sidecarInitAnonymous2(prior?.anon_session);
3370
+ out = await sidecarInitAnonymous2();
3368
3371
  spinner.succeed("Sidecar ready (anonymous trial).");
3369
3372
  } catch (err) {
3370
3373
  spinner.fail("Setup failed.");
3371
3374
  throw err;
3372
3375
  }
3373
- if (out.anon_session) saveAnonSession2(out.anon_session, out.claim_code);
3376
+ if (out.cp_key && out.team_id) saveAnonCred2(out.cp_key, out.team_id, out.claim_code);
3374
3377
  const envState = upsertEnvLocal(root, out.token);
3375
3378
  ensureGitignored(root);
3376
3379
  console.log(` ${import_chalk28.default.green("\u2713")} .env.local ${envState} (APIBLAZE_API_KEY) \u2014 gitignored`);
@@ -3463,26 +3466,25 @@ async function runSidecar(opts) {
3463
3466
  // src/commands/origins.ts
3464
3467
  var import_chalk29 = __toESM(require("chalk"));
3465
3468
  var import_ora14 = __toESM(require("ora"));
3466
- var fs8 = __toESM(require("fs"));
3467
- var path5 = __toESM(require("path"));
3468
3469
  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
- }
3470
+ init_anon_cred();
3479
3471
  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
- });
3472
+ let out;
3473
+ if (!loadCredentials()) {
3474
+ const cred = loadAnonCred();
3475
+ if (!cred) {
3476
+ console.log(import_chalk29.default.yellow("No anonymous workspace here. Run `apiblaze init` first."));
3477
+ return;
3478
+ }
3479
+ out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/candidates`, { method: "GET" });
3480
+ } else {
3481
+ const { teamId, teamName } = await resolveTeam(opts.team);
3482
+ out = await admin({
3483
+ method: "GET",
3484
+ path: `/teams/${encodeURIComponent(teamId)}/sidecar/candidates`,
3485
+ summary: `List sidecar origins for team ${teamName ?? teamId}`
3486
+ });
3487
+ }
3486
3488
  if (opts.json) {
3487
3489
  console.log(JSON.stringify(out));
3488
3490
  return;
@@ -3507,14 +3509,14 @@ Candidates \u2014 going direct, not yet approved (${candidates.length})`));
3507
3509
  }
3508
3510
  async function runOriginsApprove(origin, opts) {
3509
3511
  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."));
3512
+ const cred = loadAnonCred();
3513
+ if (!cred) {
3514
+ console.error(import_chalk29.default.red("Not logged in and no anonymous workspace. Run `apiblaze init` first."));
3513
3515
  process.exit(1);
3514
3516
  }
3515
3517
  const spinner2 = (0, import_ora14.default)(`Approving ${origin} (anonymous)...`).start();
3516
3518
  try {
3517
- const out = await sidecarApproveAnonymous(key, origin.replace(/^https?:\/\//, ""));
3519
+ const out = await cpFetch(cred.cp_key, `/teams/${encodeURIComponent(cred.team_id)}/sidecar/approve`, { method: "POST", body: JSON.stringify({ origin }) });
3518
3520
  spinner2.succeed(`Approved ${origin} \u2192 proxy ${out.project_id}. Routing within ~5 min.`);
3519
3521
  } catch (err) {
3520
3522
  spinner2.fail("Approve failed.");
@@ -3631,7 +3633,7 @@ program.command("whoami").description("Show who you are \u2014 both API Producer
3631
3633
  process.exit(1);
3632
3634
  }
3633
3635
  });
3634
- program.command("claim").description("Claim an anonymously-created proxy into one of your teams (requires login)").argument("[code]", "Claim code from `create` output / claim URL (prompted if omitted)").option("--team <id|name>", "Team to claim into (defaults to your active team)").option("--json", "Output machine-readable JSON (non-interactive)").action(async (code, opts) => {
3636
+ 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) => {
3635
3637
  try {
3636
3638
  await runClaim(code, opts);
3637
3639
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.7.2",
3
+ "version": "0.9.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",