apiblaze 0.21.39 → 0.21.41
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 +107 -57
- 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.
|
|
37
|
+
version = "0.21.41";
|
|
38
38
|
}
|
|
39
39
|
});
|
|
40
40
|
|
|
@@ -137,21 +137,26 @@ function handleUpgradeRequired(err) {
|
|
|
137
137
|
})();
|
|
138
138
|
return handling;
|
|
139
139
|
}
|
|
140
|
+
function cliHeaders() {
|
|
141
|
+
if (!guardVersion) return {};
|
|
142
|
+
const h = { [CLI_VERSION_HEADER]: guardVersion, "user-agent": `apiblaze-cli/${guardVersion}` };
|
|
143
|
+
const command = getCommandLabel();
|
|
144
|
+
if (command) {
|
|
145
|
+
h[CLI_COMMAND_HEADER] = command;
|
|
146
|
+
h[CLI_RUN_HEADER] = getRunId();
|
|
147
|
+
}
|
|
148
|
+
return h;
|
|
149
|
+
}
|
|
140
150
|
function installFetchGuard(version2) {
|
|
141
151
|
if (installed || typeof globalThis.fetch !== "function") return;
|
|
142
152
|
installed = true;
|
|
153
|
+
guardVersion = version2;
|
|
143
154
|
const base2 = globalThis.fetch.bind(globalThis);
|
|
144
155
|
globalThis.fetch = (async (input, init) => {
|
|
145
156
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
146
157
|
if (!isControlPlaneHost(url)) return base2(input, init);
|
|
147
158
|
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
148
|
-
headers.set(
|
|
149
|
-
const command = getCommandLabel();
|
|
150
|
-
if (command) {
|
|
151
|
-
headers.set(CLI_COMMAND_HEADER, command);
|
|
152
|
-
headers.set(CLI_RUN_HEADER, getRunId());
|
|
153
|
-
}
|
|
154
|
-
if (!headers.has("user-agent")) headers.set("user-agent", `apiblaze-cli/${version2}`);
|
|
159
|
+
for (const [k, v] of Object.entries(cliHeaders())) if (k !== "user-agent" || !headers.has(k)) headers.set(k, v);
|
|
155
160
|
const res = await base2(input, { ...init, headers });
|
|
156
161
|
if (res.status === 426) {
|
|
157
162
|
let body = null;
|
|
@@ -237,7 +242,7 @@ function watchCliPolicy(version2) {
|
|
|
237
242
|
t.unref?.();
|
|
238
243
|
return () => clearInterval(t);
|
|
239
244
|
}
|
|
240
|
-
var import_fs, import_os, import_path, import_chalk, DASHBOARD_BASE, CACHE_MS, UPGRADE_EXIT_CODE, CONTROL_PLANE_HOSTS, CONTROL_PLANE_ENV, CliUpgradeRequired, shutdownHook, handling, installed;
|
|
245
|
+
var import_fs, import_os, import_path, import_chalk, DASHBOARD_BASE, CACHE_MS, UPGRADE_EXIT_CODE, CONTROL_PLANE_HOSTS, CONTROL_PLANE_ENV, CliUpgradeRequired, shutdownHook, handling, guardVersion, installed;
|
|
241
246
|
var init_version_guard = __esm({
|
|
242
247
|
"src/lib/version-guard.ts"() {
|
|
243
248
|
"use strict";
|
|
@@ -273,6 +278,7 @@ var init_version_guard = __esm({
|
|
|
273
278
|
};
|
|
274
279
|
shutdownHook = null;
|
|
275
280
|
handling = null;
|
|
281
|
+
guardVersion = "";
|
|
276
282
|
installed = false;
|
|
277
283
|
}
|
|
278
284
|
});
|
|
@@ -372,6 +378,7 @@ __export(api_exports, {
|
|
|
372
378
|
bothDoorsBody: () => bothDoorsBody,
|
|
373
379
|
checkProxyName: () => checkProxyName,
|
|
374
380
|
claimTeam: () => claimTeam,
|
|
381
|
+
countRun: () => countRun,
|
|
375
382
|
createProxy: () => createProxy,
|
|
376
383
|
createProxyAnonymous: () => createProxyAnonymous,
|
|
377
384
|
deleteDevTunnel: () => deleteDevTunnel,
|
|
@@ -385,6 +392,22 @@ __export(api_exports, {
|
|
|
385
392
|
putDevTunnel: () => putDevTunnel,
|
|
386
393
|
sidecarInitAnonymous: () => sidecarInitAnonymous
|
|
387
394
|
});
|
|
395
|
+
function countRun(opts = {}) {
|
|
396
|
+
if (/^(1|true|yes)$/i.test((process.env.DO_NOT_TRACK ?? "").trim())) return;
|
|
397
|
+
if (opts.event !== void 0 && !/^[a-z0-9-]{1,48}$/.test(opts.event)) return;
|
|
398
|
+
try {
|
|
399
|
+
const child = (0, import_child_process.spawn)(process.execPath, ["-e", COUNT_RUN_CHILD], {
|
|
400
|
+
detached: true,
|
|
401
|
+
stdio: "ignore",
|
|
402
|
+
windowsHide: true,
|
|
403
|
+
env: { ...process.env, ABZ_COUNT_URL: (opts.url ?? `${PUBLIC_API_BASE}/cli/hello`) + (opts.event ? `/${opts.event}` : ""), ABZ_COUNT_HEADERS: JSON.stringify(cliHeaders()) }
|
|
404
|
+
});
|
|
405
|
+
child.on("error", () => {
|
|
406
|
+
});
|
|
407
|
+
child.unref();
|
|
408
|
+
} catch {
|
|
409
|
+
}
|
|
410
|
+
}
|
|
388
411
|
async function createProxyAnonymous(body) {
|
|
389
412
|
const res = await fetch(`${PUBLIC_API_BASE}/proxy`, {
|
|
390
413
|
method: "POST",
|
|
@@ -543,15 +566,18 @@ function integrationKitCall(project, stack) {
|
|
|
543
566
|
summary: `Integration kit for ${project} (${stack})`
|
|
544
567
|
};
|
|
545
568
|
}
|
|
546
|
-
var import_yaml, DASHBOARD_BASE2, PUBLIC_API_BASE, GITHUB_LOGIN, LOCAL_SPEC_PATHS, INTEGRATION_STACKS;
|
|
569
|
+
var import_child_process, import_yaml, DASHBOARD_BASE2, PUBLIC_API_BASE, COUNT_RUN_CHILD, GITHUB_LOGIN, LOCAL_SPEC_PATHS, INTEGRATION_STACKS;
|
|
547
570
|
var init_api = __esm({
|
|
548
571
|
"src/lib/api.ts"() {
|
|
549
572
|
"use strict";
|
|
573
|
+
import_child_process = require("child_process");
|
|
550
574
|
init_auth();
|
|
575
|
+
init_version_guard();
|
|
551
576
|
import_yaml = require("yaml");
|
|
552
577
|
init_types();
|
|
553
578
|
DASHBOARD_BASE2 = process.env.APIBLAZE_DASHBOARD_BASE || "https://dashboard.apiblaze.com";
|
|
554
579
|
PUBLIC_API_BASE = "https://api.apiblaze.com";
|
|
580
|
+
COUNT_RUN_CHILD = "fetch(process.env.ABZ_COUNT_URL,{method:'POST',headers:JSON.parse(process.env.ABZ_COUNT_HEADERS||'{}'),signal:AbortSignal.timeout(5000)}).then((r)=>r.body&&r.body.cancel(),()=>{})";
|
|
555
581
|
GITHUB_LOGIN = { providers: [{ type: "github", managed: true }] };
|
|
556
582
|
LOCAL_SPEC_PATHS = ["/openapi.json", "/openapi.yaml", "/docs/openapi.json"];
|
|
557
583
|
INTEGRATION_STACKS = ["nextjs", "express", "fastapi", "other"];
|
|
@@ -2281,7 +2307,7 @@ function waitForClaudeConnection(name, timeoutMs = 12e3) {
|
|
|
2281
2307
|
for (; ; ) {
|
|
2282
2308
|
last = claudeServerStatus(name);
|
|
2283
2309
|
if (last === "connected" || Date.now() >= deadline) return last;
|
|
2284
|
-
(0,
|
|
2310
|
+
(0, import_child_process2.spawnSync)(process.execPath, ["-e", "setTimeout(()=>{},1200)"], { timeout: 3e3 });
|
|
2285
2311
|
}
|
|
2286
2312
|
}
|
|
2287
2313
|
function claudeOneShot(spec2, prompt) {
|
|
@@ -2632,18 +2658,18 @@ async function installAndDemo(cli, spec2, getQuestion, log4 = console.log) {
|
|
|
2632
2658
|
log4(import_chalk12.default.red(` ${import_chalk12.default.bold(off)}`));
|
|
2633
2659
|
return true;
|
|
2634
2660
|
}
|
|
2635
|
-
var fs6, os4, path7,
|
|
2661
|
+
var fs6, os4, path7, import_child_process2, import_chalk12, useShell, winQuote, run, detected, mcpLoginSupport, OURS, mask, tomlStr, shellQuote, marker;
|
|
2636
2662
|
var init_external_mcp = __esm({
|
|
2637
2663
|
"src/lib/external-mcp.ts"() {
|
|
2638
2664
|
"use strict";
|
|
2639
2665
|
fs6 = __toESM(require("fs"));
|
|
2640
2666
|
os4 = __toESM(require("os"));
|
|
2641
2667
|
path7 = __toESM(require("path"));
|
|
2642
|
-
|
|
2668
|
+
import_child_process2 = require("child_process");
|
|
2643
2669
|
import_chalk12 = __toESM(require("chalk"));
|
|
2644
2670
|
useShell = process.platform === "win32";
|
|
2645
2671
|
winQuote = (a) => /^[A-Za-z0-9_\-.:/\\=]+$/.test(a) ? a : `"${a.replace(/"/g, '""')}"`;
|
|
2646
|
-
run = (cmd, args, opts = {}) => (0,
|
|
2672
|
+
run = (cmd, args, opts = {}) => (0, import_child_process2.spawnSync)(cmd, useShell ? args.map(winQuote) : args, {
|
|
2647
2673
|
encoding: "utf-8",
|
|
2648
2674
|
stdio: opts.interactive ? ["inherit", "inherit", "inherit"] : opts.inherit ? ["ignore", "inherit", "inherit"] : ["ignore", "pipe", "pipe"],
|
|
2649
2675
|
timeout: opts.inherit || opts.interactive ? void 0 : 15e3,
|
|
@@ -2952,7 +2978,7 @@ function decodeJwt2(token) {
|
|
|
2952
2978
|
function openBrowser2(url) {
|
|
2953
2979
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
2954
2980
|
try {
|
|
2955
|
-
(0,
|
|
2981
|
+
(0, import_child_process3.spawn)(cmd, [url], { stdio: "ignore", detached: true }).unref();
|
|
2956
2982
|
} catch {
|
|
2957
2983
|
}
|
|
2958
2984
|
}
|
|
@@ -3028,7 +3054,7 @@ async function validConsumerToken(creds) {
|
|
|
3028
3054
|
if (Date.now() < creds.expiresAt - 3e4) return creds;
|
|
3029
3055
|
return refreshConsumer(creds);
|
|
3030
3056
|
}
|
|
3031
|
-
var fs7, os5, path8, crypto,
|
|
3057
|
+
var fs7, os5, path8, crypto, import_child_process3, AUTH_BASE, APIBLAZE_DIR2, CONSUMER_PATH, DEVICE_GRANT;
|
|
3032
3058
|
var init_consumer_auth = __esm({
|
|
3033
3059
|
"src/lib/consumer-auth.ts"() {
|
|
3034
3060
|
"use strict";
|
|
@@ -3036,7 +3062,7 @@ var init_consumer_auth = __esm({
|
|
|
3036
3062
|
os5 = __toESM(require("os"));
|
|
3037
3063
|
path8 = __toESM(require("path"));
|
|
3038
3064
|
crypto = __toESM(require("crypto"));
|
|
3039
|
-
|
|
3065
|
+
import_child_process3 = require("child_process");
|
|
3040
3066
|
AUTH_BASE = process.env.APIBLAZE_AUTH_BASE || "https://auth.apiblaze.com";
|
|
3041
3067
|
APIBLAZE_DIR2 = path8.join(os5.homedir(), ".apiblaze");
|
|
3042
3068
|
CONSUMER_PATH = path8.join(APIBLAZE_DIR2, "consumer.json");
|
|
@@ -4738,7 +4764,7 @@ async function removeExternalMcp(projectId, cliKind) {
|
|
|
4738
4764
|
const label3 = kind === "claude" ? "Claude CLI" : "Codex CLI";
|
|
4739
4765
|
let removed = false;
|
|
4740
4766
|
if (kind === "claude") {
|
|
4741
|
-
const r = (0,
|
|
4767
|
+
const r = (0, import_child_process4.spawnSync)("claude", ["mcp", "remove", projectId], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 15e3 });
|
|
4742
4768
|
removed = r.status === 0;
|
|
4743
4769
|
} else {
|
|
4744
4770
|
removed = removeCodexServer(projectId);
|
|
@@ -4842,14 +4868,14 @@ async function runApichat(opts) {
|
|
|
4842
4868
|
if (mcpUrl2 && await maybeInstallExternalCli(p, opts)) return;
|
|
4843
4869
|
await startChat(p, [], opts);
|
|
4844
4870
|
}
|
|
4845
|
-
var fs9, path9, crypto2,
|
|
4871
|
+
var fs9, path9, crypto2, import_child_process4, import_chalk15, import_ora2, import_yaml3, GENERATOR_HINT, revealAuth, apichatsPath;
|
|
4846
4872
|
var init_apichat = __esm({
|
|
4847
4873
|
"src/commands/apichat.ts"() {
|
|
4848
4874
|
"use strict";
|
|
4849
4875
|
fs9 = __toESM(require("fs"));
|
|
4850
4876
|
path9 = __toESM(require("path"));
|
|
4851
4877
|
crypto2 = __toESM(require("crypto"));
|
|
4852
|
-
|
|
4878
|
+
import_child_process4 = require("child_process");
|
|
4853
4879
|
import_chalk15 = __toESM(require("chalk"));
|
|
4854
4880
|
import_ora2 = __toESM(require("ora"));
|
|
4855
4881
|
import_yaml3 = require("yaml");
|
|
@@ -7659,6 +7685,7 @@ __export(demo_exports, {
|
|
|
7659
7685
|
DEMO_RPS: () => DEMO_RPS,
|
|
7660
7686
|
demoName: () => demoName,
|
|
7661
7687
|
isDemoProcess: () => isDemoProcess,
|
|
7688
|
+
portFree: () => portFree,
|
|
7662
7689
|
routesOf: () => routesOf,
|
|
7663
7690
|
runDemo: () => runDemo,
|
|
7664
7691
|
runDemoLogs: () => runDemoLogs,
|
|
@@ -7670,17 +7697,31 @@ __export(demo_exports, {
|
|
|
7670
7697
|
function demoName() {
|
|
7671
7698
|
return `demo${pick2(ADJ)}${pick2(NOUN)}${import_crypto.default.randomBytes(2).toString("hex")}`;
|
|
7672
7699
|
}
|
|
7673
|
-
function portFree(port) {
|
|
7674
|
-
|
|
7700
|
+
async function portFree(port) {
|
|
7701
|
+
const answers = (host) => new Promise((resolve4) => {
|
|
7702
|
+
const sock = import_net2.default.connect({ port, host });
|
|
7703
|
+
sock.setTimeout(1e3, () => {
|
|
7704
|
+
sock.destroy();
|
|
7705
|
+
resolve4(true);
|
|
7706
|
+
});
|
|
7707
|
+
sock.once("connect", () => {
|
|
7708
|
+
sock.destroy();
|
|
7709
|
+
resolve4(true);
|
|
7710
|
+
});
|
|
7711
|
+
sock.once("error", () => resolve4(false));
|
|
7712
|
+
});
|
|
7713
|
+
const bindable = (host) => new Promise((resolve4) => {
|
|
7675
7714
|
const s = import_net2.default.createServer();
|
|
7676
|
-
s.once("error", () => resolve4(
|
|
7715
|
+
s.once("error", (e) => resolve4(host === "::1" && (e.code === "EADDRNOTAVAIL" || e.code === "EAFNOSUPPORT")));
|
|
7677
7716
|
s.once("listening", () => s.close(() => resolve4(true)));
|
|
7678
|
-
s.listen(port,
|
|
7717
|
+
s.listen(port, host);
|
|
7679
7718
|
});
|
|
7719
|
+
const [v4, v6] = await Promise.all([answers("127.0.0.1"), answers("::1")]);
|
|
7720
|
+
return !v4 && !v6 && await bindable("127.0.0.1") && await bindable("::1");
|
|
7680
7721
|
}
|
|
7681
7722
|
async function freePort(from, avoid = []) {
|
|
7682
7723
|
for (let p = from; p < from + 200; p++) if (!avoid.includes(p) && await portFree(p)) return p;
|
|
7683
|
-
throw new DemoError("No free port for the demo app.", "Close another local server, then run again.");
|
|
7724
|
+
throw new DemoError("No free port for the demo app.", "Close another local server, then run again.", "no-free-port");
|
|
7684
7725
|
}
|
|
7685
7726
|
function readRegistry() {
|
|
7686
7727
|
try {
|
|
@@ -7737,15 +7778,16 @@ async function stopTunnels() {
|
|
|
7737
7778
|
}
|
|
7738
7779
|
function appCtl(dir, arg) {
|
|
7739
7780
|
if (!import_fs6.default.existsSync(import_path5.default.join(dir, "start.js"))) return false;
|
|
7740
|
-
const r = (0,
|
|
7781
|
+
const r = (0, import_child_process5.spawnSync)(process.execPath, [import_path5.default.join(dir, "start.js"), arg], { cwd: dir, stdio: "ignore", timeout: 15e3 });
|
|
7741
7782
|
return r.status === 0;
|
|
7742
7783
|
}
|
|
7743
7784
|
function isDemoProcess(args) {
|
|
7744
|
-
|
|
7785
|
+
const node = String.raw`^(?:\S*[\\/])?node(?:\.exe)?\s+`;
|
|
7786
|
+
return new RegExp(node + String.raw`.*[\\/](?:apiblaze|mcpblaze)-demo[\\/]start\.js$`).test(args.trim()) || new RegExp(node + String.raw`\S.*\sdemo --serve\s`).test(args);
|
|
7745
7787
|
}
|
|
7746
7788
|
function demoProcesses() {
|
|
7747
7789
|
if (process.platform === "win32") return [];
|
|
7748
|
-
const r = (0,
|
|
7790
|
+
const r = (0, import_child_process5.spawnSync)("ps", ["-Ao", "pid=,args="], { encoding: "utf8" });
|
|
7749
7791
|
if (r.status !== 0 || !r.stdout) return [];
|
|
7750
7792
|
const out = [];
|
|
7751
7793
|
for (const line of r.stdout.split("\n")) {
|
|
@@ -7860,19 +7902,19 @@ async function createProxy2(name, backendPort2, openapi, tenantName) {
|
|
|
7860
7902
|
return await createProxyAnonymous(body);
|
|
7861
7903
|
} catch (err) {
|
|
7862
7904
|
const status2 = err.status;
|
|
7863
|
-
if (status2 === 429) throw new DemoError("Too many demos were started from this network in the last hour.", `Wait a few minutes, then run: ${LATEST} demo
|
|
7864
|
-
if (status2 && status2 >= 500) throw new DemoError(`${B.product} is having trouble right now.`, `Try again in a minute: ${LATEST} demo
|
|
7865
|
-
throw new DemoError(`Could not create the demo (${err.message}).`, `Run again: ${LATEST} demo
|
|
7905
|
+
if (status2 === 429) throw new DemoError("Too many demos were started from this network in the last hour.", `Wait a few minutes, then run: ${LATEST} demo`, "create-429");
|
|
7906
|
+
if (status2 && status2 >= 500) throw new DemoError(`${B.product} is having trouble right now.`, `Try again in a minute: ${LATEST} demo`, "create-5xx");
|
|
7907
|
+
throw new DemoError(`Could not create the demo (${err.message}).`, `Run again: ${LATEST} demo`, "create-failed");
|
|
7866
7908
|
}
|
|
7867
7909
|
}
|
|
7868
7910
|
async function waitTunnel(dir) {
|
|
7869
7911
|
for (let i = 0; i < 200; i++) {
|
|
7870
7912
|
const st = loadState(dir);
|
|
7871
|
-
if (st?.error) throw new DemoError(st.error, `Run again: ${LATEST} demo
|
|
7913
|
+
if (st?.error) throw new DemoError(st.error, `Run again: ${LATEST} demo`, "tunnel-error");
|
|
7872
7914
|
if (st?.ready) return;
|
|
7873
7915
|
await new Promise((r) => setTimeout(r, 100));
|
|
7874
7916
|
}
|
|
7875
|
-
throw new DemoError("The tunnel did not open in time.", `Try: ${LATEST} demo restart
|
|
7917
|
+
throw new DemoError("The tunnel did not open in time.", `Try: ${LATEST} demo restart`, "tunnel-timeout");
|
|
7876
7918
|
}
|
|
7877
7919
|
async function waitThrough(apiUrl, serverKey) {
|
|
7878
7920
|
let last = 0;
|
|
@@ -7881,13 +7923,13 @@ async function waitThrough(apiUrl, serverKey) {
|
|
|
7881
7923
|
const r = await fetch(`${apiUrl}/reservations`, { headers: { "x-api-key": serverKey, "x-end-user-id": "ana" } });
|
|
7882
7924
|
last = r.status;
|
|
7883
7925
|
if (r.status === 200) return;
|
|
7884
|
-
if (r.status === 402) throw new DemoError(`${B.product} refused the demo's free calls. That is a problem on our side, not yours.`, `Try again in a few minutes: ${LATEST} demo
|
|
7926
|
+
if (r.status === 402) throw new DemoError(`${B.product} refused the demo's free calls. That is a problem on our side, not yours.`, `Try again in a few minutes: ${LATEST} demo`, "trial-402");
|
|
7885
7927
|
} catch (e) {
|
|
7886
7928
|
if (e instanceof DemoError) throw e;
|
|
7887
7929
|
}
|
|
7888
7930
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
7889
7931
|
}
|
|
7890
|
-
throw new DemoError(`The demo is running but ${B.product} cannot reach it yet (last answer ${last}).`, `Run again: ${LATEST} demo`);
|
|
7932
|
+
throw new DemoError(`The demo is running but ${B.product} cannot reach it yet (last answer ${last}).`, `Run again: ${LATEST} demo`, `cannot-reach-${last}`);
|
|
7891
7933
|
}
|
|
7892
7934
|
async function confirmStep(opts, question) {
|
|
7893
7935
|
if (opts.yes || !interactive()) return true;
|
|
@@ -7918,7 +7960,7 @@ function openBrowser3(url) {
|
|
|
7918
7960
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
|
|
7919
7961
|
const args = process.platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
7920
7962
|
try {
|
|
7921
|
-
(0,
|
|
7963
|
+
(0, import_child_process5.spawn)(cmd, args, { stdio: "ignore", detached: true }).on("error", () => {
|
|
7922
7964
|
}).unref();
|
|
7923
7965
|
} catch {
|
|
7924
7966
|
}
|
|
@@ -7962,9 +8004,10 @@ function routesOf(openapi) {
|
|
|
7962
8004
|
async function runDemo(opts = {}) {
|
|
7963
8005
|
if (opts.serve) return serveTunnel(import_path5.default.resolve(opts.serve));
|
|
7964
8006
|
try {
|
|
7965
|
-
await startDemo(opts);
|
|
8007
|
+
countRun({ event: await startDemo(opts) });
|
|
7966
8008
|
} catch (err) {
|
|
7967
8009
|
const e = err instanceof DemoError ? err : new DemoError(`The demo could not start (${err.message}).`, `Run again: ${LATEST} demo`);
|
|
8010
|
+
countRun({ event: `demo-failed-${e.why}` });
|
|
7968
8011
|
await stopDemos().catch(() => 0);
|
|
7969
8012
|
console.log(`${import_chalk24.default.red("\u2717")} ${e.message}`);
|
|
7970
8013
|
console.log(` ${e.fix}`);
|
|
@@ -8020,9 +8063,10 @@ async function startDemo(opts) {
|
|
|
8020
8063
|
const cdDir = rel === "." ? "" : `cd ${rel} && `;
|
|
8021
8064
|
const shell = (c, note = "") => console.log(` ${import_chalk24.default.dim("$")} ${import_chalk24.default.cyan(c)}${note ? ` ${import_chalk24.default.dim(note)}` : ""}`);
|
|
8022
8065
|
const ok = (text, note = "") => console.log(` ${import_chalk24.default.green("\u2713")} ${text}${note ? ` ${import_chalk24.default.dim(note)}` : ""}`);
|
|
8023
|
-
const stopHere = (lines) => {
|
|
8066
|
+
const stopHere = (step, lines) => {
|
|
8024
8067
|
console.log();
|
|
8025
8068
|
for (const l of lines) console.log(` ${l}`);
|
|
8069
|
+
return `demo-declined-${step}`;
|
|
8026
8070
|
};
|
|
8027
8071
|
titleCard(["Restaurant Reservation Service Demo", `ResiResi, with ${B.product} in front`]);
|
|
8028
8072
|
await stopDemos();
|
|
@@ -8049,16 +8093,16 @@ paths:`));
|
|
|
8049
8093
|
for (const r of routesOf(openapi)) console.log(` ${r.method.padEnd(7)}${r.path.padEnd(21)}${import_chalk24.default.dim(r.summary)}`);
|
|
8050
8094
|
console.log(import_chalk24.default.dim(" No login, no API keys, no permission checks in its code. It only checks one shared backend secret (in .env.local)."));
|
|
8051
8095
|
if (!await confirmStep(opts, `Ok to serve the backend on localhost:${backendPort2}?`)) {
|
|
8052
|
-
return stopHere([
|
|
8096
|
+
return stopHere("backend", [
|
|
8053
8097
|
`Stopped before starting anything. ResiResi is written to ${rel}.`,
|
|
8054
8098
|
`Start it any time: ${cdDir}npm run start ${import_chalk24.default.dim("\xB7")} or run the whole demo again: ${LATEST} demo`
|
|
8055
8099
|
]);
|
|
8056
8100
|
}
|
|
8057
8101
|
shell(`${cdDir}npm run start`, "npm run stop \xB7 npm run restart");
|
|
8058
|
-
if (!appCtl(dir, "--background")) throw new DemoError("The ResiResi app could not start.", `Run again: ${LATEST} demo
|
|
8102
|
+
if (!appCtl(dir, "--background")) throw new DemoError("The ResiResi app could not start.", `Run again: ${LATEST} demo`, "app-start");
|
|
8059
8103
|
registerDemo(dir);
|
|
8060
8104
|
const appUp = await busy("Starting the reservation backend and its front-end\u2026", () => waitPorts([backendPort2, directPort]), 1800);
|
|
8061
|
-
if (!appUp) throw new DemoError(`The ResiResi app did not start (see ${import_path5.default.join(rel, STATE_DIR, "app.log")}).`, `Run again: ${LATEST} demo
|
|
8105
|
+
if (!appUp) throw new DemoError(`The ResiResi app did not start (see ${import_path5.default.join(rel, STATE_DIR, "app.log")}).`, `Run again: ${LATEST} demo`, "app-not-up");
|
|
8062
8106
|
ok(`${import_chalk24.default.bold("Reservation backend")}: localhost:${backendPort2}`, "unprotected");
|
|
8063
8107
|
ok(`${import_chalk24.default.bold("Unprotected reservation front-end")}, going directly to the reservation backend: ${import_chalk24.default.bold(`http://localhost:${directPort}`)}`);
|
|
8064
8108
|
console.log(" Book a table directly, the way the unprotected front-end does:");
|
|
@@ -8067,7 +8111,7 @@ paths:`));
|
|
|
8067
8111
|
console.log(import_chalk24.default.cyan(` -H "x-abz-user-id: ana" -H "x-abz-tenant-id: ${ninoTenant}" \\`));
|
|
8068
8112
|
console.log(import_chalk24.default.cyan(` -H "content-type: application/json" -d '{"time":"19:30","guests":2}'`));
|
|
8069
8113
|
if (!await confirmStep(opts, `Ok to put an ${B.product} proxy and MCP in front of the reservation backend?`)) {
|
|
8070
|
-
return stopHere([
|
|
8114
|
+
return stopHere("proxy", [
|
|
8071
8115
|
`Stopped before ${B.product}. ResiResi keeps running on this laptop: http://localhost:${directPort} ${import_chalk24.default.dim(`(${cdDir}npm run stop stops it)`)}`,
|
|
8072
8116
|
`Run the whole demo again any time: ${LATEST} demo`
|
|
8073
8117
|
]);
|
|
@@ -8086,7 +8130,7 @@ paths:`));
|
|
|
8086
8130
|
const rr = r;
|
|
8087
8131
|
const tenant3 = rr.tenant ?? tenantFromPortal(rr.portal ?? rr.devPortal) ?? "";
|
|
8088
8132
|
const missing = [!cpKey2 && "workspace key", !teamId2 && "team", !serverKey2 && "API key", !tenant3 && "tenant"].filter(Boolean);
|
|
8089
|
-
if (missing.length) throw new DemoError(`${B.product} did not return everything the demo needs (${missing.join(", ")}).`, `Run again: ${LATEST} demo
|
|
8133
|
+
if (missing.length) throw new DemoError(`${B.product} did not return everything the demo needs (${missing.join(", ")}).`, `Run again: ${LATEST} demo`, "setup-incomplete");
|
|
8090
8134
|
const createSecs2 = ((Date.now() - tCreate) / 1e3).toFixed(1);
|
|
8091
8135
|
adoptWorkspace(cpKey2, teamId2, rr.claim_code);
|
|
8092
8136
|
const cp = (p, init) => cpFetch(cpKey2, p, init).then(() => true).catch(() => false);
|
|
@@ -8108,7 +8152,7 @@ paths:`));
|
|
|
8108
8152
|
return { limited: lim, secretOk: sec };
|
|
8109
8153
|
})()
|
|
8110
8154
|
]);
|
|
8111
|
-
if (!secretOk) throw new DemoError(`Could not give ${B.product} the backend secret.`, `Run again: ${LATEST} demo
|
|
8155
|
+
if (!secretOk) throw new DemoError(`Could not give ${B.product} the backend secret.`, `Run again: ${LATEST} demo`, "secret-failed");
|
|
8112
8156
|
return { cpKey: cpKey2, teamId: teamId2, serverKey: serverKey2, project: project2, version: version3, tenant: tenant3, gino: gino2, createSecs: createSecs2, adminOk: adminOk2, ginaOk: ginaOk2, limited: limited2, claimCode: rr.claim_code, applied: rr.secure?.applied ?? [] };
|
|
8113
8157
|
});
|
|
8114
8158
|
const { cpKey, teamId, serverKey, project, version: version2, tenant: tenant2, gino, createSecs, adminOk, ginaOk, limited } = setup;
|
|
@@ -8160,7 +8204,7 @@ paths:`));
|
|
|
8160
8204
|
}
|
|
8161
8205
|
]);
|
|
8162
8206
|
if (!await confirmStep(opts, `Ok to create a tunnel allowing ${project} to forward requests to localhost:${backendPort2}?`)) {
|
|
8163
|
-
return stopHere([
|
|
8207
|
+
return stopHere("tunnel", [
|
|
8164
8208
|
`Stopped before the tunnel. The proxy exists but cannot reach this laptop yet.`,
|
|
8165
8209
|
`Open the tunnel any time: ${LATEST} demo start`
|
|
8166
8210
|
]);
|
|
@@ -8175,7 +8219,7 @@ paths:`));
|
|
|
8175
8219
|
ok(`${import_chalk24.default.bold("Tunnel")}: the public address reaches localhost:${backendPort2} on this laptop`, `checked with a real call \xB7 ${Math.round((Date.now() - t0) / 1e3)} s so far`);
|
|
8176
8220
|
printAddresses(dir);
|
|
8177
8221
|
if (!await confirmStep(opts, "Ok to launch the protected website, which will use the proxy to reach the backend?")) {
|
|
8178
|
-
return stopHere([
|
|
8222
|
+
return stopHere("website", [
|
|
8179
8223
|
`Stopped before the protected website. The API and MCP addresses above work now.`,
|
|
8180
8224
|
`Start the website any time: ${cdDir}npm run restart`
|
|
8181
8225
|
]);
|
|
@@ -8188,12 +8232,13 @@ paths:`));
|
|
|
8188
8232
|
appCtl(dir, "--background");
|
|
8189
8233
|
return waitPorts([appPort, directPort, backendPort2]);
|
|
8190
8234
|
}, 1500);
|
|
8191
|
-
if (!siteUp) throw new DemoError(`The protected website did not start (see ${import_path5.default.join(rel, STATE_DIR, "app.log")}).`, `Try: ${cdDir}npm run restart
|
|
8235
|
+
if (!siteUp) throw new DemoError(`The protected website did not start (see ${import_path5.default.join(rel, STATE_DIR, "app.log")}).`, `Try: ${cdDir}npm run restart`, "site-not-up");
|
|
8192
8236
|
ok(`${import_chalk24.default.bold("Protected reservation website")}, going through the ${B.product} proxy ${apiUrl}: ${import_chalk24.default.bold(`http://localhost:${appPort}`)}`);
|
|
8193
8237
|
ok(`${import_chalk24.default.bold("Unprotected reservation front-end")}, still going directly to the backend: http://localhost:${directPort}`, "the switch at the top of the page goes between them");
|
|
8194
8238
|
console.log();
|
|
8195
8239
|
console.log(import_chalk24.default.dim(` Logs: ${logsCommand(readEnvFile(import_path5.default.join(dir, ".env.local")))} \xB7 Stop the tunnel: ${LATEST} demo stop \xB7 Your own app: ${LATEST} dev --port <port>`));
|
|
8196
8240
|
await offerBrowserAndLogs(dir, opts);
|
|
8241
|
+
return "demo-ready";
|
|
8197
8242
|
}
|
|
8198
8243
|
function printAddresses(dir) {
|
|
8199
8244
|
const env = readEnvFile(import_path5.default.join(dir, ".env.local"));
|
|
@@ -8204,7 +8249,7 @@ function printAddresses(dir) {
|
|
|
8204
8249
|
}
|
|
8205
8250
|
async function spawnTunnel(dir, state) {
|
|
8206
8251
|
const log4 = import_fs6.default.openSync(import_path5.default.join(dir, STATE_DIR, "tunnel.log"), "a");
|
|
8207
|
-
const child = (0,
|
|
8252
|
+
const child = (0, import_child_process5.spawn)(process.execPath, [process.argv[1], "demo", "--serve", dir], { cwd: dir, detached: true, stdio: ["ignore", log4, log4] });
|
|
8208
8253
|
child.unref();
|
|
8209
8254
|
saveState(dir, { ...state, pid: child.pid, ready: false, error: void 0 });
|
|
8210
8255
|
registerDemo(dir, child.pid ?? 0);
|
|
@@ -8225,10 +8270,12 @@ async function runDemoStart(opts = {}) {
|
|
|
8225
8270
|
await spawnTunnel(dir, state);
|
|
8226
8271
|
} catch (err) {
|
|
8227
8272
|
const e = err instanceof DemoError ? err : new DemoError(`The tunnel could not start (${err.message}).`, `Start over: ${LATEST} demo`);
|
|
8273
|
+
countRun({ event: `demo-restart-failed-${e.why}` });
|
|
8228
8274
|
console.log(`${import_chalk24.default.red("\u2717")} ${e.message}`);
|
|
8229
8275
|
console.log(` ${e.fix}`);
|
|
8230
8276
|
process.exit(1);
|
|
8231
8277
|
}
|
|
8278
|
+
countRun({ event: "demo-restarted" });
|
|
8232
8279
|
console.log(`${import_chalk24.default.green("\u2713")} Tunnel open: the public address reaches localhost:${env.BACKEND_PORT} again ${import_chalk24.default.dim(`(${Math.round((Date.now() - t0) / 1e3)} s)`)}`);
|
|
8233
8280
|
printAddresses(dir);
|
|
8234
8281
|
const appUp = await fetch(`http://127.0.0.1:${env.APP_PORT}/api/config`).then(() => true).catch(() => false);
|
|
@@ -8306,14 +8353,14 @@ async function serveTunnel(dir) {
|
|
|
8306
8353
|
await new Promise(() => {
|
|
8307
8354
|
});
|
|
8308
8355
|
}
|
|
8309
|
-
var import_fs6, import_path5, import_net2,
|
|
8356
|
+
var import_fs6, import_path5, import_net2, import_child_process5, import_crypto, import_chalk24, import_ora9, DIR_NAME, STATE_DIR, LATEST, DEMO_RPS, DEMO_ADMIN_EMAIL, DEMO_GINO_ADMIN_EMAIL, RULE_SENTENCE, DemoError, ADJ, NOUN, pick2, registryFile, alive, interactive, logsCommand;
|
|
8310
8357
|
var init_demo = __esm({
|
|
8311
8358
|
"src/commands/demo.ts"() {
|
|
8312
8359
|
"use strict";
|
|
8313
8360
|
import_fs6 = __toESM(require("fs"));
|
|
8314
8361
|
import_path5 = __toESM(require("path"));
|
|
8315
8362
|
import_net2 = __toESM(require("net"));
|
|
8316
|
-
|
|
8363
|
+
import_child_process5 = require("child_process");
|
|
8317
8364
|
import_crypto = __toESM(require("crypto"));
|
|
8318
8365
|
import_chalk24 = __toESM(require("chalk"));
|
|
8319
8366
|
import_ora9 = __toESM(require("ora"));
|
|
@@ -8332,9 +8379,10 @@ var init_demo = __esm({
|
|
|
8332
8379
|
DEMO_GINO_ADMIN_EMAIL = "gina@ginopizza.example";
|
|
8333
8380
|
RULE_SENTENCE = "Only the person who made a reservation can change or cancel it";
|
|
8334
8381
|
DemoError = class extends Error {
|
|
8335
|
-
constructor(message, fix) {
|
|
8382
|
+
constructor(message, fix, why = "unexpected") {
|
|
8336
8383
|
super(message);
|
|
8337
8384
|
this.fix = fix;
|
|
8385
|
+
this.why = why;
|
|
8338
8386
|
}
|
|
8339
8387
|
};
|
|
8340
8388
|
ADJ = ["brave", "calm", "clever", "eager", "happy", "jolly", "lucky", "merry", "noble", "quick", "sunny", "swift", "witty", "zesty", "bright", "gentle"];
|
|
@@ -8587,7 +8635,7 @@ __export(op_anon_exports, {
|
|
|
8587
8635
|
function runCli(args, cwd, home, timeoutMs) {
|
|
8588
8636
|
return new Promise((resolve4) => {
|
|
8589
8637
|
const t0 = Date.now();
|
|
8590
|
-
const child = (0,
|
|
8638
|
+
const child = (0, import_child_process6.spawn)(process.execPath, [process.argv[1], ...args], { cwd, env: { ...process.env, HOME: home, USERPROFILE: home }, stdio: ["ignore", "pipe", "pipe"] });
|
|
8591
8639
|
let out = "";
|
|
8592
8640
|
child.stdout.on("data", (d) => {
|
|
8593
8641
|
out += d;
|
|
@@ -8721,7 +8769,7 @@ async function runOpAnon(o = {}) {
|
|
|
8721
8769
|
const demoFolder = import_path7.default.join(work, `${B.cli}-demo`);
|
|
8722
8770
|
if (import_fs10.default.existsSync(import_path7.default.join(demoFolder, "start.js"))) {
|
|
8723
8771
|
await new Promise((res) => {
|
|
8724
|
-
const c = (0,
|
|
8772
|
+
const c = (0, import_child_process6.spawn)(process.execPath, [import_path7.default.join(demoFolder, "start.js"), "--stop"], { cwd: demoFolder, stdio: "ignore" });
|
|
8725
8773
|
c.on("close", () => res());
|
|
8726
8774
|
});
|
|
8727
8775
|
}
|
|
@@ -8745,14 +8793,14 @@ async function runOpAnon(o = {}) {
|
|
|
8745
8793
|
if (failed) process.exitCode = 1;
|
|
8746
8794
|
return { ok: !failed, checks };
|
|
8747
8795
|
}
|
|
8748
|
-
var import_fs10, import_os3, import_path7,
|
|
8796
|
+
var import_fs10, import_os3, import_path7, import_child_process6, import_chalk70, SECRET;
|
|
8749
8797
|
var init_op_anon = __esm({
|
|
8750
8798
|
"src/commands/op-anon.ts"() {
|
|
8751
8799
|
"use strict";
|
|
8752
8800
|
import_fs10 = __toESM(require("fs"));
|
|
8753
8801
|
import_os3 = __toESM(require("os"));
|
|
8754
8802
|
import_path7 = __toESM(require("path"));
|
|
8755
|
-
|
|
8803
|
+
import_child_process6 = require("child_process");
|
|
8756
8804
|
import_chalk70 = __toESM(require("chalk"));
|
|
8757
8805
|
init_brand();
|
|
8758
8806
|
SECRET = /\bsk_(?:dev|test|prod)_[A-Za-z0-9]{6,}/;
|
|
@@ -9546,6 +9594,7 @@ function backendPort(f) {
|
|
|
9546
9594
|
}
|
|
9547
9595
|
|
|
9548
9596
|
// src/commands/skill.ts
|
|
9597
|
+
init_api();
|
|
9549
9598
|
var SKILL_NAME = "ship-safely";
|
|
9550
9599
|
var SKILL_RELATIVE_PATH = import_path6.default.join(".claude", "skills", SKILL_NAME, "SKILL.md");
|
|
9551
9600
|
var CP_TOOLS = [
|
|
@@ -10189,6 +10238,7 @@ async function runForPerson(found) {
|
|
|
10189
10238
|
await runDemo2({});
|
|
10190
10239
|
}
|
|
10191
10240
|
async function runSkill(opts = {}) {
|
|
10241
|
+
countRun();
|
|
10192
10242
|
if (opts.install) return installSkill(opts);
|
|
10193
10243
|
if (opts.static) {
|
|
10194
10244
|
process.stdout.write(skillMarkdown());
|
|
@@ -13482,10 +13532,10 @@ async function runBillingTopup(amount, opts) {
|
|
|
13482
13532
|
if (c?.auto_rebuy?.enabled) console.log(import_chalk48.default.dim(` Auto-rebuy is on (${money(c.auto_rebuy.amount_cents)} under ${money(c.auto_rebuy.threshold_cents)}).`));
|
|
13483
13533
|
else console.log(import_chalk48.default.dim(` Never run dry: ${B.cli} billing rebuy on --amount 50 --threshold 10`));
|
|
13484
13534
|
if (opts.open) {
|
|
13485
|
-
const { spawn:
|
|
13535
|
+
const { spawn: spawn5 } = await import("child_process");
|
|
13486
13536
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
13487
13537
|
try {
|
|
13488
|
-
|
|
13538
|
+
spawn5(cmd, [url], { stdio: "ignore", detached: true }).unref();
|
|
13489
13539
|
} catch {
|
|
13490
13540
|
}
|
|
13491
13541
|
}
|