apiblaze 0.21.40 → 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 +29 -22
- 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
|
|
|
@@ -394,12 +394,13 @@ __export(api_exports, {
|
|
|
394
394
|
});
|
|
395
395
|
function countRun(opts = {}) {
|
|
396
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;
|
|
397
398
|
try {
|
|
398
399
|
const child = (0, import_child_process.spawn)(process.execPath, ["-e", COUNT_RUN_CHILD], {
|
|
399
400
|
detached: true,
|
|
400
401
|
stdio: "ignore",
|
|
401
402
|
windowsHide: true,
|
|
402
|
-
env: { ...process.env, ABZ_COUNT_URL: opts.url ?? `${PUBLIC_API_BASE}/cli/hello
|
|
403
|
+
env: { ...process.env, ABZ_COUNT_URL: (opts.url ?? `${PUBLIC_API_BASE}/cli/hello`) + (opts.event ? `/${opts.event}` : ""), ABZ_COUNT_HEADERS: JSON.stringify(cliHeaders()) }
|
|
403
404
|
});
|
|
404
405
|
child.on("error", () => {
|
|
405
406
|
});
|
|
@@ -7720,7 +7721,7 @@ async function portFree(port) {
|
|
|
7720
7721
|
}
|
|
7721
7722
|
async function freePort(from, avoid = []) {
|
|
7722
7723
|
for (let p = from; p < from + 200; p++) if (!avoid.includes(p) && await portFree(p)) return p;
|
|
7723
|
-
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");
|
|
7724
7725
|
}
|
|
7725
7726
|
function readRegistry() {
|
|
7726
7727
|
try {
|
|
@@ -7901,19 +7902,19 @@ async function createProxy2(name, backendPort2, openapi, tenantName) {
|
|
|
7901
7902
|
return await createProxyAnonymous(body);
|
|
7902
7903
|
} catch (err) {
|
|
7903
7904
|
const status2 = err.status;
|
|
7904
|
-
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
|
|
7905
|
-
if (status2 && status2 >= 500) throw new DemoError(`${B.product} is having trouble right now.`, `Try again in a minute: ${LATEST} demo
|
|
7906
|
-
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");
|
|
7907
7908
|
}
|
|
7908
7909
|
}
|
|
7909
7910
|
async function waitTunnel(dir) {
|
|
7910
7911
|
for (let i = 0; i < 200; i++) {
|
|
7911
7912
|
const st = loadState(dir);
|
|
7912
|
-
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");
|
|
7913
7914
|
if (st?.ready) return;
|
|
7914
7915
|
await new Promise((r) => setTimeout(r, 100));
|
|
7915
7916
|
}
|
|
7916
|
-
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");
|
|
7917
7918
|
}
|
|
7918
7919
|
async function waitThrough(apiUrl, serverKey) {
|
|
7919
7920
|
let last = 0;
|
|
@@ -7922,13 +7923,13 @@ async function waitThrough(apiUrl, serverKey) {
|
|
|
7922
7923
|
const r = await fetch(`${apiUrl}/reservations`, { headers: { "x-api-key": serverKey, "x-end-user-id": "ana" } });
|
|
7923
7924
|
last = r.status;
|
|
7924
7925
|
if (r.status === 200) return;
|
|
7925
|
-
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");
|
|
7926
7927
|
} catch (e) {
|
|
7927
7928
|
if (e instanceof DemoError) throw e;
|
|
7928
7929
|
}
|
|
7929
7930
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
7930
7931
|
}
|
|
7931
|
-
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}`);
|
|
7932
7933
|
}
|
|
7933
7934
|
async function confirmStep(opts, question) {
|
|
7934
7935
|
if (opts.yes || !interactive()) return true;
|
|
@@ -8003,9 +8004,10 @@ function routesOf(openapi) {
|
|
|
8003
8004
|
async function runDemo(opts = {}) {
|
|
8004
8005
|
if (opts.serve) return serveTunnel(import_path5.default.resolve(opts.serve));
|
|
8005
8006
|
try {
|
|
8006
|
-
await startDemo(opts);
|
|
8007
|
+
countRun({ event: await startDemo(opts) });
|
|
8007
8008
|
} catch (err) {
|
|
8008
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}` });
|
|
8009
8011
|
await stopDemos().catch(() => 0);
|
|
8010
8012
|
console.log(`${import_chalk24.default.red("\u2717")} ${e.message}`);
|
|
8011
8013
|
console.log(` ${e.fix}`);
|
|
@@ -8061,9 +8063,10 @@ async function startDemo(opts) {
|
|
|
8061
8063
|
const cdDir = rel === "." ? "" : `cd ${rel} && `;
|
|
8062
8064
|
const shell = (c, note = "") => console.log(` ${import_chalk24.default.dim("$")} ${import_chalk24.default.cyan(c)}${note ? ` ${import_chalk24.default.dim(note)}` : ""}`);
|
|
8063
8065
|
const ok = (text, note = "") => console.log(` ${import_chalk24.default.green("\u2713")} ${text}${note ? ` ${import_chalk24.default.dim(note)}` : ""}`);
|
|
8064
|
-
const stopHere = (lines) => {
|
|
8066
|
+
const stopHere = (step, lines) => {
|
|
8065
8067
|
console.log();
|
|
8066
8068
|
for (const l of lines) console.log(` ${l}`);
|
|
8069
|
+
return `demo-declined-${step}`;
|
|
8067
8070
|
};
|
|
8068
8071
|
titleCard(["Restaurant Reservation Service Demo", `ResiResi, with ${B.product} in front`]);
|
|
8069
8072
|
await stopDemos();
|
|
@@ -8090,16 +8093,16 @@ paths:`));
|
|
|
8090
8093
|
for (const r of routesOf(openapi)) console.log(` ${r.method.padEnd(7)}${r.path.padEnd(21)}${import_chalk24.default.dim(r.summary)}`);
|
|
8091
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)."));
|
|
8092
8095
|
if (!await confirmStep(opts, `Ok to serve the backend on localhost:${backendPort2}?`)) {
|
|
8093
|
-
return stopHere([
|
|
8096
|
+
return stopHere("backend", [
|
|
8094
8097
|
`Stopped before starting anything. ResiResi is written to ${rel}.`,
|
|
8095
8098
|
`Start it any time: ${cdDir}npm run start ${import_chalk24.default.dim("\xB7")} or run the whole demo again: ${LATEST} demo`
|
|
8096
8099
|
]);
|
|
8097
8100
|
}
|
|
8098
8101
|
shell(`${cdDir}npm run start`, "npm run stop \xB7 npm run restart");
|
|
8099
|
-
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");
|
|
8100
8103
|
registerDemo(dir);
|
|
8101
8104
|
const appUp = await busy("Starting the reservation backend and its front-end\u2026", () => waitPorts([backendPort2, directPort]), 1800);
|
|
8102
|
-
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");
|
|
8103
8106
|
ok(`${import_chalk24.default.bold("Reservation backend")}: localhost:${backendPort2}`, "unprotected");
|
|
8104
8107
|
ok(`${import_chalk24.default.bold("Unprotected reservation front-end")}, going directly to the reservation backend: ${import_chalk24.default.bold(`http://localhost:${directPort}`)}`);
|
|
8105
8108
|
console.log(" Book a table directly, the way the unprotected front-end does:");
|
|
@@ -8108,7 +8111,7 @@ paths:`));
|
|
|
8108
8111
|
console.log(import_chalk24.default.cyan(` -H "x-abz-user-id: ana" -H "x-abz-tenant-id: ${ninoTenant}" \\`));
|
|
8109
8112
|
console.log(import_chalk24.default.cyan(` -H "content-type: application/json" -d '{"time":"19:30","guests":2}'`));
|
|
8110
8113
|
if (!await confirmStep(opts, `Ok to put an ${B.product} proxy and MCP in front of the reservation backend?`)) {
|
|
8111
|
-
return stopHere([
|
|
8114
|
+
return stopHere("proxy", [
|
|
8112
8115
|
`Stopped before ${B.product}. ResiResi keeps running on this laptop: http://localhost:${directPort} ${import_chalk24.default.dim(`(${cdDir}npm run stop stops it)`)}`,
|
|
8113
8116
|
`Run the whole demo again any time: ${LATEST} demo`
|
|
8114
8117
|
]);
|
|
@@ -8127,7 +8130,7 @@ paths:`));
|
|
|
8127
8130
|
const rr = r;
|
|
8128
8131
|
const tenant3 = rr.tenant ?? tenantFromPortal(rr.portal ?? rr.devPortal) ?? "";
|
|
8129
8132
|
const missing = [!cpKey2 && "workspace key", !teamId2 && "team", !serverKey2 && "API key", !tenant3 && "tenant"].filter(Boolean);
|
|
8130
|
-
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");
|
|
8131
8134
|
const createSecs2 = ((Date.now() - tCreate) / 1e3).toFixed(1);
|
|
8132
8135
|
adoptWorkspace(cpKey2, teamId2, rr.claim_code);
|
|
8133
8136
|
const cp = (p, init) => cpFetch(cpKey2, p, init).then(() => true).catch(() => false);
|
|
@@ -8149,7 +8152,7 @@ paths:`));
|
|
|
8149
8152
|
return { limited: lim, secretOk: sec };
|
|
8150
8153
|
})()
|
|
8151
8154
|
]);
|
|
8152
|
-
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");
|
|
8153
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 ?? [] };
|
|
8154
8157
|
});
|
|
8155
8158
|
const { cpKey, teamId, serverKey, project, version: version2, tenant: tenant2, gino, createSecs, adminOk, ginaOk, limited } = setup;
|
|
@@ -8201,7 +8204,7 @@ paths:`));
|
|
|
8201
8204
|
}
|
|
8202
8205
|
]);
|
|
8203
8206
|
if (!await confirmStep(opts, `Ok to create a tunnel allowing ${project} to forward requests to localhost:${backendPort2}?`)) {
|
|
8204
|
-
return stopHere([
|
|
8207
|
+
return stopHere("tunnel", [
|
|
8205
8208
|
`Stopped before the tunnel. The proxy exists but cannot reach this laptop yet.`,
|
|
8206
8209
|
`Open the tunnel any time: ${LATEST} demo start`
|
|
8207
8210
|
]);
|
|
@@ -8216,7 +8219,7 @@ paths:`));
|
|
|
8216
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`);
|
|
8217
8220
|
printAddresses(dir);
|
|
8218
8221
|
if (!await confirmStep(opts, "Ok to launch the protected website, which will use the proxy to reach the backend?")) {
|
|
8219
|
-
return stopHere([
|
|
8222
|
+
return stopHere("website", [
|
|
8220
8223
|
`Stopped before the protected website. The API and MCP addresses above work now.`,
|
|
8221
8224
|
`Start the website any time: ${cdDir}npm run restart`
|
|
8222
8225
|
]);
|
|
@@ -8229,12 +8232,13 @@ paths:`));
|
|
|
8229
8232
|
appCtl(dir, "--background");
|
|
8230
8233
|
return waitPorts([appPort, directPort, backendPort2]);
|
|
8231
8234
|
}, 1500);
|
|
8232
|
-
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");
|
|
8233
8236
|
ok(`${import_chalk24.default.bold("Protected reservation website")}, going through the ${B.product} proxy ${apiUrl}: ${import_chalk24.default.bold(`http://localhost:${appPort}`)}`);
|
|
8234
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");
|
|
8235
8238
|
console.log();
|
|
8236
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>`));
|
|
8237
8240
|
await offerBrowserAndLogs(dir, opts);
|
|
8241
|
+
return "demo-ready";
|
|
8238
8242
|
}
|
|
8239
8243
|
function printAddresses(dir) {
|
|
8240
8244
|
const env = readEnvFile(import_path5.default.join(dir, ".env.local"));
|
|
@@ -8266,10 +8270,12 @@ async function runDemoStart(opts = {}) {
|
|
|
8266
8270
|
await spawnTunnel(dir, state);
|
|
8267
8271
|
} catch (err) {
|
|
8268
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}` });
|
|
8269
8274
|
console.log(`${import_chalk24.default.red("\u2717")} ${e.message}`);
|
|
8270
8275
|
console.log(` ${e.fix}`);
|
|
8271
8276
|
process.exit(1);
|
|
8272
8277
|
}
|
|
8278
|
+
countRun({ event: "demo-restarted" });
|
|
8273
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)`)}`);
|
|
8274
8280
|
printAddresses(dir);
|
|
8275
8281
|
const appUp = await fetch(`http://127.0.0.1:${env.APP_PORT}/api/config`).then(() => true).catch(() => false);
|
|
@@ -8373,9 +8379,10 @@ var init_demo = __esm({
|
|
|
8373
8379
|
DEMO_GINO_ADMIN_EMAIL = "gina@ginopizza.example";
|
|
8374
8380
|
RULE_SENTENCE = "Only the person who made a reservation can change or cancel it";
|
|
8375
8381
|
DemoError = class extends Error {
|
|
8376
|
-
constructor(message, fix) {
|
|
8382
|
+
constructor(message, fix, why = "unexpected") {
|
|
8377
8383
|
super(message);
|
|
8378
8384
|
this.fix = fix;
|
|
8385
|
+
this.why = why;
|
|
8379
8386
|
}
|
|
8380
8387
|
};
|
|
8381
8388
|
ADJ = ["brave", "calm", "clever", "eager", "happy", "jolly", "lucky", "merry", "noble", "quick", "sunny", "swift", "witty", "zesty", "bright", "gentle"];
|