@lark-apaas/devtool-kits 1.2.20 → 1.2.22-alpha.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/index.cjs +168 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +172 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1769,12 +1769,154 @@ function createOpenapiHandler(openapiFilePath, enableEnhancement, serverDir) {
|
|
|
1769
1769
|
}
|
|
1770
1770
|
__name(createOpenapiHandler, "createOpenapiHandler");
|
|
1771
1771
|
|
|
1772
|
+
// src/middlewares/openapi/spec-controller.ts
|
|
1773
|
+
var import_promises3 = __toESM(require("fs/promises"), 1);
|
|
1774
|
+
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
1775
|
+
var MAX_REF_DEPTH = 5;
|
|
1776
|
+
var EMPTY_OPENAPI_SPEC = {
|
|
1777
|
+
openapi: "3.0.0",
|
|
1778
|
+
info: {
|
|
1779
|
+
title: "\u5F00\u653E API",
|
|
1780
|
+
version: "0.0.0"
|
|
1781
|
+
},
|
|
1782
|
+
paths: {},
|
|
1783
|
+
components: {
|
|
1784
|
+
schemas: {}
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
function createOpenapiSpecHandler(openapiSpecFilePath) {
|
|
1788
|
+
let cache = null;
|
|
1789
|
+
return async (_req, res, context) => {
|
|
1790
|
+
try {
|
|
1791
|
+
let fileBuffer;
|
|
1792
|
+
try {
|
|
1793
|
+
fileBuffer = await import_promises3.default.readFile(openapiSpecFilePath, "utf-8");
|
|
1794
|
+
} catch (err) {
|
|
1795
|
+
if (err?.code === "ENOENT") {
|
|
1796
|
+
return res.json(EMPTY_OPENAPI_SPEC);
|
|
1797
|
+
}
|
|
1798
|
+
throw err;
|
|
1799
|
+
}
|
|
1800
|
+
const currentHash = import_node_crypto2.default.createHash("md5").update(fileBuffer).digest("hex");
|
|
1801
|
+
if (cache && cache.fileHash === currentHash) {
|
|
1802
|
+
return res.json(cache.data);
|
|
1803
|
+
}
|
|
1804
|
+
let parsed;
|
|
1805
|
+
try {
|
|
1806
|
+
parsed = JSON.parse(fileBuffer);
|
|
1807
|
+
} catch (err) {
|
|
1808
|
+
const message = err instanceof Error ? err.message : "Invalid JSON";
|
|
1809
|
+
return res.status(500).json({
|
|
1810
|
+
error: "Failed to load OpenAPI spec",
|
|
1811
|
+
message: `${openapiSpecFilePath} invalid: ${message}`
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
if (!parsed || typeof parsed !== "object" || !parsed.paths || typeof parsed.paths !== "object") {
|
|
1815
|
+
return res.status(500).json({
|
|
1816
|
+
error: "Failed to load OpenAPI spec",
|
|
1817
|
+
message: `${openapiSpecFilePath} missing "paths"`
|
|
1818
|
+
});
|
|
1819
|
+
}
|
|
1820
|
+
const result = buildFilteredSpec(parsed, context.basePath ?? "");
|
|
1821
|
+
cache = {
|
|
1822
|
+
data: result,
|
|
1823
|
+
fileHash: currentHash
|
|
1824
|
+
};
|
|
1825
|
+
res.json(result);
|
|
1826
|
+
} catch (error) {
|
|
1827
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1828
|
+
res.status(500).json({
|
|
1829
|
+
error: "Failed to load OpenAPI spec",
|
|
1830
|
+
message
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
};
|
|
1834
|
+
}
|
|
1835
|
+
__name(createOpenapiSpecHandler, "createOpenapiSpecHandler");
|
|
1836
|
+
function buildFilteredSpec(spec, globalPrefix) {
|
|
1837
|
+
const schemas = spec.components?.schemas ?? {};
|
|
1838
|
+
const paths = spec.paths ?? {};
|
|
1839
|
+
const filteredPaths = {};
|
|
1840
|
+
const cleanPrefix = globalPrefix.replace(/\/+$/, "");
|
|
1841
|
+
for (const [pathKey, methods] of Object.entries(paths)) {
|
|
1842
|
+
const cleanPath = stripPrefix(pathKey, cleanPrefix);
|
|
1843
|
+
if (!cleanPath.startsWith("/openapi")) continue;
|
|
1844
|
+
filteredPaths[cleanPath] = {};
|
|
1845
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
1846
|
+
if ([
|
|
1847
|
+
"parameters",
|
|
1848
|
+
"summary",
|
|
1849
|
+
"description",
|
|
1850
|
+
"servers"
|
|
1851
|
+
].includes(method)) continue;
|
|
1852
|
+
filteredPaths[cleanPath][method] = resolveRefsDeep(structuredClone(operation), schemas);
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
return {
|
|
1856
|
+
openapi: spec.openapi ?? "3.0.0",
|
|
1857
|
+
paths: filteredPaths,
|
|
1858
|
+
components: {
|
|
1859
|
+
schemas: resolveAllSchemaRefs(structuredClone(schemas))
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
1862
|
+
}
|
|
1863
|
+
__name(buildFilteredSpec, "buildFilteredSpec");
|
|
1864
|
+
function stripPrefix(pathStr, prefix) {
|
|
1865
|
+
if (prefix && pathStr.startsWith(prefix)) {
|
|
1866
|
+
return pathStr.slice(prefix.length);
|
|
1867
|
+
}
|
|
1868
|
+
return pathStr;
|
|
1869
|
+
}
|
|
1870
|
+
__name(stripPrefix, "stripPrefix");
|
|
1871
|
+
function resolveRefsDeep(obj, schemas, depth = 0) {
|
|
1872
|
+
if (depth > MAX_REF_DEPTH || obj === null || obj === void 0) return obj;
|
|
1873
|
+
if (typeof obj !== "object") return obj;
|
|
1874
|
+
if (Array.isArray(obj)) {
|
|
1875
|
+
return obj.map((item) => resolveRefsDeep(item, schemas, depth));
|
|
1876
|
+
}
|
|
1877
|
+
const record = obj;
|
|
1878
|
+
if (typeof record["$ref"] === "string") {
|
|
1879
|
+
const resolved = resolveRef(record["$ref"], schemas);
|
|
1880
|
+
if (resolved !== void 0) {
|
|
1881
|
+
return resolveRefsDeep(structuredClone(resolved), schemas, depth + 1);
|
|
1882
|
+
}
|
|
1883
|
+
return record;
|
|
1884
|
+
}
|
|
1885
|
+
const result = {};
|
|
1886
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1887
|
+
result[key] = resolveRefsDeep(value, schemas, depth);
|
|
1888
|
+
}
|
|
1889
|
+
return result;
|
|
1890
|
+
}
|
|
1891
|
+
__name(resolveRefsDeep, "resolveRefsDeep");
|
|
1892
|
+
function resolveRef(ref, schemas) {
|
|
1893
|
+
const prefix = "#/components/schemas/";
|
|
1894
|
+
if (ref.startsWith(prefix)) {
|
|
1895
|
+
const name = ref.slice(prefix.length);
|
|
1896
|
+
return schemas[name];
|
|
1897
|
+
}
|
|
1898
|
+
return void 0;
|
|
1899
|
+
}
|
|
1900
|
+
__name(resolveRef, "resolveRef");
|
|
1901
|
+
function resolveAllSchemaRefs(schemas) {
|
|
1902
|
+
const result = {};
|
|
1903
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
1904
|
+
result[name] = resolveRefsDeep(schema, schemas);
|
|
1905
|
+
}
|
|
1906
|
+
return result;
|
|
1907
|
+
}
|
|
1908
|
+
__name(resolveAllSchemaRefs, "resolveAllSchemaRefs");
|
|
1909
|
+
|
|
1772
1910
|
// src/middlewares/openapi/router.ts
|
|
1773
1911
|
function createOpenapiRouter(options, context) {
|
|
1774
|
-
const { openapiFilePath, enableEnhancement, serverDir } = options;
|
|
1912
|
+
const { openapiFilePath, openapiSpecFilePath, enableEnhancement, serverDir } = options;
|
|
1775
1913
|
const router = import_express.default.Router();
|
|
1776
1914
|
const handler = createOpenapiHandler(openapiFilePath, enableEnhancement, serverDir);
|
|
1777
1915
|
router.get("/openapi.json", (req, res) => handler(req, res, context));
|
|
1916
|
+
if (openapiSpecFilePath) {
|
|
1917
|
+
const specHandler = createOpenapiSpecHandler(openapiSpecFilePath);
|
|
1918
|
+
router.get("/openapi/spec", (req, res) => specHandler(req, res, context));
|
|
1919
|
+
}
|
|
1778
1920
|
return router;
|
|
1779
1921
|
}
|
|
1780
1922
|
__name(createOpenapiRouter, "createOpenapiRouter");
|
|
@@ -1785,18 +1927,25 @@ var OPENAPI_ROUTES = [
|
|
|
1785
1927
|
method: "GET",
|
|
1786
1928
|
path: "/openapi.json",
|
|
1787
1929
|
description: "Serve enhanced OpenAPI specification with source code references"
|
|
1930
|
+
},
|
|
1931
|
+
{
|
|
1932
|
+
method: "GET",
|
|
1933
|
+
path: "/openapi/spec",
|
|
1934
|
+
description: "Serve OpenAPI specification for /openapi/*"
|
|
1788
1935
|
}
|
|
1789
1936
|
];
|
|
1790
1937
|
function createOpenapiMiddleware(options) {
|
|
1791
|
-
const { openapiFilePath, enableEnhancement = true, serverDir } = options;
|
|
1938
|
+
const { openapiFilePath, openapiSpecFilePath, enableEnhancement = true, serverDir } = options;
|
|
1939
|
+
const routes = openapiSpecFilePath ? OPENAPI_ROUTES : OPENAPI_ROUTES.filter((route) => route.path !== "/openapi/spec");
|
|
1792
1940
|
return {
|
|
1793
1941
|
name: "openapi",
|
|
1794
1942
|
mountPath: "/dev",
|
|
1795
|
-
routes
|
|
1943
|
+
routes,
|
|
1796
1944
|
enabled: /* @__PURE__ */ __name((context) => context.isDev, "enabled"),
|
|
1797
1945
|
createRouter: /* @__PURE__ */ __name((context) => {
|
|
1798
1946
|
return createOpenapiRouter({
|
|
1799
1947
|
openapiFilePath,
|
|
1948
|
+
openapiSpecFilePath,
|
|
1800
1949
|
enableEnhancement,
|
|
1801
1950
|
serverDir
|
|
1802
1951
|
}, context);
|
|
@@ -2191,8 +2340,8 @@ async function readRecentTraceCalls(filePath, page, pageSize, pathFilter, method
|
|
|
2191
2340
|
const handleRequestCompleted = /* @__PURE__ */ __name((builder, entry, message) => {
|
|
2192
2341
|
builder.hasCompleted = true;
|
|
2193
2342
|
builder.endTime = entry.time;
|
|
2194
|
-
builder.statusCode = extractNumber(message, /status_code:\s*(\d+)/);
|
|
2195
|
-
builder.durationMs = extractNumber(message, /duration_ms:\s*(\d+)/);
|
|
2343
|
+
builder.statusCode = typeof entry.status_code === "number" ? entry.status_code : extractNumber(message, /status_code:\s*(\d+)/);
|
|
2344
|
+
builder.durationMs = typeof entry.duration_ms === "number" ? entry.duration_ms : extractNumber(message, /duration_ms:\s*(\d+)/);
|
|
2196
2345
|
if (!builder.path && entry.path) {
|
|
2197
2346
|
builder.path = String(entry.path);
|
|
2198
2347
|
}
|
|
@@ -2908,7 +3057,7 @@ function createHealthCheckHandler(options = {}) {
|
|
|
2908
3057
|
__name(createHealthCheckHandler, "createHealthCheckHandler");
|
|
2909
3058
|
|
|
2910
3059
|
// src/middlewares/dev-logs/sse/log-watcher.ts
|
|
2911
|
-
var
|
|
3060
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
2912
3061
|
var path5 = __toESM(require("path"), 1);
|
|
2913
3062
|
function mapPinoLevelToServerLogLevel2(pinoLevel) {
|
|
2914
3063
|
if (typeof pinoLevel === "string") {
|
|
@@ -3127,12 +3276,12 @@ var LogWatcher = class {
|
|
|
3127
3276
|
*/
|
|
3128
3277
|
watchFile(config) {
|
|
3129
3278
|
const filePath = path5.join(this.logDir, config.fileName);
|
|
3130
|
-
if (!
|
|
3279
|
+
if (!fs9.existsSync(filePath)) {
|
|
3131
3280
|
this.log(`File not found, skipping: ${config.fileName}`);
|
|
3132
3281
|
return;
|
|
3133
3282
|
}
|
|
3134
3283
|
try {
|
|
3135
|
-
const stats =
|
|
3284
|
+
const stats = fs9.statSync(filePath);
|
|
3136
3285
|
this.filePositions.set(config.fileName, stats.size);
|
|
3137
3286
|
this.log(`Initialized position for ${config.fileName}: ${stats.size} bytes`);
|
|
3138
3287
|
} catch (error) {
|
|
@@ -3140,7 +3289,7 @@ var LogWatcher = class {
|
|
|
3140
3289
|
this.filePositions.set(config.fileName, 0);
|
|
3141
3290
|
}
|
|
3142
3291
|
try {
|
|
3143
|
-
const watcher =
|
|
3292
|
+
const watcher = fs9.watch(filePath, (eventType) => {
|
|
3144
3293
|
if (eventType === "change") {
|
|
3145
3294
|
this.handleFileChange(config);
|
|
3146
3295
|
}
|
|
@@ -3178,7 +3327,7 @@ var LogWatcher = class {
|
|
|
3178
3327
|
const filePath = path5.join(this.logDir, config.fileName);
|
|
3179
3328
|
const lastPosition = this.filePositions.get(config.fileName) || 0;
|
|
3180
3329
|
try {
|
|
3181
|
-
const stats =
|
|
3330
|
+
const stats = fs9.statSync(filePath);
|
|
3182
3331
|
const currentSize = stats.size;
|
|
3183
3332
|
if (currentSize < lastPosition) {
|
|
3184
3333
|
this.log(`File ${config.fileName} was truncated, resetting position`);
|
|
@@ -3191,11 +3340,11 @@ var LogWatcher = class {
|
|
|
3191
3340
|
}
|
|
3192
3341
|
const readSize = currentSize - lastPosition;
|
|
3193
3342
|
const buffer = Buffer.alloc(readSize);
|
|
3194
|
-
const fd =
|
|
3343
|
+
const fd = fs9.openSync(filePath, "r");
|
|
3195
3344
|
try {
|
|
3196
|
-
|
|
3345
|
+
fs9.readSync(fd, buffer, 0, readSize, lastPosition);
|
|
3197
3346
|
} finally {
|
|
3198
|
-
|
|
3347
|
+
fs9.closeSync(fd);
|
|
3199
3348
|
}
|
|
3200
3349
|
this.filePositions.set(config.fileName, currentSize);
|
|
3201
3350
|
const content = buffer.toString("utf8");
|
|
@@ -3919,9 +4068,9 @@ async function registerMiddlewares(server, middlewares, options) {
|
|
|
3919
4068
|
__name(registerMiddlewares, "registerMiddlewares");
|
|
3920
4069
|
|
|
3921
4070
|
// src/route-parser.ts
|
|
3922
|
-
var
|
|
4071
|
+
var fs12 = __toESM(require("fs"), 1);
|
|
3923
4072
|
var path7 = __toESM(require("path"), 1);
|
|
3924
|
-
var
|
|
4073
|
+
var crypto3 = __toESM(require("crypto"), 1);
|
|
3925
4074
|
var import_parser = require("@babel/parser");
|
|
3926
4075
|
var import_traverse = __toESM(require("@babel/traverse"), 1);
|
|
3927
4076
|
var t = __toESM(require("@babel/types"), 1);
|
|
@@ -3946,8 +4095,8 @@ function routeParserLog(level, message, ...args) {
|
|
|
3946
4095
|
__name(routeParserLog, "routeParserLog");
|
|
3947
4096
|
function calculateFileHash(filePath) {
|
|
3948
4097
|
try {
|
|
3949
|
-
const content =
|
|
3950
|
-
return
|
|
4098
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
4099
|
+
return crypto3.createHash("md5").update(content).digest("hex");
|
|
3951
4100
|
} catch (error) {
|
|
3952
4101
|
routeParserLog("warn", "Failed to calculate file hash:", error.message);
|
|
3953
4102
|
return null;
|
|
@@ -4031,10 +4180,10 @@ function parseRoutesFromFile(appPath, basePath, options = {}) {
|
|
|
4031
4180
|
const defaultPath = applyBasePath && basePath ? `${basePath}/` : "/";
|
|
4032
4181
|
try {
|
|
4033
4182
|
const appFilePath = path7.resolve(process.cwd(), appPath);
|
|
4034
|
-
if (!
|
|
4183
|
+
if (!fs12.existsSync(appFilePath)) {
|
|
4035
4184
|
throw new Error(`App file does not exist: ${appFilePath}`);
|
|
4036
4185
|
}
|
|
4037
|
-
const sourceCode =
|
|
4186
|
+
const sourceCode = fs12.readFileSync(appFilePath, "utf-8");
|
|
4038
4187
|
const ast = (0, import_parser.parse)(sourceCode, {
|
|
4039
4188
|
sourceType: "module",
|
|
4040
4189
|
plugins: [
|