@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.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,154 @@ 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
+ var EMPTY_OPENAPI_SPEC = {
1396
+ openapi: "3.0.0",
1397
+ info: {
1398
+ title: "\u5F00\u653E API",
1399
+ version: "0.0.0"
1400
+ },
1401
+ paths: {},
1402
+ components: {
1403
+ schemas: {}
1404
+ }
1405
+ };
1406
+ function createOpenapiSpecHandler(openapiSpecFilePath) {
1407
+ let cache = null;
1408
+ return async (_req, res, context) => {
1409
+ try {
1410
+ let fileBuffer;
1411
+ try {
1412
+ fileBuffer = await fs4.readFile(openapiSpecFilePath, "utf-8");
1413
+ } catch (err) {
1414
+ if (err?.code === "ENOENT") {
1415
+ return res.json(EMPTY_OPENAPI_SPEC);
1416
+ }
1417
+ throw err;
1418
+ }
1419
+ const currentHash = crypto2.createHash("md5").update(fileBuffer).digest("hex");
1420
+ if (cache && cache.fileHash === currentHash) {
1421
+ return res.json(cache.data);
1422
+ }
1423
+ let parsed;
1424
+ try {
1425
+ parsed = JSON.parse(fileBuffer);
1426
+ } catch (err) {
1427
+ const message = err instanceof Error ? err.message : "Invalid JSON";
1428
+ return res.status(500).json({
1429
+ error: "Failed to load OpenAPI spec",
1430
+ message: `${openapiSpecFilePath} invalid: ${message}`
1431
+ });
1432
+ }
1433
+ if (!parsed || typeof parsed !== "object" || !parsed.paths || typeof parsed.paths !== "object") {
1434
+ return res.status(500).json({
1435
+ error: "Failed to load OpenAPI spec",
1436
+ message: `${openapiSpecFilePath} missing "paths"`
1437
+ });
1438
+ }
1439
+ const result = buildFilteredSpec(parsed, context.basePath ?? "");
1440
+ cache = {
1441
+ data: result,
1442
+ fileHash: currentHash
1443
+ };
1444
+ res.json(result);
1445
+ } catch (error) {
1446
+ const message = error instanceof Error ? error.message : "Unknown error";
1447
+ res.status(500).json({
1448
+ error: "Failed to load OpenAPI spec",
1449
+ message
1450
+ });
1451
+ }
1452
+ };
1453
+ }
1454
+ __name(createOpenapiSpecHandler, "createOpenapiSpecHandler");
1455
+ function buildFilteredSpec(spec, globalPrefix) {
1456
+ const schemas = spec.components?.schemas ?? {};
1457
+ const paths = spec.paths ?? {};
1458
+ const filteredPaths = {};
1459
+ const cleanPrefix = globalPrefix.replace(/\/+$/, "");
1460
+ for (const [pathKey, methods] of Object.entries(paths)) {
1461
+ const cleanPath = stripPrefix(pathKey, cleanPrefix);
1462
+ if (!cleanPath.startsWith("/openapi")) continue;
1463
+ filteredPaths[cleanPath] = {};
1464
+ for (const [method, operation] of Object.entries(methods)) {
1465
+ if ([
1466
+ "parameters",
1467
+ "summary",
1468
+ "description",
1469
+ "servers"
1470
+ ].includes(method)) continue;
1471
+ filteredPaths[cleanPath][method] = resolveRefsDeep(structuredClone(operation), schemas);
1472
+ }
1473
+ }
1474
+ return {
1475
+ openapi: spec.openapi ?? "3.0.0",
1476
+ paths: filteredPaths,
1477
+ components: {
1478
+ schemas: resolveAllSchemaRefs(structuredClone(schemas))
1479
+ }
1480
+ };
1481
+ }
1482
+ __name(buildFilteredSpec, "buildFilteredSpec");
1483
+ function stripPrefix(pathStr, prefix) {
1484
+ if (prefix && pathStr.startsWith(prefix)) {
1485
+ return pathStr.slice(prefix.length);
1486
+ }
1487
+ return pathStr;
1488
+ }
1489
+ __name(stripPrefix, "stripPrefix");
1490
+ function resolveRefsDeep(obj, schemas, depth = 0) {
1491
+ if (depth > MAX_REF_DEPTH || obj === null || obj === void 0) return obj;
1492
+ if (typeof obj !== "object") return obj;
1493
+ if (Array.isArray(obj)) {
1494
+ return obj.map((item) => resolveRefsDeep(item, schemas, depth));
1495
+ }
1496
+ const record = obj;
1497
+ if (typeof record["$ref"] === "string") {
1498
+ const resolved = resolveRef(record["$ref"], schemas);
1499
+ if (resolved !== void 0) {
1500
+ return resolveRefsDeep(structuredClone(resolved), schemas, depth + 1);
1501
+ }
1502
+ return record;
1503
+ }
1504
+ const result = {};
1505
+ for (const [key, value] of Object.entries(record)) {
1506
+ result[key] = resolveRefsDeep(value, schemas, depth);
1507
+ }
1508
+ return result;
1509
+ }
1510
+ __name(resolveRefsDeep, "resolveRefsDeep");
1511
+ function resolveRef(ref, schemas) {
1512
+ const prefix = "#/components/schemas/";
1513
+ if (ref.startsWith(prefix)) {
1514
+ const name = ref.slice(prefix.length);
1515
+ return schemas[name];
1516
+ }
1517
+ return void 0;
1518
+ }
1519
+ __name(resolveRef, "resolveRef");
1520
+ function resolveAllSchemaRefs(schemas) {
1521
+ const result = {};
1522
+ for (const [name, schema] of Object.entries(schemas)) {
1523
+ result[name] = resolveRefsDeep(schema, schemas);
1524
+ }
1525
+ return result;
1526
+ }
1527
+ __name(resolveAllSchemaRefs, "resolveAllSchemaRefs");
1528
+
1391
1529
  // src/middlewares/openapi/router.ts
1392
1530
  function createOpenapiRouter(options, context) {
1393
- const { openapiFilePath, enableEnhancement, serverDir } = options;
1531
+ const { openapiFilePath, openapiSpecFilePath, enableEnhancement, serverDir } = options;
1394
1532
  const router = express.Router();
1395
1533
  const handler = createOpenapiHandler(openapiFilePath, enableEnhancement, serverDir);
1396
1534
  router.get("/openapi.json", (req, res) => handler(req, res, context));
1535
+ if (openapiSpecFilePath) {
1536
+ const specHandler = createOpenapiSpecHandler(openapiSpecFilePath);
1537
+ router.get("/openapi/spec", (req, res) => specHandler(req, res, context));
1538
+ }
1397
1539
  return router;
1398
1540
  }
1399
1541
  __name(createOpenapiRouter, "createOpenapiRouter");
@@ -1404,18 +1546,25 @@ var OPENAPI_ROUTES = [
1404
1546
  method: "GET",
1405
1547
  path: "/openapi.json",
1406
1548
  description: "Serve enhanced OpenAPI specification with source code references"
1549
+ },
1550
+ {
1551
+ method: "GET",
1552
+ path: "/openapi/spec",
1553
+ description: "Serve OpenAPI specification for /openapi/*"
1407
1554
  }
1408
1555
  ];
1409
1556
  function createOpenapiMiddleware(options) {
1410
- const { openapiFilePath, enableEnhancement = true, serverDir } = options;
1557
+ const { openapiFilePath, openapiSpecFilePath, enableEnhancement = true, serverDir } = options;
1558
+ const routes = openapiSpecFilePath ? OPENAPI_ROUTES : OPENAPI_ROUTES.filter((route) => route.path !== "/openapi/spec");
1411
1559
  return {
1412
1560
  name: "openapi",
1413
1561
  mountPath: "/dev",
1414
- routes: OPENAPI_ROUTES,
1562
+ routes,
1415
1563
  enabled: /* @__PURE__ */ __name((context) => context.isDev, "enabled"),
1416
1564
  createRouter: /* @__PURE__ */ __name((context) => {
1417
1565
  return createOpenapiRouter({
1418
1566
  openapiFilePath,
1567
+ openapiSpecFilePath,
1419
1568
  enableEnhancement,
1420
1569
  serverDir
1421
1570
  }, context);
@@ -1428,7 +1577,7 @@ __name(createOpenapiMiddleware, "createOpenapiMiddleware");
1428
1577
  import express2 from "express";
1429
1578
 
1430
1579
  // src/middlewares/dev-logs/utils.ts
1431
- import { promises as fs4 } from "fs";
1580
+ import { promises as fs5 } from "fs";
1432
1581
  import { isAbsolute, join as join2, relative } from "path";
1433
1582
 
1434
1583
  // src/middlewares/dev-logs/helper/path-matcher.ts
@@ -1480,7 +1629,7 @@ function getRelativePath(filePath) {
1480
1629
  __name(getRelativePath, "getRelativePath");
1481
1630
  async function fileExists(filePath) {
1482
1631
  try {
1483
- await fs4.access(filePath);
1632
+ await fs5.access(filePath);
1484
1633
  return true;
1485
1634
  } catch {
1486
1635
  return false;
@@ -1563,9 +1712,9 @@ __name(serializeError, "serializeError");
1563
1712
  import { join as join4 } from "path";
1564
1713
 
1565
1714
  // src/middlewares/dev-logs/services/file-reader.ts
1566
- import { promises as fs5 } from "fs";
1715
+ import { promises as fs6 } from "fs";
1567
1716
  async function readFileReverse(filePath, chunkSize, processLine) {
1568
- const handle = await fs5.open(filePath, "r");
1717
+ const handle = await fs6.open(filePath, "r");
1569
1718
  try {
1570
1719
  const stats = await handle.stat();
1571
1720
  let position = stats.size;
@@ -1810,8 +1959,8 @@ async function readRecentTraceCalls(filePath, page, pageSize, pathFilter, method
1810
1959
  const handleRequestCompleted = /* @__PURE__ */ __name((builder, entry, message) => {
1811
1960
  builder.hasCompleted = true;
1812
1961
  builder.endTime = entry.time;
1813
- builder.statusCode = extractNumber(message, /status_code:\s*(\d+)/);
1814
- builder.durationMs = extractNumber(message, /duration_ms:\s*(\d+)/);
1962
+ builder.statusCode = typeof entry.status_code === "number" ? entry.status_code : extractNumber(message, /status_code:\s*(\d+)/);
1963
+ builder.durationMs = typeof entry.duration_ms === "number" ? entry.duration_ms : extractNumber(message, /duration_ms:\s*(\d+)/);
1815
1964
  if (!builder.path && entry.path) {
1816
1965
  builder.path = String(entry.path);
1817
1966
  }
@@ -2527,7 +2676,7 @@ function createHealthCheckHandler(options = {}) {
2527
2676
  __name(createHealthCheckHandler, "createHealthCheckHandler");
2528
2677
 
2529
2678
  // src/middlewares/dev-logs/sse/log-watcher.ts
2530
- import * as fs6 from "fs";
2679
+ import * as fs7 from "fs";
2531
2680
  import * as path3 from "path";
2532
2681
  function mapPinoLevelToServerLogLevel2(pinoLevel) {
2533
2682
  if (typeof pinoLevel === "string") {
@@ -2746,12 +2895,12 @@ var LogWatcher = class {
2746
2895
  */
2747
2896
  watchFile(config) {
2748
2897
  const filePath = path3.join(this.logDir, config.fileName);
2749
- if (!fs6.existsSync(filePath)) {
2898
+ if (!fs7.existsSync(filePath)) {
2750
2899
  this.log(`File not found, skipping: ${config.fileName}`);
2751
2900
  return;
2752
2901
  }
2753
2902
  try {
2754
- const stats = fs6.statSync(filePath);
2903
+ const stats = fs7.statSync(filePath);
2755
2904
  this.filePositions.set(config.fileName, stats.size);
2756
2905
  this.log(`Initialized position for ${config.fileName}: ${stats.size} bytes`);
2757
2906
  } catch (error) {
@@ -2759,7 +2908,7 @@ var LogWatcher = class {
2759
2908
  this.filePositions.set(config.fileName, 0);
2760
2909
  }
2761
2910
  try {
2762
- const watcher = fs6.watch(filePath, (eventType) => {
2911
+ const watcher = fs7.watch(filePath, (eventType) => {
2763
2912
  if (eventType === "change") {
2764
2913
  this.handleFileChange(config);
2765
2914
  }
@@ -2797,7 +2946,7 @@ var LogWatcher = class {
2797
2946
  const filePath = path3.join(this.logDir, config.fileName);
2798
2947
  const lastPosition = this.filePositions.get(config.fileName) || 0;
2799
2948
  try {
2800
- const stats = fs6.statSync(filePath);
2949
+ const stats = fs7.statSync(filePath);
2801
2950
  const currentSize = stats.size;
2802
2951
  if (currentSize < lastPosition) {
2803
2952
  this.log(`File ${config.fileName} was truncated, resetting position`);
@@ -2810,11 +2959,11 @@ var LogWatcher = class {
2810
2959
  }
2811
2960
  const readSize = currentSize - lastPosition;
2812
2961
  const buffer = Buffer.alloc(readSize);
2813
- const fd = fs6.openSync(filePath, "r");
2962
+ const fd = fs7.openSync(filePath, "r");
2814
2963
  try {
2815
- fs6.readSync(fd, buffer, 0, readSize, lastPosition);
2964
+ fs7.readSync(fd, buffer, 0, readSize, lastPosition);
2816
2965
  } finally {
2817
- fs6.closeSync(fd);
2966
+ fs7.closeSync(fd);
2818
2967
  }
2819
2968
  this.filePositions.set(config.fileName, currentSize);
2820
2969
  const content = buffer.toString("utf8");
@@ -3220,11 +3369,11 @@ import express3 from "express";
3220
3369
 
3221
3370
  // src/middlewares/collect-logs/controller.ts
3222
3371
  import { join as join7 } from "path";
3223
- import fs8 from "fs";
3372
+ import fs9 from "fs";
3224
3373
 
3225
3374
  // src/middlewares/collect-logs/utils.ts
3226
3375
  import { isAbsolute as isAbsolute2, join as join6 } from "path";
3227
- import fs7 from "fs";
3376
+ import fs8 from "fs";
3228
3377
  function resolveLogDir2(provided) {
3229
3378
  if (!provided) {
3230
3379
  return join6(process.cwd(), "logs");
@@ -3233,8 +3382,8 @@ function resolveLogDir2(provided) {
3233
3382
  }
3234
3383
  __name(resolveLogDir2, "resolveLogDir");
3235
3384
  function ensureDir(dir) {
3236
- if (!fs7.existsSync(dir)) {
3237
- fs7.mkdirSync(dir, {
3385
+ if (!fs8.existsSync(dir)) {
3386
+ fs8.mkdirSync(dir, {
3238
3387
  recursive: true
3239
3388
  });
3240
3389
  }
@@ -3266,7 +3415,7 @@ function collectLogsHandler(logDir, fileName) {
3266
3415
  ...logContent,
3267
3416
  server_time: (/* @__PURE__ */ new Date()).toISOString()
3268
3417
  }) + "\n";
3269
- await fs8.promises.appendFile(filePath, logLine);
3418
+ await fs9.promises.appendFile(filePath, logLine);
3270
3419
  res.json({
3271
3420
  success: true
3272
3421
  });
@@ -3294,7 +3443,7 @@ function collectLogsBatchHandler(logDir, fileName) {
3294
3443
  server_time: (/* @__PURE__ */ new Date()).toISOString()
3295
3444
  }) + "\n");
3296
3445
  }
3297
- await fs8.promises.appendFile(filePath, logLines.join(""));
3446
+ await fs9.promises.appendFile(filePath, logLines.join(""));
3298
3447
  res.json({
3299
3448
  success: true
3300
3449
  });