apiblaze 0.21.63 → 0.21.65

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 +150 -64
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ var __toESM = (mod, isNodeMode, target2) => (target2 = mod != null ? __create(__
34
34
  var version;
35
35
  var init_package = __esm({
36
36
  "package.json"() {
37
- version = "0.21.63";
37
+ version = "0.21.65";
38
38
  }
39
39
  });
40
40
 
@@ -5351,6 +5351,9 @@ function parseYesNo(flag, v) {
5351
5351
  }
5352
5352
  function directoryBodyFromFlags(f2) {
5353
5353
  const m = {};
5354
+ for (const [flag, v] of [["--privacy-url", f2.privacyUrl], ["--docs-url", f2.docsUrl], ["--icon-url", f2.iconUrl]]) {
5355
+ if (v && !/^https:\/\//i.test(v.trim())) throw new Error(`${flag} must be an https URL (got ${v.trim()}).`);
5356
+ }
5354
5357
  if (f2.privacyUrl) m.privacy_url = f2.privacyUrl;
5355
5358
  if (f2.support) m.support_contact = f2.support;
5356
5359
  if (f2.docsUrl) {
@@ -7069,7 +7072,7 @@ __export(agent_exports, {
7069
7072
  });
7070
7073
  async function callAgent(messages, teamId) {
7071
7074
  const token = getAccessToken();
7072
- const res = await fetch(`${DASHBOARD_BASE6}/api/cli/agent`, {
7075
+ const res = await fetch(`${DASHBOARD_BASE7}/api/cli/agent`, {
7073
7076
  method: "POST",
7074
7077
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
7075
7078
  body: JSON.stringify({ messages: messages.slice(-20), tools: toolCatalogue(), team_id: teamId })
@@ -7164,7 +7167,7 @@ async function runAgent(opts) {
7164
7167
  }
7165
7168
  console.log(import_chalk25.default.dim("\nBye."));
7166
7169
  }
7167
- var import_chalk25, import_ora9, DASHBOARD_BASE6, MAX_TOOL_STEPS;
7170
+ var import_chalk25, import_ora9, DASHBOARD_BASE7, MAX_TOOL_STEPS;
7168
7171
  var init_agent = __esm({
7169
7172
  "src/commands/agent.ts"() {
7170
7173
  "use strict";
@@ -7178,7 +7181,7 @@ var init_agent = __esm({
7178
7181
  init_types();
7179
7182
  init_problem();
7180
7183
  init_brand();
7181
- DASHBOARD_BASE6 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
7184
+ DASHBOARD_BASE7 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
7182
7185
  MAX_TOOL_STEPS = 6;
7183
7186
  }
7184
7187
  });
@@ -7716,7 +7719,7 @@ var init_exercise = __esm({
7716
7719
  // src/commands/connector-exercise.ts
7717
7720
  var connector_exercise_exports = {};
7718
7721
  __export(connector_exercise_exports, {
7719
- DASHBOARD_BASE: () => DASHBOARD_BASE7,
7722
+ DASHBOARD_BASE: () => DASHBOARD_BASE8,
7720
7723
  RUN_HEADER: () => RUN_HEADER,
7721
7724
  RUN_META_KEY: () => RUN_META_KEY,
7722
7725
  reportLink: () => reportLink,
@@ -7724,7 +7727,7 @@ __export(connector_exercise_exports, {
7724
7727
  runConnectorExercise: () => runConnectorExercise
7725
7728
  });
7726
7729
  function reportLink(projectId, apiVersion = "1.0.0") {
7727
- return `${DASHBOARD_BASE7}/directory/${encodeURIComponent(projectId)}/${encodeURIComponent(apiVersion)}`;
7730
+ return `${DASHBOARD_BASE8}/directory/${encodeURIComponent(projectId)}/${encodeURIComponent(apiVersion)}`;
7728
7731
  }
7729
7732
  async function confirm(message, interactive2) {
7730
7733
  if (!interactive2) return false;
@@ -7897,20 +7900,30 @@ async function runConnectorAnswers(project, opts = {}) {
7897
7900
  const current = await producer(caller, { method: "POST", path: `${projectPath2(proj2)}/directory-report`, body: { probe: false }, summary: "Current answers" });
7898
7901
  const have = current.target?.metadata?.portalAnswers ?? {};
7899
7902
  const { default: inquirer3 } = await import("inquirer");
7903
+ const saveNow = async (part) => {
7904
+ try {
7905
+ await producer(caller, { method: "PATCH", path: projectPath2(proj2), body: part, summary: "Save an answer" });
7906
+ } catch (e) {
7907
+ console.log(import_chalk27.default.yellow(` not saved: ${e instanceof Error ? e.message : String(e)}`));
7908
+ }
7909
+ };
7900
7910
  for (const q of QUESTIONS) {
7901
7911
  if (answers[q.field] !== void 0) continue;
7902
7912
  const existing = typeof have[q.field] === "string" ? String(have[q.field]) : "";
7903
7913
  if (existing.length >= (q.min ?? 1)) continue;
7904
7914
  const a = await inquirer3.prompt([{ type: "input", name: "value", message: q.message, default: existing || void 0, validate: (v) => v.trim().length >= (q.min ?? 1) ? true : `${q.min ?? 1}+ characters` }]);
7905
7915
  answers[q.field] = a.value.trim();
7916
+ await saveNow({ directory_portal_answers: { [q.field]: a.value.trim() } });
7906
7917
  }
7907
7918
  if (answers.access === void 0 && !have.access) {
7908
7919
  const a = await inquirer3.prompt([{ type: "list", name: "value", message: "What the tools do:", choices: ["read", "write", "both"] }]);
7909
7920
  answers.access = a.value;
7921
+ await saveNow({ directory_portal_answers: { access: a.value } });
7910
7922
  }
7911
7923
  if (answers.categories === void 0 && !(Array.isArray(have.categories) && have.categories.length)) {
7912
7924
  const a = await inquirer3.prompt([{ type: "input", name: "value", message: "Category suggestions (1\u20135, comma-separated; you pick the closest in the portal):", validate: (v) => v.trim() ? true : "one at least" }]);
7913
7925
  answers.categories = a.value.split(",").map((c) => c.trim()).filter(Boolean).slice(0, 5);
7926
+ await saveNow({ directory_portal_answers: { categories: answers.categories } });
7914
7927
  }
7915
7928
  if (!meta.data_handling && !current.target?.metadata?.dataHandling) {
7916
7929
  const a = await inquirer3.prompt([
@@ -7918,14 +7931,17 @@ async function runConnectorAnswers(project, opts = {}) {
7918
7931
  { type: "input", name: "statement", message: "The permission you hold (who granted what, and when; goes into portal step 7):", when: (ans) => ans.mode === "proxied", validate: (v) => v.trim().length >= 20 ? true : "a sentence, please" }
7919
7932
  ]);
7920
7933
  meta.data_handling = { mode: a.mode, ...a.statement?.trim() ? { statement: a.statement.trim() } : {} };
7934
+ await saveNow({ directory_metadata: { data_handling: meta.data_handling } });
7921
7935
  }
7922
7936
  if (!meta.health_data && !current.target?.metadata?.healthData) {
7923
7937
  const a = await inquirer3.prompt([{ type: "confirm", name: "value", message: "Do the tools handle health data?", default: false }]);
7924
7938
  meta.health_data = a.value ? "yes" : "no";
7939
+ await saveNow({ directory_metadata: { health_data: meta.health_data } });
7925
7940
  }
7926
7941
  if (!meta.sponsored_content && !current.target?.metadata?.sponsoredContent) {
7927
7942
  const a = await inquirer3.prompt([{ type: "confirm", name: "value", message: "Do tool results carry sponsored content?", default: false }]);
7928
7943
  meta.sponsored_content = a.value ? "yes" : "no";
7944
+ await saveNow({ directory_metadata: { sponsored_content: meta.sponsored_content } });
7929
7945
  }
7930
7946
  }
7931
7947
  const body = {};
@@ -7945,7 +7961,7 @@ async function runConnectorAnswers(project, opts = {}) {
7945
7961
  console.log(import_chalk27.default.green(` \u2713 recorded: ${Object.keys({ ...answers, ...meta }).join(", ")}`));
7946
7962
  console.log(import_chalk27.default.dim(` ${r.rendered.headline}`));
7947
7963
  }
7948
- var import_chalk27, import_fs6, import_os3, import_path5, import_child_process6, DASHBOARD_BASE7, RUN_META_KEY, RUN_HEADER, projectPath2, QUESTIONS;
7964
+ var import_chalk27, import_fs6, import_os3, import_path5, import_child_process6, DASHBOARD_BASE8, RUN_META_KEY, RUN_HEADER, projectPath2, QUESTIONS;
7949
7965
  var init_connector_exercise = __esm({
7950
7966
  "src/commands/connector-exercise.ts"() {
7951
7967
  "use strict";
@@ -7961,7 +7977,7 @@ var init_connector_exercise = __esm({
7961
7977
  init_exercise();
7962
7978
  init_brand();
7963
7979
  init_external_mcp();
7964
- DASHBOARD_BASE7 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
7980
+ DASHBOARD_BASE8 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
7965
7981
  RUN_META_KEY = "com.apiblaze/run";
7966
7982
  RUN_HEADER = "apiblaze-directory-run";
7967
7983
  projectPath2 = (p) => `/projects/${encodeURIComponent(p.projectId)}/${encodeURIComponent(p.apiVersion)}`;
@@ -11575,6 +11591,31 @@ Not ready: ${lines.length} blocker${lines.length === 1 ? "" : "s"} (${r.rendered
11575
11591
  process.exit(1);
11576
11592
  }
11577
11593
 
11594
+ // src/lib/op-call.ts
11595
+ init_auth();
11596
+ init_trace();
11597
+ init_types();
11598
+ var DASHBOARD_BASE6 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
11599
+ async function opCall(call3) {
11600
+ const token = getAccessToken();
11601
+ const res = await fetch(`${DASHBOARD_BASE6}/api/cli/op`, {
11602
+ method: "POST",
11603
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
11604
+ body: JSON.stringify({ path: call3.path, method: call3.method, body: call3.body })
11605
+ });
11606
+ let data = null;
11607
+ try {
11608
+ data = await res.json();
11609
+ } catch {
11610
+ }
11611
+ recordCall({ method: call3.method, path: call3.path, body: call3.body, status: res.status, summary: call3.summary });
11612
+ if (!res.ok) {
11613
+ const msg = data?.details ?? data?.error ?? res.statusText;
11614
+ throw new ApiError(res.status, typeof msg === "string" ? msg : JSON.stringify(msg), data);
11615
+ }
11616
+ return data;
11617
+ }
11618
+
11578
11619
  // src/commands/connector.ts
11579
11620
  var import_fs8 = __toESM(require("fs"));
11580
11621
  var import_path6 = __toESM(require("path"));
@@ -11794,13 +11835,17 @@ function shortenTo(text, limit) {
11794
11835
  const base2 = atWord >= Math.floor(limit * 0.4) ? cut.slice(0, atWord) : cut;
11795
11836
  return base2.replace(/[\s,;:(\-–—]+$/g, "").trim();
11796
11837
  }
11797
- async function promptForMissing(r, interactive2, defaults = { prompts: [] }, platforms = PLATFORMS) {
11838
+ async function promptForMissing(r, interactive2, defaults = { prompts: [] }, platforms = PLATFORMS, given = {}, save) {
11798
11839
  const out = {};
11799
11840
  const failing = r.report.results.filter((x) => !x.pass && !x.unverified);
11841
+ const answered = (k) => {
11842
+ const v = given[k];
11843
+ return Array.isArray(v) ? v.length > 0 : typeof v === "string" ? v.trim().length > 0 : v !== void 0 && v !== null && v !== false;
11844
+ };
11800
11845
  const asks = /* @__PURE__ */ new Map();
11801
11846
  for (const x of failing) {
11802
11847
  const p = PROMPT_FOR_RULE[x.id];
11803
- if (!p) continue;
11848
+ if (!p || answered(p.key)) continue;
11804
11849
  const cur = asks.get(p.key);
11805
11850
  if (!cur) {
11806
11851
  asks.set(p.key, { ...p });
@@ -11853,7 +11898,13 @@ async function promptForMissing(r, interactive2, defaults = { prompts: [] }, pla
11853
11898
  }
11854
11899
  lines.push(line.trim());
11855
11900
  }
11856
- if (lines.length) out.prompt = lines;
11901
+ if (lines.length) {
11902
+ out.prompt = lines;
11903
+ if (save) {
11904
+ const why = await save({ prompt: lines });
11905
+ if (why) say_(import_chalk30.default.yellow(` not saved: ${why}`));
11906
+ }
11907
+ }
11857
11908
  continue;
11858
11909
  }
11859
11910
  const dk = DEFAULT_FOR_KEY[a.key];
@@ -11867,9 +11918,18 @@ async function promptForMissing(r, interactive2, defaults = { prompts: [] }, pla
11867
11918
  // The privacy page is a hard portal requirement (https + 200): check it here, before the
11868
11919
  // report has to come back red for a typo.
11869
11920
  // Wrapped: inquirer calls validate(input, answers) and the answers object must not land in fetchFn.
11870
- validate: a.key === "privacyUrl" ? (v) => validatePrivacyUrl(v) : withinLimit(a)
11921
+ validate: a.key === "privacyUrl" ? (v) => validatePrivacyUrl(v) : a.key === "docsUrl" ? (v) => validateHttpsUrl(v, { label: "documentation URL", required: false }) : a.key === "iconUrl" ? (v) => validateHttpsUrl(v, { label: "icon URL", required: false }) : withinLimit(a)
11871
11922
  }]);
11872
- if (value?.trim()) out[a.key] = value.trim();
11923
+ if (value?.trim()) {
11924
+ out[a.key] = value.trim();
11925
+ if (save) {
11926
+ const why = await save({ [a.key]: value.trim() });
11927
+ if (why) {
11928
+ say_(import_chalk30.default.yellow(` not saved: ${why}`));
11929
+ delete out[a.key];
11930
+ }
11931
+ }
11932
+ }
11873
11933
  }
11874
11934
  const missingAttest = failing.filter((x) => x.id.startsWith("ATTEST_"));
11875
11935
  if (missingAttest.length) {
@@ -11900,7 +11960,7 @@ async function askOpenMode(caller, proj2, r, opts, interactive2, say) {
11900
11960
  say(import_chalk30.default.green(" \u2713 open mode: the connector takes no sign-in (public data); no reviewer account is needed."));
11901
11961
  return true;
11902
11962
  }
11903
- async function promptListingBasics(r, interactive2, defaults, given, platforms = PLATFORMS) {
11963
+ async function promptListingBasics(r, interactive2, defaults, given, platforms = PLATFORMS, save) {
11904
11964
  const meta = r.target?.metadata ?? {};
11905
11965
  const gpt = platforms.includes("chatgpt");
11906
11966
  const lim = { serverName: gpt ? 30 : 100, tagline: gpt ? 30 : 200, description: platforms.includes("claude") ? 2e3 : 4e3 };
@@ -11920,7 +11980,16 @@ async function promptListingBasics(r, interactive2, defaults, given, platforms =
11920
11980
  const { default: inquirer3 } = await import("inquirer");
11921
11981
  for (const w of want) {
11922
11982
  const { value } = await inquirer3.prompt([{ type: "input", name: "value", message: w.message, default: w.def }]);
11923
- if (value?.trim()) out[w.key] = value.trim();
11983
+ if (value?.trim()) {
11984
+ out[w.key] = value.trim();
11985
+ if (save) {
11986
+ const why = await save({ [w.key]: value.trim() });
11987
+ if (why) {
11988
+ say_(import_chalk30.default.yellow(` not saved: ${why}`));
11989
+ delete out[w.key];
11990
+ }
11991
+ }
11992
+ }
11924
11993
  }
11925
11994
  return out;
11926
11995
  }
@@ -12155,9 +12224,17 @@ async function runConnector(target2, opts) {
12155
12224
  if (changed) r = await fetchDirectoryReport(caller, proj2, { platforms });
12156
12225
  }
12157
12226
  if (await askOpenMode(caller, proj2, r, opts, interactive2, say)) r = await fetchDirectoryReport(caller, proj2, { platforms });
12158
- const basics = await promptListingBasics(r, interactive2, defaults, opts, platforms);
12227
+ const saveAnswer = async (f2) => {
12228
+ try {
12229
+ await patchProject(caller, proj2, { ...directoryBodyFromFlags(f2) }, "Save an answer");
12230
+ return null;
12231
+ } catch (e) {
12232
+ return e instanceof Error ? e.message : String(e);
12233
+ }
12234
+ };
12235
+ const basics = await promptListingBasics(r, interactive2, defaults, opts, platforms, interactive2 ? saveAnswer : void 0);
12159
12236
  if (!isReady(r, platforms) || Object.keys(basics).length) {
12160
- const asked = { ...basics, ...isReady(r, platforms) ? {} : await promptForMissing(r, interactive2, defaults, platforms) };
12237
+ const asked = { ...basics, ...isReady(r, platforms) ? {} : await promptForMissing(r, interactive2, defaults, platforms, basics, interactive2 ? saveAnswer : void 0) };
12161
12238
  const body = directoryBodyFromFlags(asked);
12162
12239
  if (body.directory_metadata || body.directory_attestations || body.openai_challenge_token) {
12163
12240
  await patchProject(caller, proj2, { ...body }, "Save listing details");
@@ -12180,21 +12257,19 @@ async function runConnector(target2, opts) {
12180
12257
  }
12181
12258
  r = await fetchDirectoryReport(caller, proj2, { platforms });
12182
12259
  }
12183
- if (!readyExceptSnapshot(r, platforms)) {
12184
- printReport(r, json);
12260
+ if (interactive2 && r.report.results.some((x) => ANSWER_RULES.includes(x.id) && !x.pass)) {
12261
+ const { runConnectorAnswers: runConnectorAnswers2 } = await Promise.resolve().then(() => (init_connector_exercise(), connector_exercise_exports));
12262
+ say(import_chalk30.default.bold(" The review answers the portal asks for (saved as you go):"));
12263
+ await runConnectorAnswers2(proj2.projectName, { team: opts.team, apiversion: opts.apiversion });
12264
+ r = await fetchDirectoryReport(caller, proj2, { platforms });
12265
+ }
12266
+ if (!readyExcept(r, platforms, [SNAPSHOT_RULE, ...EVIDENCE_RULES])) {
12185
12267
  if (!domain2.active && domain2.hostname && !json) {
12186
12268
  console.error(import_chalk30.default.yellow(`
12187
12269
  ${domain2.hostname} is not active yet. Once the CNAME is in place, run again: ${B.cli} connector ${proj2.projectName}`));
12188
12270
  }
12189
- exitNotReady(r, platforms, json);
12271
+ exitWithReport(r, proj2, platforms, json);
12190
12272
  }
12191
- r = await fetchDirectoryReport(caller, proj2, { platforms, refreshSnapshot: true, publishedUrl: r.report.project.publishedUrl ?? null });
12192
- const packet = await producer(caller, { method: "GET", path: `${projectPath3(proj2)}/directory-packet`, summary: "Submission packet" });
12193
- const dir = opts.out ?? process.cwd();
12194
- const mdPath = import_path6.default.join(dir, `connector-packet-${proj2.projectId}.md`);
12195
- const jsonPath = import_path6.default.join(dir, `connector-packet-${proj2.projectId}.json`);
12196
- import_fs8.default.writeFileSync(mdPath, packet.markdown, { mode: 384 });
12197
- import_fs8.default.writeFileSync(jsonPath, JSON.stringify(packet.json, null, 2) + "\n", { mode: 384 });
12198
12273
  if (opts.exercise !== false) {
12199
12274
  let run2 = !!opts.yes;
12200
12275
  if (interactive2) {
@@ -12207,6 +12282,14 @@ async function runConnector(target2, opts) {
12207
12282
  r = await fetchDirectoryReport(caller, proj2, { platforms, publishedUrl: r.report.project.publishedUrl ?? null });
12208
12283
  }
12209
12284
  }
12285
+ if (!readyExceptSnapshot(r, platforms)) exitWithReport(r, proj2, platforms, json);
12286
+ r = await fetchDirectoryReport(caller, proj2, { platforms, refreshSnapshot: true, publishedUrl: r.report.project.publishedUrl ?? null });
12287
+ const packet = await producer(caller, { method: "GET", path: `${projectPath3(proj2)}/directory-packet`, summary: "Submission packet" });
12288
+ const dir = opts.out ?? process.cwd();
12289
+ const mdPath = import_path6.default.join(dir, `connector-packet-${proj2.projectId}.md`);
12290
+ const jsonPath = import_path6.default.join(dir, `connector-packet-${proj2.projectId}.json`);
12291
+ import_fs8.default.writeFileSync(mdPath, packet.markdown, { mode: 384 });
12292
+ import_fs8.default.writeFileSync(jsonPath, JSON.stringify(packet.json, null, 2) + "\n", { mode: 384 });
12210
12293
  if (json) {
12211
12294
  process.stdout.write(JSON.stringify({ ready: true, project: proj2.projectId, headline: r.rendered.headline, report: r.report, packet: { markdown: mdPath, json: jsonPath }, portals: PORTALS, ...reviewer ? { reviewer } : {} }) + "\n");
12212
12295
  return;
@@ -12225,6 +12308,23 @@ async function runConnector(target2, opts) {
12225
12308
  console.log(import_chalk30.default.dim(` ${r.report.disclaimer}`));
12226
12309
  }
12227
12310
  var SNAPSHOT_RULE = "LISTING_SNAPSHOT_MATCH";
12311
+ var ANSWER_RULES = ["PORTAL_ANSWERS_COMPLETE", "HEALTH_SPONSORED_DECLARED", "API_OWNERSHIP_DOMAIN"];
12312
+ var EVIDENCE_RULES = ["TOOL_EXERCISED_EACH", "TOOL_ERROR_PATH_EACH", "REVIEWER_ACCOUNT_POPULATED", "TESTED_IN_CLAUDE_OR_INSPECTOR", "TESTED_FROM_CLAUDE", "EXAMPLE_PROMPTS_WORK", "OAUTH_FLOW_COMPLETED"];
12313
+ function exitWithReport(r, proj2, platforms, json) {
12314
+ if (json) {
12315
+ process.stdout.write(JSON.stringify({ ready: false, project: proj2.projectId, headline: r.rendered.headline, report: r.report }) + "\n");
12316
+ process.exit(1);
12317
+ }
12318
+ printReport(r, false);
12319
+ const want = platforms;
12320
+ const blocking = r.report.results.filter((x) => !x.pass && x.severity === "block" && !x.unverified && x.platforms.some((p) => want.includes(p)));
12321
+ const first = blocking.find((x) => x.id !== SNAPSHOT_RULE) ?? blocking[0];
12322
+ console.error(import_chalk30.default.red(`
12323
+ Not ready: ${blocking.length} blocker${blocking.length === 1 ? "" : "s"} (${blocking.map((x) => x.id).join(", ")}).`));
12324
+ if (first) console.error(` Next: ${first.fix ?? first.message ?? first.title}`);
12325
+ console.error(import_chalk30.default.dim(` Report page: ${DASHBOARD_BASE6}/directory/${encodeURIComponent(proj2.projectId)}/${encodeURIComponent(proj2.apiVersion)}`));
12326
+ process.exit(1);
12327
+ }
12228
12328
  var TOOL_DESC_RULE = "TOOL_DESC_NONEMPTY_SPECIFIC";
12229
12329
  var UTILITY_PATH = /(health|ping|status|openapi|swagger|docs|spec|whoami|version)/i;
12230
12330
  var SPECIFIC_MIN = 12;
@@ -12284,10 +12384,13 @@ async function fixToolDescriptions(proj2, environment, interactive2, say) {
12284
12384
  return true;
12285
12385
  }
12286
12386
  function readyExceptSnapshot(r, platforms) {
12387
+ return readyExcept(r, platforms, [SNAPSHOT_RULE]);
12388
+ }
12389
+ function readyExcept(r, platforms, ignore) {
12287
12390
  if (isReady(r, platforms)) return true;
12288
12391
  const want = platforms ?? r.report.platformsRequested ?? ["claude", "chatgpt"];
12289
12392
  const blocking = r.report.results.filter((x) => !x.pass && x.severity === "block" && x.platforms.some((p) => want.includes(p)));
12290
- return blocking.length > 0 && blocking.every((x) => x.id === SNAPSHOT_RULE && /no listing snapshot/i.test(x.message ?? ""));
12393
+ return blocking.length > 0 && blocking.every((x) => ignore.includes(x.id) && (x.id !== SNAPSHOT_RULE || /no listing snapshot/i.test(x.message ?? "")));
12291
12394
  }
12292
12395
  async function probeConventionalUrls(apexDomain, fetchFn = headStatus) {
12293
12396
  if (!apexDomain) return {};
@@ -12309,11 +12412,19 @@ async function probeConventionalUrls(apexDomain, fetchFn = headStatus) {
12309
12412
  }
12310
12413
  return out;
12311
12414
  }
12415
+ var say_ = (line) => {
12416
+ if (process.env.APIBLAZE_SILENT !== "1") console.log(line);
12417
+ };
12312
12418
  async function validatePrivacyUrl(input, fetchFn = headStatus) {
12313
12419
  if (typeof fetchFn !== "function") fetchFn = headStatus;
12420
+ if (!(input ?? "").trim()) return "A public privacy policy URL is required by both directories.";
12421
+ return validateHttpsUrl(input, { label: "privacy URL", required: true, fetchFn });
12422
+ }
12423
+ async function validateHttpsUrl(input, o) {
12424
+ const fetchFn = typeof o.fetchFn === "function" ? o.fetchFn : headStatus;
12314
12425
  const u = (input ?? "").trim();
12315
- if (!u) return "A public privacy policy URL is required by both directories.";
12316
- if (!/^https:\/\//i.test(u)) return "The privacy URL must start with https://";
12426
+ if (!u) return o.required ? `A ${o.label} is required.` : true;
12427
+ if (!/^https:\/\//i.test(u)) return `The ${o.label} must start with https://`;
12317
12428
  const status2 = await fetchFn(u);
12318
12429
  if (status2 === 200) return true;
12319
12430
  return status2 === 0 ? `${u} did not answer (timeout or DNS). Publish the page, then enter its URL.` : `${u} answered ${status2}; it must answer 200.`;
@@ -14248,7 +14359,7 @@ var import_fs12 = require("fs");
14248
14359
  init_admin();
14249
14360
  init_auth();
14250
14361
  init_resolve();
14251
- var DASHBOARD_BASE8 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
14362
+ var DASHBOARD_BASE9 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
14252
14363
  async function runExport(projectArg, versionArg, opts) {
14253
14364
  const token = getAccessToken();
14254
14365
  if (!token) throw new Error("Not authenticated. Run `apiblaze login` first.");
@@ -14286,7 +14397,7 @@ async function runExport(projectArg, versionArg, opts) {
14286
14397
  }
14287
14398
  process.stdout.write("\n");
14288
14399
  const outFile = opts.out || `apiblaze-export-${projectId}-${version2}-${target2}.zip`;
14289
- const res = await fetch(`${DASHBOARD_BASE8}/api/cli/admin/download`, {
14400
+ const res = await fetch(`${DASHBOARD_BASE9}/api/cli/admin/download`, {
14290
14401
  method: "POST",
14291
14402
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
14292
14403
  body: JSON.stringify({ path: `${statusPath}?download=1` })
@@ -16052,7 +16163,7 @@ var import_ora20 = __toESM(require("ora"));
16052
16163
  init_admin();
16053
16164
  init_resolve();
16054
16165
  init_brand();
16055
- var DASHBOARD_BASE9 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
16166
+ var DASHBOARD_BASE10 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
16056
16167
  var TOPUP_MIN_USD = 10;
16057
16168
  var TOPUP_MAX_USD = 1e3;
16058
16169
  var money = (cents2) => typeof cents2 === "number" ? `$${usdStr(cents2)}` : "\u2014";
@@ -16114,7 +16225,7 @@ async function runBillingBalance(opts) {
16114
16225
  console.log("");
16115
16226
  }
16116
16227
  function walletUrl(teamId) {
16117
- return teamId ? `${DASHBOARD_BASE9}/topup?teamId=${encodeURIComponent(teamId)}` : `${DASHBOARD_BASE9}/account?section=wallet`;
16228
+ return teamId ? `${DASHBOARD_BASE10}/topup?teamId=${encodeURIComponent(teamId)}` : `${DASHBOARD_BASE10}/account?section=wallet`;
16118
16229
  }
16119
16230
  async function runBillingTopup(amount, opts) {
16120
16231
  const usd2 = Number(amount);
@@ -18689,7 +18800,7 @@ init_tenant_choice();
18689
18800
  init_resolve();
18690
18801
  init_types();
18691
18802
  init_paging();
18692
- var DASHBOARD_BASE10 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
18803
+ var DASHBOARD_BASE11 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
18693
18804
  var IAM_BASE = process.env.APIBLAZE_IAM_BASE || "https://iam.apiblaze.com";
18694
18805
  async function resolveTransport(opts) {
18695
18806
  const producer2 = loadCredentials();
@@ -18713,7 +18824,7 @@ async function resolveTransport(opts) {
18713
18824
  return {
18714
18825
  tenant: tenant2,
18715
18826
  call: async (path19, method = "GET", body) => {
18716
- const res = await fetch(`${DASHBOARD_BASE10}/api/cli/iam`, {
18827
+ const res = await fetch(`${DASHBOARD_BASE11}/api/cli/iam`, {
18717
18828
  method: "POST",
18718
18829
  headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
18719
18830
  body: JSON.stringify({ tenant: tenant2, path: path19, method, body })
@@ -19589,31 +19700,6 @@ async function runOriginsRemove(origin, opts) {
19589
19700
  var import_chalk77 = __toESM(require("chalk"));
19590
19701
  init_auth();
19591
19702
 
19592
- // src/lib/op-call.ts
19593
- init_auth();
19594
- init_trace();
19595
- init_types();
19596
- var DASHBOARD_BASE11 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
19597
- async function opCall(call3) {
19598
- const token = getAccessToken();
19599
- const res = await fetch(`${DASHBOARD_BASE11}/api/cli/op`, {
19600
- method: "POST",
19601
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
19602
- body: JSON.stringify({ path: call3.path, method: call3.method, body: call3.body })
19603
- });
19604
- let data = null;
19605
- try {
19606
- data = await res.json();
19607
- } catch {
19608
- }
19609
- recordCall({ method: call3.method, path: call3.path, body: call3.body, status: res.status, summary: call3.summary });
19610
- if (!res.ok) {
19611
- const msg = data?.details ?? data?.error ?? res.statusText;
19612
- throw new ApiError(res.status, typeof msg === "string" ? msg : JSON.stringify(msg), data);
19613
- }
19614
- return data;
19615
- }
19616
-
19617
19703
  // src/commands/op-money.ts
19618
19704
  var import_chalk70 = __toESM(require("chalk"));
19619
19705
  init_admin();
@@ -19702,8 +19788,8 @@ function lastLedgerSendAtMs(st) {
19702
19788
  const v = st.lastLedgerSendAtMs !== void 0 ? st.lastLedgerSendAtMs : st.lastFlushAtMs;
19703
19789
  return typeof v === "number" && Number.isFinite(v) ? v : null;
19704
19790
  }
19705
- var walletPage = (ba) => `${DASHBOARD_BASE11}/operator/wallets/${encodeURIComponent(ba)}`;
19706
- var incidentPage = () => `${DASHBOARD_BASE11}/operator/incident`;
19791
+ var walletPage = (ba) => `${DASHBOARD_BASE6}/operator/wallets/${encodeURIComponent(ba)}`;
19792
+ var incidentPage = () => `${DASHBOARD_BASE6}/operator/incident`;
19707
19793
  var WALLET_MUTATIONS = {
19708
19794
  "freeze": "a reason (required, \u2264 500 chars). Sets frozen; epoch++ recalls every shard \u2014 serving stops within seconds.",
19709
19795
  "unfreeze": "a reason (required, \u2264 500 chars).",
@@ -19717,7 +19803,7 @@ var WALLET_MUTATIONS = {
19717
19803
  function opWalletMutation(action2, ref, opts) {
19718
19804
  const need = WALLET_MUTATIONS[action2];
19719
19805
  const target2 = ref ?? "<wallet>";
19720
- const url = ref && !isTeamId(ref) ? walletPage(ref) : `${DASHBOARD_BASE11}/operator/wallets`;
19806
+ const url = ref && !isTeamId(ref) ? walletPage(ref) : `${DASHBOARD_BASE6}/operator/wallets`;
19721
19807
  if (opts.json) return void console.log(JSON.stringify({ action: action2, wallet: ref ?? null, dashboard_only: true, url, requires: need ?? "a reason" }));
19722
19808
  console.log(import_chalk70.default.yellow(`
19723
19809
  \`op wallet ${action2}\` is dashboard-only \u2014 it writes an operator_audit row with YOUR reason before touching the root.`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apiblaze",
3
- "version": "0.21.63",
3
+ "version": "0.21.65",
4
4
  "description": "APIblaze CLI — Chat with your APIs, Manage your API keys, users and groups with the APIblaze serverless proxy",
5
5
  "keywords": [
6
6
  "apiblaze",