@forinda/kickjs-cli 0.6.0 → 0.7.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.
- package/dist/cli.js +175 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.js +13 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,6 +4,9 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
4
4
|
|
|
5
5
|
// src/cli.ts
|
|
6
6
|
import { Command } from "commander";
|
|
7
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
8
|
+
import { dirname as dirname3, join as join11 } from "path";
|
|
9
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
7
10
|
|
|
8
11
|
// src/commands/init.ts
|
|
9
12
|
import { resolve, basename } from "path";
|
|
@@ -11,8 +14,10 @@ import { createInterface } from "readline";
|
|
|
11
14
|
import { existsSync, readdirSync, rmSync } from "fs";
|
|
12
15
|
|
|
13
16
|
// src/generators/project.ts
|
|
14
|
-
import { join } from "path";
|
|
17
|
+
import { join, dirname as dirname2 } from "path";
|
|
15
18
|
import { execSync } from "child_process";
|
|
19
|
+
import { readFileSync } from "fs";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
16
21
|
|
|
17
22
|
// src/utils/fs.ts
|
|
18
23
|
import { writeFile, mkdir, access, readFile } from "fs/promises";
|
|
@@ -35,6 +40,9 @@ async function fileExists(filePath) {
|
|
|
35
40
|
__name(fileExists, "fileExists");
|
|
36
41
|
|
|
37
42
|
// src/generators/project.ts
|
|
43
|
+
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
44
|
+
var cliPkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
45
|
+
var KICKJS_VERSION = `^${cliPkg.version}`;
|
|
38
46
|
async function initProject(options) {
|
|
39
47
|
const { name, directory, packageManager = "pnpm" } = options;
|
|
40
48
|
const dir = directory;
|
|
@@ -43,7 +51,7 @@ async function initProject(options) {
|
|
|
43
51
|
`);
|
|
44
52
|
await writeFileSafe(join(dir, "package.json"), JSON.stringify({
|
|
45
53
|
name,
|
|
46
|
-
version:
|
|
54
|
+
version: cliPkg.version,
|
|
47
55
|
type: "module",
|
|
48
56
|
scripts: {
|
|
49
57
|
dev: "kick dev",
|
|
@@ -57,10 +65,10 @@ async function initProject(options) {
|
|
|
57
65
|
format: "prettier --write src/"
|
|
58
66
|
},
|
|
59
67
|
dependencies: {
|
|
60
|
-
"@forinda/kickjs-core":
|
|
61
|
-
"@forinda/kickjs-http":
|
|
62
|
-
"@forinda/kickjs-config":
|
|
63
|
-
"@forinda/kickjs-swagger":
|
|
68
|
+
"@forinda/kickjs-core": KICKJS_VERSION,
|
|
69
|
+
"@forinda/kickjs-http": KICKJS_VERSION,
|
|
70
|
+
"@forinda/kickjs-config": KICKJS_VERSION,
|
|
71
|
+
"@forinda/kickjs-swagger": KICKJS_VERSION,
|
|
64
72
|
express: "^5.1.0",
|
|
65
73
|
"reflect-metadata": "^0.2.2",
|
|
66
74
|
zod: "^4.3.6",
|
|
@@ -68,7 +76,7 @@ async function initProject(options) {
|
|
|
68
76
|
"pino-pretty": "^13.1.3"
|
|
69
77
|
},
|
|
70
78
|
devDependencies: {
|
|
71
|
-
"@forinda/kickjs-cli":
|
|
79
|
+
"@forinda/kickjs-cli": KICKJS_VERSION,
|
|
72
80
|
"@swc/core": "^1.7.28",
|
|
73
81
|
"@types/express": "^5.0.6",
|
|
74
82
|
"@types/node": "^24.5.2",
|
|
@@ -166,7 +174,7 @@ bootstrap({
|
|
|
166
174
|
modules,
|
|
167
175
|
adapters: [
|
|
168
176
|
new SwaggerAdapter({
|
|
169
|
-
info: { title: '${name}', version: '
|
|
177
|
+
info: { title: '${name}', version: '${cliPkg.version}' },
|
|
170
178
|
}),
|
|
171
179
|
],
|
|
172
180
|
})
|
|
@@ -1650,6 +1658,161 @@ function registerSingleCommand(program, def) {
|
|
|
1650
1658
|
}
|
|
1651
1659
|
__name(registerSingleCommand, "registerSingleCommand");
|
|
1652
1660
|
|
|
1661
|
+
// src/commands/inspect.ts
|
|
1662
|
+
var esc = /* @__PURE__ */ __name((code) => `\x1B[${code}m`, "esc");
|
|
1663
|
+
var reset = esc("0");
|
|
1664
|
+
var bold = /* @__PURE__ */ __name((s) => `${esc("1")}${s}${reset}`, "bold");
|
|
1665
|
+
var dim = /* @__PURE__ */ __name((s) => `${esc("2")}${s}${reset}`, "dim");
|
|
1666
|
+
var green = /* @__PURE__ */ __name((s) => `${esc("32")}${s}${reset}`, "green");
|
|
1667
|
+
var red = /* @__PURE__ */ __name((s) => `${esc("31")}${s}${reset}`, "red");
|
|
1668
|
+
var yellow = /* @__PURE__ */ __name((s) => `${esc("33")}${s}${reset}`, "yellow");
|
|
1669
|
+
var cyan = /* @__PURE__ */ __name((s) => `${esc("36")}${s}${reset}`, "cyan");
|
|
1670
|
+
var magenta = /* @__PURE__ */ __name((s) => `${esc("35")}${s}${reset}`, "magenta");
|
|
1671
|
+
var blue = /* @__PURE__ */ __name((s) => `${esc("34")}${s}${reset}`, "blue");
|
|
1672
|
+
var METHOD_COLORS = {
|
|
1673
|
+
GET: green,
|
|
1674
|
+
POST: cyan,
|
|
1675
|
+
PUT: yellow,
|
|
1676
|
+
PATCH: magenta,
|
|
1677
|
+
DELETE: red
|
|
1678
|
+
};
|
|
1679
|
+
function colorMethod(method) {
|
|
1680
|
+
const fn = METHOD_COLORS[method] ?? dim;
|
|
1681
|
+
return fn(method.padEnd(7));
|
|
1682
|
+
}
|
|
1683
|
+
__name(colorMethod, "colorMethod");
|
|
1684
|
+
function formatUptime(seconds) {
|
|
1685
|
+
const d = Math.floor(seconds / 86400);
|
|
1686
|
+
const h = Math.floor(seconds % 86400 / 3600);
|
|
1687
|
+
const m = Math.floor(seconds % 3600 / 60);
|
|
1688
|
+
const s = seconds % 60;
|
|
1689
|
+
const parts = [];
|
|
1690
|
+
if (d) parts.push(`${d}d`);
|
|
1691
|
+
if (h) parts.push(`${h}h`);
|
|
1692
|
+
if (m) parts.push(`${m}m`);
|
|
1693
|
+
parts.push(`${s}s`);
|
|
1694
|
+
return parts.join(" ");
|
|
1695
|
+
}
|
|
1696
|
+
__name(formatUptime, "formatUptime");
|
|
1697
|
+
async function fetchJson(url) {
|
|
1698
|
+
const res = await fetch(url, {
|
|
1699
|
+
signal: AbortSignal.timeout(5e3)
|
|
1700
|
+
});
|
|
1701
|
+
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`);
|
|
1702
|
+
return res.json();
|
|
1703
|
+
}
|
|
1704
|
+
__name(fetchJson, "fetchJson");
|
|
1705
|
+
async function fetchEndpoint(base, path) {
|
|
1706
|
+
try {
|
|
1707
|
+
return await fetchJson(`${base}${path}`);
|
|
1708
|
+
} catch {
|
|
1709
|
+
return null;
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
__name(fetchEndpoint, "fetchEndpoint");
|
|
1713
|
+
async function fetchAll(base) {
|
|
1714
|
+
const [health, metrics, routes, container, ws] = await Promise.all([
|
|
1715
|
+
fetchEndpoint(base, "/health"),
|
|
1716
|
+
fetchEndpoint(base, "/metrics"),
|
|
1717
|
+
fetchEndpoint(base, "/routes"),
|
|
1718
|
+
fetchEndpoint(base, "/container"),
|
|
1719
|
+
fetchEndpoint(base, "/ws")
|
|
1720
|
+
]);
|
|
1721
|
+
return {
|
|
1722
|
+
health,
|
|
1723
|
+
metrics,
|
|
1724
|
+
routes,
|
|
1725
|
+
container,
|
|
1726
|
+
ws
|
|
1727
|
+
};
|
|
1728
|
+
}
|
|
1729
|
+
__name(fetchAll, "fetchAll");
|
|
1730
|
+
function printSummary(base, data) {
|
|
1731
|
+
const { health, metrics, routes, container, ws } = data;
|
|
1732
|
+
const line = dim("\u2500".repeat(60));
|
|
1733
|
+
console.log();
|
|
1734
|
+
console.log(bold(` KickJS Inspector`) + dim(` \u2192 ${base}`));
|
|
1735
|
+
console.log(line);
|
|
1736
|
+
if (health) {
|
|
1737
|
+
const statusText = health.status === "healthy" ? green("\u25CF healthy") : red("\u25CF " + health.status);
|
|
1738
|
+
console.log(` ${bold("Health:")} ${statusText}`);
|
|
1739
|
+
} else {
|
|
1740
|
+
console.log(` ${bold("Health:")} ${red("\u25CF unreachable")}`);
|
|
1741
|
+
}
|
|
1742
|
+
if (metrics) {
|
|
1743
|
+
const rate = ((metrics.errorRate ?? 0) * 100).toFixed(1);
|
|
1744
|
+
const rateColor = metrics.errorRate > 0.1 ? red : metrics.errorRate > 0 ? yellow : green;
|
|
1745
|
+
console.log(` ${bold("Uptime:")} ${formatUptime(metrics.uptimeSeconds)}`);
|
|
1746
|
+
console.log(` ${bold("Requests:")} ${metrics.requests}`);
|
|
1747
|
+
console.log(` ${bold("Errors:")} ${metrics.serverErrors} server, ${metrics.clientErrors ?? 0} client ${dim("(")}${rateColor(rate + "%")}${dim(")")}`);
|
|
1748
|
+
}
|
|
1749
|
+
if (container) {
|
|
1750
|
+
console.log(` ${bold("DI:")} ${container.count} bindings`);
|
|
1751
|
+
}
|
|
1752
|
+
if (ws && ws.enabled) {
|
|
1753
|
+
console.log(` ${bold("WS:")} ${ws.connections ?? 0} connections, ${ws.namespaces ?? 0} namespaces`);
|
|
1754
|
+
}
|
|
1755
|
+
if (routes?.routes?.length) {
|
|
1756
|
+
console.log();
|
|
1757
|
+
console.log(bold(" Routes"));
|
|
1758
|
+
console.log(line);
|
|
1759
|
+
console.log(` ${dim("METHOD")} ${dim("PATH".padEnd(36))} ${dim("CONTROLLER")}`);
|
|
1760
|
+
for (const r of routes.routes) {
|
|
1761
|
+
const path = r.path.length > 36 ? r.path.slice(0, 33) + "..." : r.path.padEnd(36);
|
|
1762
|
+
console.log(` ${colorMethod(r.method)} ${path} ${blue(r.controller)}.${dim(r.handler)}`);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
console.log(line);
|
|
1766
|
+
console.log();
|
|
1767
|
+
}
|
|
1768
|
+
__name(printSummary, "printSummary");
|
|
1769
|
+
function registerInspectCommand(program) {
|
|
1770
|
+
program.command("inspect [url]").description("Connect to a running KickJS app and display debug info").option("-p, --port <port>", "Override port").option("-w, --watch", "Poll every 5 seconds").option("-j, --json", "Output raw JSON").action(async (url, opts) => {
|
|
1771
|
+
let base = url ?? "http://localhost:3000";
|
|
1772
|
+
if (opts.port) {
|
|
1773
|
+
try {
|
|
1774
|
+
const parsed = new URL(base);
|
|
1775
|
+
parsed.port = opts.port;
|
|
1776
|
+
base = parsed.origin;
|
|
1777
|
+
} catch {
|
|
1778
|
+
base = `http://localhost:${opts.port}`;
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
const debugBase = `${base.replace(/\/$/, "")}/_debug`;
|
|
1782
|
+
const run = /* @__PURE__ */ __name(async () => {
|
|
1783
|
+
try {
|
|
1784
|
+
const data = await fetchAll(debugBase);
|
|
1785
|
+
if (opts.json) {
|
|
1786
|
+
console.log(JSON.stringify(data, null, 2));
|
|
1787
|
+
} else {
|
|
1788
|
+
printSummary(base, data);
|
|
1789
|
+
}
|
|
1790
|
+
} catch (err) {
|
|
1791
|
+
if (opts.json) {
|
|
1792
|
+
console.log(JSON.stringify({
|
|
1793
|
+
error: String(err)
|
|
1794
|
+
}));
|
|
1795
|
+
} else {
|
|
1796
|
+
console.error(red(` \u2716 Could not connect to ${base}`));
|
|
1797
|
+
console.error(dim(` ${err instanceof Error ? err.message : String(err)}`));
|
|
1798
|
+
}
|
|
1799
|
+
if (!opts.watch) process.exitCode = 1;
|
|
1800
|
+
}
|
|
1801
|
+
}, "run");
|
|
1802
|
+
if (opts.watch) {
|
|
1803
|
+
const poll = /* @__PURE__ */ __name(async () => {
|
|
1804
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
1805
|
+
await run();
|
|
1806
|
+
}, "poll");
|
|
1807
|
+
await poll();
|
|
1808
|
+
setInterval(poll, 5e3);
|
|
1809
|
+
} else {
|
|
1810
|
+
await run();
|
|
1811
|
+
}
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
__name(registerInspectCommand, "registerInspectCommand");
|
|
1815
|
+
|
|
1653
1816
|
// src/config.ts
|
|
1654
1817
|
import { readFile as readFile3, access as access2 } from "fs/promises";
|
|
1655
1818
|
import { join as join10 } from "path";
|
|
@@ -1687,14 +1850,17 @@ async function loadKickConfig(cwd) {
|
|
|
1687
1850
|
__name(loadKickConfig, "loadKickConfig");
|
|
1688
1851
|
|
|
1689
1852
|
// src/cli.ts
|
|
1853
|
+
var __dirname2 = dirname3(fileURLToPath2(import.meta.url));
|
|
1854
|
+
var pkg = JSON.parse(readFileSync2(join11(__dirname2, "..", "package.json"), "utf-8"));
|
|
1690
1855
|
async function main() {
|
|
1691
1856
|
const program = new Command();
|
|
1692
|
-
program.name("kick").description("KickJS \u2014 A production-grade, decorator-driven Node.js framework").version(
|
|
1857
|
+
program.name("kick").description("KickJS \u2014 A production-grade, decorator-driven Node.js framework").version(pkg.version);
|
|
1693
1858
|
const config = await loadKickConfig(process.cwd());
|
|
1694
1859
|
registerInitCommand(program);
|
|
1695
1860
|
registerGenerateCommand(program);
|
|
1696
1861
|
registerRunCommands(program);
|
|
1697
1862
|
registerInfoCommand(program);
|
|
1863
|
+
registerInspectCommand(program);
|
|
1698
1864
|
registerCustomCommands(program, config);
|
|
1699
1865
|
program.showHelpAfterError();
|
|
1700
1866
|
await program.parseAsync(process.argv);
|