@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.d.cts
CHANGED
|
@@ -166,6 +166,8 @@ type Middleware = RouteMiddleware | GlobalMiddleware;
|
|
|
166
166
|
interface OpenapiMiddlewareOptions {
|
|
167
167
|
/** Path to the openapi.json file */
|
|
168
168
|
openapiFilePath: string;
|
|
169
|
+
/** Path to the OpenAPI spec source file (when set, serves /openapi/spec with /openapi/* filtered and $refs resolved) */
|
|
170
|
+
openapiSpecFilePath?: string;
|
|
169
171
|
/** Enable source code enhancement */
|
|
170
172
|
enableEnhancement?: boolean;
|
|
171
173
|
/** Server directory for source code scanning (defaults to context.rootDir) */
|
package/dist/index.d.ts
CHANGED
|
@@ -166,6 +166,8 @@ type Middleware = RouteMiddleware | GlobalMiddleware;
|
|
|
166
166
|
interface OpenapiMiddlewareOptions {
|
|
167
167
|
/** Path to the openapi.json file */
|
|
168
168
|
openapiFilePath: string;
|
|
169
|
+
/** Path to the OpenAPI spec source file (when set, serves /openapi/spec with /openapi/* filtered and $refs resolved) */
|
|
170
|
+
openapiSpecFilePath?: string;
|
|
169
171
|
/** Enable source code enhancement */
|
|
170
172
|
enableEnhancement?: boolean;
|
|
171
173
|
/** Server directory for source code scanning (defaults to context.rootDir) */
|
package/dist/index.js
CHANGED
|
@@ -1388,12 +1388,135 @@ function createOpenapiHandler(openapiFilePath, enableEnhancement, serverDir) {
|
|
|
1388
1388
|
}
|
|
1389
1389
|
__name(createOpenapiHandler, "createOpenapiHandler");
|
|
1390
1390
|
|
|
1391
|
+
// src/middlewares/openapi/spec-controller.ts
|
|
1392
|
+
import fs4 from "fs/promises";
|
|
1393
|
+
import crypto2 from "crypto";
|
|
1394
|
+
var MAX_REF_DEPTH = 5;
|
|
1395
|
+
function createOpenapiSpecHandler(openapiSpecFilePath) {
|
|
1396
|
+
let cache = null;
|
|
1397
|
+
return async (_req, res, context) => {
|
|
1398
|
+
try {
|
|
1399
|
+
const fileBuffer = await fs4.readFile(openapiSpecFilePath, "utf-8");
|
|
1400
|
+
const currentHash = crypto2.createHash("md5").update(fileBuffer).digest("hex");
|
|
1401
|
+
if (cache && cache.fileHash === currentHash) {
|
|
1402
|
+
return res.json(cache.data);
|
|
1403
|
+
}
|
|
1404
|
+
let parsed;
|
|
1405
|
+
try {
|
|
1406
|
+
parsed = JSON.parse(fileBuffer);
|
|
1407
|
+
} catch (err) {
|
|
1408
|
+
const message = err instanceof Error ? err.message : "Invalid JSON";
|
|
1409
|
+
return res.status(500).json({
|
|
1410
|
+
error: "Failed to load OpenAPI spec",
|
|
1411
|
+
message: `${openapiSpecFilePath} invalid: ${message}`
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
if (!parsed || typeof parsed !== "object" || !parsed.paths || typeof parsed.paths !== "object") {
|
|
1415
|
+
return res.status(500).json({
|
|
1416
|
+
error: "Failed to load OpenAPI spec",
|
|
1417
|
+
message: `${openapiSpecFilePath} missing "paths"`
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
const result = buildFilteredSpec(parsed, context.basePath ?? "");
|
|
1421
|
+
cache = {
|
|
1422
|
+
data: result,
|
|
1423
|
+
fileHash: currentHash
|
|
1424
|
+
};
|
|
1425
|
+
res.json(result);
|
|
1426
|
+
} catch (error) {
|
|
1427
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1428
|
+
res.status(500).json({
|
|
1429
|
+
error: "Failed to load OpenAPI spec",
|
|
1430
|
+
message
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
__name(createOpenapiSpecHandler, "createOpenapiSpecHandler");
|
|
1436
|
+
function buildFilteredSpec(spec, globalPrefix) {
|
|
1437
|
+
const schemas = spec.components?.schemas ?? {};
|
|
1438
|
+
const paths = spec.paths ?? {};
|
|
1439
|
+
const filteredPaths = {};
|
|
1440
|
+
const cleanPrefix = globalPrefix.replace(/\/+$/, "");
|
|
1441
|
+
for (const [pathKey, methods] of Object.entries(paths)) {
|
|
1442
|
+
const cleanPath = stripPrefix(pathKey, cleanPrefix);
|
|
1443
|
+
if (!cleanPath.startsWith("/openapi")) continue;
|
|
1444
|
+
filteredPaths[cleanPath] = {};
|
|
1445
|
+
for (const [method, operation] of Object.entries(methods)) {
|
|
1446
|
+
if ([
|
|
1447
|
+
"parameters",
|
|
1448
|
+
"summary",
|
|
1449
|
+
"description",
|
|
1450
|
+
"servers"
|
|
1451
|
+
].includes(method)) continue;
|
|
1452
|
+
filteredPaths[cleanPath][method] = resolveRefsDeep(structuredClone(operation), schemas);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
return {
|
|
1456
|
+
openapi: spec.openapi ?? "3.0.0",
|
|
1457
|
+
paths: filteredPaths,
|
|
1458
|
+
components: {
|
|
1459
|
+
schemas: resolveAllSchemaRefs(structuredClone(schemas))
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
__name(buildFilteredSpec, "buildFilteredSpec");
|
|
1464
|
+
function stripPrefix(pathStr, prefix) {
|
|
1465
|
+
if (prefix && pathStr.startsWith(prefix)) {
|
|
1466
|
+
return pathStr.slice(prefix.length);
|
|
1467
|
+
}
|
|
1468
|
+
return pathStr;
|
|
1469
|
+
}
|
|
1470
|
+
__name(stripPrefix, "stripPrefix");
|
|
1471
|
+
function resolveRefsDeep(obj, schemas, depth = 0) {
|
|
1472
|
+
if (depth > MAX_REF_DEPTH || obj === null || obj === void 0) return obj;
|
|
1473
|
+
if (typeof obj !== "object") return obj;
|
|
1474
|
+
if (Array.isArray(obj)) {
|
|
1475
|
+
return obj.map((item) => resolveRefsDeep(item, schemas, depth));
|
|
1476
|
+
}
|
|
1477
|
+
const record = obj;
|
|
1478
|
+
if (typeof record["$ref"] === "string") {
|
|
1479
|
+
const resolved = resolveRef(record["$ref"], schemas);
|
|
1480
|
+
if (resolved !== void 0) {
|
|
1481
|
+
return resolveRefsDeep(structuredClone(resolved), schemas, depth + 1);
|
|
1482
|
+
}
|
|
1483
|
+
return record;
|
|
1484
|
+
}
|
|
1485
|
+
const result = {};
|
|
1486
|
+
for (const [key, value] of Object.entries(record)) {
|
|
1487
|
+
result[key] = resolveRefsDeep(value, schemas, depth);
|
|
1488
|
+
}
|
|
1489
|
+
return result;
|
|
1490
|
+
}
|
|
1491
|
+
__name(resolveRefsDeep, "resolveRefsDeep");
|
|
1492
|
+
function resolveRef(ref, schemas) {
|
|
1493
|
+
const prefix = "#/components/schemas/";
|
|
1494
|
+
if (ref.startsWith(prefix)) {
|
|
1495
|
+
const name = ref.slice(prefix.length);
|
|
1496
|
+
return schemas[name];
|
|
1497
|
+
}
|
|
1498
|
+
return void 0;
|
|
1499
|
+
}
|
|
1500
|
+
__name(resolveRef, "resolveRef");
|
|
1501
|
+
function resolveAllSchemaRefs(schemas) {
|
|
1502
|
+
const result = {};
|
|
1503
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
1504
|
+
result[name] = resolveRefsDeep(schema, schemas);
|
|
1505
|
+
}
|
|
1506
|
+
return result;
|
|
1507
|
+
}
|
|
1508
|
+
__name(resolveAllSchemaRefs, "resolveAllSchemaRefs");
|
|
1509
|
+
|
|
1391
1510
|
// src/middlewares/openapi/router.ts
|
|
1392
1511
|
function createOpenapiRouter(options, context) {
|
|
1393
|
-
const { openapiFilePath, enableEnhancement, serverDir } = options;
|
|
1512
|
+
const { openapiFilePath, openapiSpecFilePath, enableEnhancement, serverDir } = options;
|
|
1394
1513
|
const router = express.Router();
|
|
1395
1514
|
const handler = createOpenapiHandler(openapiFilePath, enableEnhancement, serverDir);
|
|
1396
1515
|
router.get("/openapi.json", (req, res) => handler(req, res, context));
|
|
1516
|
+
if (openapiSpecFilePath) {
|
|
1517
|
+
const specHandler = createOpenapiSpecHandler(openapiSpecFilePath);
|
|
1518
|
+
router.get("/openapi/spec", (req, res) => specHandler(req, res, context));
|
|
1519
|
+
}
|
|
1397
1520
|
return router;
|
|
1398
1521
|
}
|
|
1399
1522
|
__name(createOpenapiRouter, "createOpenapiRouter");
|
|
@@ -1404,18 +1527,25 @@ var OPENAPI_ROUTES = [
|
|
|
1404
1527
|
method: "GET",
|
|
1405
1528
|
path: "/openapi.json",
|
|
1406
1529
|
description: "Serve enhanced OpenAPI specification with source code references"
|
|
1530
|
+
},
|
|
1531
|
+
{
|
|
1532
|
+
method: "GET",
|
|
1533
|
+
path: "/openapi/spec",
|
|
1534
|
+
description: "Serve OpenAPI specification for /openapi/*"
|
|
1407
1535
|
}
|
|
1408
1536
|
];
|
|
1409
1537
|
function createOpenapiMiddleware(options) {
|
|
1410
|
-
const { openapiFilePath, enableEnhancement = true, serverDir } = options;
|
|
1538
|
+
const { openapiFilePath, openapiSpecFilePath, enableEnhancement = true, serverDir } = options;
|
|
1539
|
+
const routes = openapiSpecFilePath ? OPENAPI_ROUTES : OPENAPI_ROUTES.filter((route) => route.path !== "/openapi/spec");
|
|
1411
1540
|
return {
|
|
1412
1541
|
name: "openapi",
|
|
1413
1542
|
mountPath: "/dev",
|
|
1414
|
-
routes
|
|
1543
|
+
routes,
|
|
1415
1544
|
enabled: /* @__PURE__ */ __name((context) => context.isDev, "enabled"),
|
|
1416
1545
|
createRouter: /* @__PURE__ */ __name((context) => {
|
|
1417
1546
|
return createOpenapiRouter({
|
|
1418
1547
|
openapiFilePath,
|
|
1548
|
+
openapiSpecFilePath,
|
|
1419
1549
|
enableEnhancement,
|
|
1420
1550
|
serverDir
|
|
1421
1551
|
}, context);
|
|
@@ -1428,7 +1558,7 @@ __name(createOpenapiMiddleware, "createOpenapiMiddleware");
|
|
|
1428
1558
|
import express2 from "express";
|
|
1429
1559
|
|
|
1430
1560
|
// src/middlewares/dev-logs/utils.ts
|
|
1431
|
-
import { promises as
|
|
1561
|
+
import { promises as fs5 } from "fs";
|
|
1432
1562
|
import { isAbsolute, join as join2, relative } from "path";
|
|
1433
1563
|
|
|
1434
1564
|
// src/middlewares/dev-logs/helper/path-matcher.ts
|
|
@@ -1480,7 +1610,7 @@ function getRelativePath(filePath) {
|
|
|
1480
1610
|
__name(getRelativePath, "getRelativePath");
|
|
1481
1611
|
async function fileExists(filePath) {
|
|
1482
1612
|
try {
|
|
1483
|
-
await
|
|
1613
|
+
await fs5.access(filePath);
|
|
1484
1614
|
return true;
|
|
1485
1615
|
} catch {
|
|
1486
1616
|
return false;
|
|
@@ -1563,9 +1693,9 @@ __name(serializeError, "serializeError");
|
|
|
1563
1693
|
import { join as join4 } from "path";
|
|
1564
1694
|
|
|
1565
1695
|
// src/middlewares/dev-logs/services/file-reader.ts
|
|
1566
|
-
import { promises as
|
|
1696
|
+
import { promises as fs6 } from "fs";
|
|
1567
1697
|
async function readFileReverse(filePath, chunkSize, processLine) {
|
|
1568
|
-
const handle = await
|
|
1698
|
+
const handle = await fs6.open(filePath, "r");
|
|
1569
1699
|
try {
|
|
1570
1700
|
const stats = await handle.stat();
|
|
1571
1701
|
let position = stats.size;
|
|
@@ -1810,8 +1940,8 @@ async function readRecentTraceCalls(filePath, page, pageSize, pathFilter, method
|
|
|
1810
1940
|
const handleRequestCompleted = /* @__PURE__ */ __name((builder, entry, message) => {
|
|
1811
1941
|
builder.hasCompleted = true;
|
|
1812
1942
|
builder.endTime = entry.time;
|
|
1813
|
-
builder.statusCode = extractNumber(message, /status_code:\s*(\d+)/);
|
|
1814
|
-
builder.durationMs = extractNumber(message, /duration_ms:\s*(\d+)/);
|
|
1943
|
+
builder.statusCode = typeof entry.status_code === "number" ? entry.status_code : extractNumber(message, /status_code:\s*(\d+)/);
|
|
1944
|
+
builder.durationMs = typeof entry.duration_ms === "number" ? entry.duration_ms : extractNumber(message, /duration_ms:\s*(\d+)/);
|
|
1815
1945
|
if (!builder.path && entry.path) {
|
|
1816
1946
|
builder.path = String(entry.path);
|
|
1817
1947
|
}
|
|
@@ -2527,7 +2657,7 @@ function createHealthCheckHandler(options = {}) {
|
|
|
2527
2657
|
__name(createHealthCheckHandler, "createHealthCheckHandler");
|
|
2528
2658
|
|
|
2529
2659
|
// src/middlewares/dev-logs/sse/log-watcher.ts
|
|
2530
|
-
import * as
|
|
2660
|
+
import * as fs7 from "fs";
|
|
2531
2661
|
import * as path3 from "path";
|
|
2532
2662
|
function mapPinoLevelToServerLogLevel2(pinoLevel) {
|
|
2533
2663
|
if (typeof pinoLevel === "string") {
|
|
@@ -2746,12 +2876,12 @@ var LogWatcher = class {
|
|
|
2746
2876
|
*/
|
|
2747
2877
|
watchFile(config) {
|
|
2748
2878
|
const filePath = path3.join(this.logDir, config.fileName);
|
|
2749
|
-
if (!
|
|
2879
|
+
if (!fs7.existsSync(filePath)) {
|
|
2750
2880
|
this.log(`File not found, skipping: ${config.fileName}`);
|
|
2751
2881
|
return;
|
|
2752
2882
|
}
|
|
2753
2883
|
try {
|
|
2754
|
-
const stats =
|
|
2884
|
+
const stats = fs7.statSync(filePath);
|
|
2755
2885
|
this.filePositions.set(config.fileName, stats.size);
|
|
2756
2886
|
this.log(`Initialized position for ${config.fileName}: ${stats.size} bytes`);
|
|
2757
2887
|
} catch (error) {
|
|
@@ -2759,7 +2889,7 @@ var LogWatcher = class {
|
|
|
2759
2889
|
this.filePositions.set(config.fileName, 0);
|
|
2760
2890
|
}
|
|
2761
2891
|
try {
|
|
2762
|
-
const watcher =
|
|
2892
|
+
const watcher = fs7.watch(filePath, (eventType) => {
|
|
2763
2893
|
if (eventType === "change") {
|
|
2764
2894
|
this.handleFileChange(config);
|
|
2765
2895
|
}
|
|
@@ -2797,7 +2927,7 @@ var LogWatcher = class {
|
|
|
2797
2927
|
const filePath = path3.join(this.logDir, config.fileName);
|
|
2798
2928
|
const lastPosition = this.filePositions.get(config.fileName) || 0;
|
|
2799
2929
|
try {
|
|
2800
|
-
const stats =
|
|
2930
|
+
const stats = fs7.statSync(filePath);
|
|
2801
2931
|
const currentSize = stats.size;
|
|
2802
2932
|
if (currentSize < lastPosition) {
|
|
2803
2933
|
this.log(`File ${config.fileName} was truncated, resetting position`);
|
|
@@ -2810,11 +2940,11 @@ var LogWatcher = class {
|
|
|
2810
2940
|
}
|
|
2811
2941
|
const readSize = currentSize - lastPosition;
|
|
2812
2942
|
const buffer = Buffer.alloc(readSize);
|
|
2813
|
-
const fd =
|
|
2943
|
+
const fd = fs7.openSync(filePath, "r");
|
|
2814
2944
|
try {
|
|
2815
|
-
|
|
2945
|
+
fs7.readSync(fd, buffer, 0, readSize, lastPosition);
|
|
2816
2946
|
} finally {
|
|
2817
|
-
|
|
2947
|
+
fs7.closeSync(fd);
|
|
2818
2948
|
}
|
|
2819
2949
|
this.filePositions.set(config.fileName, currentSize);
|
|
2820
2950
|
const content = buffer.toString("utf8");
|
|
@@ -3220,11 +3350,11 @@ import express3 from "express";
|
|
|
3220
3350
|
|
|
3221
3351
|
// src/middlewares/collect-logs/controller.ts
|
|
3222
3352
|
import { join as join7 } from "path";
|
|
3223
|
-
import
|
|
3353
|
+
import fs9 from "fs";
|
|
3224
3354
|
|
|
3225
3355
|
// src/middlewares/collect-logs/utils.ts
|
|
3226
3356
|
import { isAbsolute as isAbsolute2, join as join6 } from "path";
|
|
3227
|
-
import
|
|
3357
|
+
import fs8 from "fs";
|
|
3228
3358
|
function resolveLogDir2(provided) {
|
|
3229
3359
|
if (!provided) {
|
|
3230
3360
|
return join6(process.cwd(), "logs");
|
|
@@ -3233,8 +3363,8 @@ function resolveLogDir2(provided) {
|
|
|
3233
3363
|
}
|
|
3234
3364
|
__name(resolveLogDir2, "resolveLogDir");
|
|
3235
3365
|
function ensureDir(dir) {
|
|
3236
|
-
if (!
|
|
3237
|
-
|
|
3366
|
+
if (!fs8.existsSync(dir)) {
|
|
3367
|
+
fs8.mkdirSync(dir, {
|
|
3238
3368
|
recursive: true
|
|
3239
3369
|
});
|
|
3240
3370
|
}
|
|
@@ -3266,7 +3396,7 @@ function collectLogsHandler(logDir, fileName) {
|
|
|
3266
3396
|
...logContent,
|
|
3267
3397
|
server_time: (/* @__PURE__ */ new Date()).toISOString()
|
|
3268
3398
|
}) + "\n";
|
|
3269
|
-
await
|
|
3399
|
+
await fs9.promises.appendFile(filePath, logLine);
|
|
3270
3400
|
res.json({
|
|
3271
3401
|
success: true
|
|
3272
3402
|
});
|
|
@@ -3294,7 +3424,7 @@ function collectLogsBatchHandler(logDir, fileName) {
|
|
|
3294
3424
|
server_time: (/* @__PURE__ */ new Date()).toISOString()
|
|
3295
3425
|
}) + "\n");
|
|
3296
3426
|
}
|
|
3297
|
-
await
|
|
3427
|
+
await fs9.promises.appendFile(filePath, logLines.join(""));
|
|
3298
3428
|
res.json({
|
|
3299
3429
|
success: true
|
|
3300
3430
|
});
|