@lark-apaas/devtool-kits 1.2.20 → 1.2.21
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 +149 -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 +153 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1769,12 +1769,135 @@ 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
|
+
function createOpenapiSpecHandler(openapiSpecFilePath) {
|
|
1777
|
+
let cache = null;
|
|
1778
|
+
return async (_req, res, context) => {
|
|
1779
|
+
try {
|
|
1780
|
+
const fileBuffer = await import_promises3.default.readFile(openapiSpecFilePath, "utf-8");
|
|
1781
|
+
const currentHash = import_node_crypto2.default.createHash("md5").update(fileBuffer).digest("hex");
|
|
1782
|
+
if (cache && cache.fileHash === currentHash) {
|
|
1783
|
+
return res.json(cache.data);
|
|
1784
|
+
}
|
|
1785
|
+
let parsed;
|
|
1786
|
+
try {
|
|
1787
|
+
parsed = JSON.parse(fileBuffer);
|
|
1788
|
+
} catch (err) {
|
|
1789
|
+
const message = err instanceof Error ? err.message : "Invalid JSON";
|
|
1790
|
+
return res.status(500).json({
|
|
1791
|
+
error: "Failed to load OpenAPI spec",
|
|
1792
|
+
message: `${openapiSpecFilePath} invalid: ${message}`
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
if (!parsed || typeof parsed !== "object" || !parsed.paths || typeof parsed.paths !== "object") {
|
|
1796
|
+
return res.status(500).json({
|
|
1797
|
+
error: "Failed to load OpenAPI spec",
|
|
1798
|
+
message: `${openapiSpecFilePath} missing "paths"`
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
const result = buildFilteredSpec(parsed, context.basePath ?? "");
|
|
1802
|
+
cache = {
|
|
1803
|
+
data: result,
|
|
1804
|
+
fileHash: currentHash
|
|
1805
|
+
};
|
|
1806
|
+
res.json(result);
|
|
1807
|
+
} catch (error) {
|
|
1808
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1809
|
+
res.status(500).json({
|
|
1810
|
+
error: "Failed to load OpenAPI spec",
|
|
1811
|
+
message
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
__name(createOpenapiSpecHandler, "createOpenapiSpecHandler");
|
|
1817
|
+
function buildFilteredSpec(spec, globalPrefix) {
|
|
1818
|
+
const schemas = spec.components?.schemas ?? {};
|
|
1819
|
+
const paths = spec.paths ?? {};
|
|
1820
|
+
const filteredPaths = {};
|
|
1821
|
+
const cleanPrefix = globalPrefix.replace(/\/+$/, "");
|
|
1822
|
+
for (const [pathKey, methods] of Object.entries(paths)) {
|
|
1823
|
+
const cleanPath = stripPrefix(pathKey, cleanPrefix);
|
|
1824
|
+
if (!cleanPath.startsWith("/openapi")) continue;
|
|
1825
|
+
filteredPaths[cleanPath] = {};
|
|
1826
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
1827
|
+
if ([
|
|
1828
|
+
"parameters",
|
|
1829
|
+
"summary",
|
|
1830
|
+
"description",
|
|
1831
|
+
"servers"
|
|
1832
|
+
].includes(method)) continue;
|
|
1833
|
+
filteredPaths[cleanPath][method] = resolveRefsDeep(structuredClone(operation), schemas);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return {
|
|
1837
|
+
openapi: spec.openapi ?? "3.0.0",
|
|
1838
|
+
paths: filteredPaths,
|
|
1839
|
+
components: {
|
|
1840
|
+
schemas: resolveAllSchemaRefs(structuredClone(schemas))
|
|
1841
|
+
}
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
__name(buildFilteredSpec, "buildFilteredSpec");
|
|
1845
|
+
function stripPrefix(pathStr, prefix) {
|
|
1846
|
+
if (prefix && pathStr.startsWith(prefix)) {
|
|
1847
|
+
return pathStr.slice(prefix.length);
|
|
1848
|
+
}
|
|
1849
|
+
return pathStr;
|
|
1850
|
+
}
|
|
1851
|
+
__name(stripPrefix, "stripPrefix");
|
|
1852
|
+
function resolveRefsDeep(obj, schemas, depth = 0) {
|
|
1853
|
+
if (depth > MAX_REF_DEPTH || obj === null || obj === void 0) return obj;
|
|
1854
|
+
if (typeof obj !== "object") return obj;
|
|
1855
|
+
if (Array.isArray(obj)) {
|
|
1856
|
+
return obj.map((item) => resolveRefsDeep(item, schemas, depth));
|
|
1857
|
+
}
|
|
1858
|
+
const record = obj;
|
|
1859
|
+
if (typeof record["$ref"] === "string") {
|
|
1860
|
+
const resolved = resolveRef(record["$ref"], schemas);
|
|
1861
|
+
if (resolved !== void 0) {
|
|
1862
|
+
return resolveRefsDeep(structuredClone(resolved), schemas, depth + 1);
|
|
1863
|
+
}
|
|
1864
|
+
return record;
|
|
1865
|
+
}
|
|
1866
|
+
const result = {};
|
|
1867
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1868
|
+
result[key] = resolveRefsDeep(value, schemas, depth);
|
|
1869
|
+
}
|
|
1870
|
+
return result;
|
|
1871
|
+
}
|
|
1872
|
+
__name(resolveRefsDeep, "resolveRefsDeep");
|
|
1873
|
+
function resolveRef(ref, schemas) {
|
|
1874
|
+
const prefix = "#/components/schemas/";
|
|
1875
|
+
if (ref.startsWith(prefix)) {
|
|
1876
|
+
const name = ref.slice(prefix.length);
|
|
1877
|
+
return schemas[name];
|
|
1878
|
+
}
|
|
1879
|
+
return void 0;
|
|
1880
|
+
}
|
|
1881
|
+
__name(resolveRef, "resolveRef");
|
|
1882
|
+
function resolveAllSchemaRefs(schemas) {
|
|
1883
|
+
const result = {};
|
|
1884
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
1885
|
+
result[name] = resolveRefsDeep(schema, schemas);
|
|
1886
|
+
}
|
|
1887
|
+
return result;
|
|
1888
|
+
}
|
|
1889
|
+
__name(resolveAllSchemaRefs, "resolveAllSchemaRefs");
|
|
1890
|
+
|
|
1772
1891
|
// src/middlewares/openapi/router.ts
|
|
1773
1892
|
function createOpenapiRouter(options, context) {
|
|
1774
|
-
const { openapiFilePath, enableEnhancement, serverDir } = options;
|
|
1893
|
+
const { openapiFilePath, openapiSpecFilePath, enableEnhancement, serverDir } = options;
|
|
1775
1894
|
const router = import_express.default.Router();
|
|
1776
1895
|
const handler = createOpenapiHandler(openapiFilePath, enableEnhancement, serverDir);
|
|
1777
1896
|
router.get("/openapi.json", (req, res) => handler(req, res, context));
|
|
1897
|
+
if (openapiSpecFilePath) {
|
|
1898
|
+
const specHandler = createOpenapiSpecHandler(openapiSpecFilePath);
|
|
1899
|
+
router.get("/openapi/spec", (req, res) => specHandler(req, res, context));
|
|
1900
|
+
}
|
|
1778
1901
|
return router;
|
|
1779
1902
|
}
|
|
1780
1903
|
__name(createOpenapiRouter, "createOpenapiRouter");
|
|
@@ -1785,18 +1908,25 @@ var OPENAPI_ROUTES = [
|
|
|
1785
1908
|
method: "GET",
|
|
1786
1909
|
path: "/openapi.json",
|
|
1787
1910
|
description: "Serve enhanced OpenAPI specification with source code references"
|
|
1911
|
+
},
|
|
1912
|
+
{
|
|
1913
|
+
method: "GET",
|
|
1914
|
+
path: "/openapi/spec",
|
|
1915
|
+
description: "Serve OpenAPI specification for /openapi/*"
|
|
1788
1916
|
}
|
|
1789
1917
|
];
|
|
1790
1918
|
function createOpenapiMiddleware(options) {
|
|
1791
|
-
const { openapiFilePath, enableEnhancement = true, serverDir } = options;
|
|
1919
|
+
const { openapiFilePath, openapiSpecFilePath, enableEnhancement = true, serverDir } = options;
|
|
1920
|
+
const routes = openapiSpecFilePath ? OPENAPI_ROUTES : OPENAPI_ROUTES.filter((route) => route.path !== "/openapi/spec");
|
|
1792
1921
|
return {
|
|
1793
1922
|
name: "openapi",
|
|
1794
1923
|
mountPath: "/dev",
|
|
1795
|
-
routes
|
|
1924
|
+
routes,
|
|
1796
1925
|
enabled: /* @__PURE__ */ __name((context) => context.isDev, "enabled"),
|
|
1797
1926
|
createRouter: /* @__PURE__ */ __name((context) => {
|
|
1798
1927
|
return createOpenapiRouter({
|
|
1799
1928
|
openapiFilePath,
|
|
1929
|
+
openapiSpecFilePath,
|
|
1800
1930
|
enableEnhancement,
|
|
1801
1931
|
serverDir
|
|
1802
1932
|
}, context);
|
|
@@ -2191,8 +2321,8 @@ async function readRecentTraceCalls(filePath, page, pageSize, pathFilter, method
|
|
|
2191
2321
|
const handleRequestCompleted = /* @__PURE__ */ __name((builder, entry, message) => {
|
|
2192
2322
|
builder.hasCompleted = true;
|
|
2193
2323
|
builder.endTime = entry.time;
|
|
2194
|
-
builder.statusCode = extractNumber(message, /status_code:\s*(\d+)/);
|
|
2195
|
-
builder.durationMs = extractNumber(message, /duration_ms:\s*(\d+)/);
|
|
2324
|
+
builder.statusCode = typeof entry.status_code === "number" ? entry.status_code : extractNumber(message, /status_code:\s*(\d+)/);
|
|
2325
|
+
builder.durationMs = typeof entry.duration_ms === "number" ? entry.duration_ms : extractNumber(message, /duration_ms:\s*(\d+)/);
|
|
2196
2326
|
if (!builder.path && entry.path) {
|
|
2197
2327
|
builder.path = String(entry.path);
|
|
2198
2328
|
}
|
|
@@ -2908,7 +3038,7 @@ function createHealthCheckHandler(options = {}) {
|
|
|
2908
3038
|
__name(createHealthCheckHandler, "createHealthCheckHandler");
|
|
2909
3039
|
|
|
2910
3040
|
// src/middlewares/dev-logs/sse/log-watcher.ts
|
|
2911
|
-
var
|
|
3041
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
2912
3042
|
var path5 = __toESM(require("path"), 1);
|
|
2913
3043
|
function mapPinoLevelToServerLogLevel2(pinoLevel) {
|
|
2914
3044
|
if (typeof pinoLevel === "string") {
|
|
@@ -3127,12 +3257,12 @@ var LogWatcher = class {
|
|
|
3127
3257
|
*/
|
|
3128
3258
|
watchFile(config) {
|
|
3129
3259
|
const filePath = path5.join(this.logDir, config.fileName);
|
|
3130
|
-
if (!
|
|
3260
|
+
if (!fs9.existsSync(filePath)) {
|
|
3131
3261
|
this.log(`File not found, skipping: ${config.fileName}`);
|
|
3132
3262
|
return;
|
|
3133
3263
|
}
|
|
3134
3264
|
try {
|
|
3135
|
-
const stats =
|
|
3265
|
+
const stats = fs9.statSync(filePath);
|
|
3136
3266
|
this.filePositions.set(config.fileName, stats.size);
|
|
3137
3267
|
this.log(`Initialized position for ${config.fileName}: ${stats.size} bytes`);
|
|
3138
3268
|
} catch (error) {
|
|
@@ -3140,7 +3270,7 @@ var LogWatcher = class {
|
|
|
3140
3270
|
this.filePositions.set(config.fileName, 0);
|
|
3141
3271
|
}
|
|
3142
3272
|
try {
|
|
3143
|
-
const watcher =
|
|
3273
|
+
const watcher = fs9.watch(filePath, (eventType) => {
|
|
3144
3274
|
if (eventType === "change") {
|
|
3145
3275
|
this.handleFileChange(config);
|
|
3146
3276
|
}
|
|
@@ -3178,7 +3308,7 @@ var LogWatcher = class {
|
|
|
3178
3308
|
const filePath = path5.join(this.logDir, config.fileName);
|
|
3179
3309
|
const lastPosition = this.filePositions.get(config.fileName) || 0;
|
|
3180
3310
|
try {
|
|
3181
|
-
const stats =
|
|
3311
|
+
const stats = fs9.statSync(filePath);
|
|
3182
3312
|
const currentSize = stats.size;
|
|
3183
3313
|
if (currentSize < lastPosition) {
|
|
3184
3314
|
this.log(`File ${config.fileName} was truncated, resetting position`);
|
|
@@ -3191,11 +3321,11 @@ var LogWatcher = class {
|
|
|
3191
3321
|
}
|
|
3192
3322
|
const readSize = currentSize - lastPosition;
|
|
3193
3323
|
const buffer = Buffer.alloc(readSize);
|
|
3194
|
-
const fd =
|
|
3324
|
+
const fd = fs9.openSync(filePath, "r");
|
|
3195
3325
|
try {
|
|
3196
|
-
|
|
3326
|
+
fs9.readSync(fd, buffer, 0, readSize, lastPosition);
|
|
3197
3327
|
} finally {
|
|
3198
|
-
|
|
3328
|
+
fs9.closeSync(fd);
|
|
3199
3329
|
}
|
|
3200
3330
|
this.filePositions.set(config.fileName, currentSize);
|
|
3201
3331
|
const content = buffer.toString("utf8");
|
|
@@ -3919,9 +4049,9 @@ async function registerMiddlewares(server, middlewares, options) {
|
|
|
3919
4049
|
__name(registerMiddlewares, "registerMiddlewares");
|
|
3920
4050
|
|
|
3921
4051
|
// src/route-parser.ts
|
|
3922
|
-
var
|
|
4052
|
+
var fs12 = __toESM(require("fs"), 1);
|
|
3923
4053
|
var path7 = __toESM(require("path"), 1);
|
|
3924
|
-
var
|
|
4054
|
+
var crypto3 = __toESM(require("crypto"), 1);
|
|
3925
4055
|
var import_parser = require("@babel/parser");
|
|
3926
4056
|
var import_traverse = __toESM(require("@babel/traverse"), 1);
|
|
3927
4057
|
var t = __toESM(require("@babel/types"), 1);
|
|
@@ -3946,8 +4076,8 @@ function routeParserLog(level, message, ...args) {
|
|
|
3946
4076
|
__name(routeParserLog, "routeParserLog");
|
|
3947
4077
|
function calculateFileHash(filePath) {
|
|
3948
4078
|
try {
|
|
3949
|
-
const content =
|
|
3950
|
-
return
|
|
4079
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
4080
|
+
return crypto3.createHash("md5").update(content).digest("hex");
|
|
3951
4081
|
} catch (error) {
|
|
3952
4082
|
routeParserLog("warn", "Failed to calculate file hash:", error.message);
|
|
3953
4083
|
return null;
|
|
@@ -4031,10 +4161,10 @@ function parseRoutesFromFile(appPath, basePath, options = {}) {
|
|
|
4031
4161
|
const defaultPath = applyBasePath && basePath ? `${basePath}/` : "/";
|
|
4032
4162
|
try {
|
|
4033
4163
|
const appFilePath = path7.resolve(process.cwd(), appPath);
|
|
4034
|
-
if (!
|
|
4164
|
+
if (!fs12.existsSync(appFilePath)) {
|
|
4035
4165
|
throw new Error(`App file does not exist: ${appFilePath}`);
|
|
4036
4166
|
}
|
|
4037
|
-
const sourceCode =
|
|
4167
|
+
const sourceCode = fs12.readFileSync(appFilePath, "utf-8");
|
|
4038
4168
|
const ast = (0, import_parser.parse)(sourceCode, {
|
|
4039
4169
|
sourceType: "module",
|
|
4040
4170
|
plugins: [
|