@nasl/cli 0.1.16 → 0.1.18

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.
Files changed (52) hide show
  1. package/README.md +113 -11
  2. package/dist/bin/nasl.mjs +340 -43
  3. package/dist/bin/nasl.mjs.map +1 -1
  4. package/dist/bin/naslc.mjs +316 -20
  5. package/dist/bin/naslc.mjs.map +1 -1
  6. package/dist/index.mjs +336 -39
  7. package/dist/index.mjs.map +1 -1
  8. package/out/apis/cachable.d.ts +16 -0
  9. package/out/apis/cachable.d.ts.map +1 -0
  10. package/out/apis/cachable.js +142 -0
  11. package/out/apis/cachable.js.map +1 -0
  12. package/out/apis/compileApi.d.ts.map +1 -1
  13. package/out/apis/compileApi.js +2 -4
  14. package/out/apis/compileApi.js.map +1 -1
  15. package/out/apis/createAppApi.js +1 -1
  16. package/out/apis/createAppApi.js.map +1 -1
  17. package/out/apis/createAxios.d.ts +7 -1
  18. package/out/apis/createAxios.d.ts.map +1 -1
  19. package/out/apis/createAxios.js +33 -5
  20. package/out/apis/createAxios.js.map +1 -1
  21. package/out/apis/openapi.d.ts +37 -0
  22. package/out/apis/openapi.d.ts.map +1 -0
  23. package/out/apis/openapi.js +110 -0
  24. package/out/apis/openapi.js.map +1 -0
  25. package/out/apis/transformApi.d.ts +1 -1
  26. package/out/apis/transformApi.d.ts.map +1 -1
  27. package/out/apis/transformApi.js +4 -6
  28. package/out/apis/transformApi.js.map +1 -1
  29. package/out/bin/nasl.js +3 -3
  30. package/out/bin/nasl.js.map +1 -1
  31. package/out/commands/check.d.ts.map +1 -1
  32. package/out/commands/check.js +1 -4
  33. package/out/commands/check.js.map +1 -1
  34. package/out/commands/compile.d.ts.map +1 -1
  35. package/out/commands/compile.js +1 -4
  36. package/out/commands/compile.js.map +1 -1
  37. package/out/commands/createAppInIde.d.ts.map +1 -1
  38. package/out/commands/createAppInIde.js +4 -0
  39. package/out/commands/createAppInIde.js.map +1 -1
  40. package/out/commands/transform.d.ts.map +1 -1
  41. package/out/commands/transform.js +6 -4
  42. package/out/commands/transform.js.map +1 -1
  43. package/out/types/api.d.ts +8 -0
  44. package/out/types/api.d.ts.map +1 -1
  45. package/out/types/config.d.ts +6 -0
  46. package/out/types/config.d.ts.map +1 -1
  47. package/out/types/config.js +2 -2
  48. package/out/types/config.js.map +1 -1
  49. package/out/utils/config.d.ts.map +1 -1
  50. package/out/utils/config.js +31 -2
  51. package/out/utils/config.js.map +1 -1
  52. package/package.json +3 -1
@@ -3,8 +3,8 @@
3
3
  import require$$0$1, { EventEmitter } from 'events';
4
4
  import require$$1 from 'child_process';
5
5
  import * as sysPath from 'path';
6
- import sysPath__default from 'path';
7
- import require$$0$2 from 'fs';
6
+ import sysPath__default, { join } from 'path';
7
+ import require$$0$2, { promises } from 'fs';
8
8
  import require$$4 from 'process';
9
9
  import require$$0$5 from 'os';
10
10
  import require$$1$1 from 'tty';
@@ -15,7 +15,7 @@ import require$$5 from 'assert';
15
15
  import require$$3 from 'http';
16
16
  import require$$4$1 from 'https';
17
17
  import require$$0$6 from 'url';
18
- import require$$8 from 'crypto';
18
+ import crypto$1, { createHash } from 'crypto';
19
19
  import http2 from 'http2';
20
20
  import zlib from 'zlib';
21
21
 
@@ -8304,10 +8304,39 @@ function loadConfig(configDir) {
8304
8304
  const content = libExports.readFileSync(configPath, 'utf-8');
8305
8305
  const config = JSON.parse(content);
8306
8306
  // 验证必需字段
8307
- if (!config.serverBaseURL || !config.ideVersion || !config.srcDir || !config.outDir) {
8308
- defaultLogger.error('配置文件格式不正确,缺少必需字段');
8307
+ if (!config.srcDir || !config.outDir) {
8308
+ defaultLogger.error('配置文件格式不正确,缺少必需的 srcDir 或 outDir 字段');
8309
8309
  return defaultLogger.exit(1);
8310
8310
  }
8311
+ if (!config.ideVersion) {
8312
+ config.ideVersion = process.env.NASL_IDE_VERSION || '';
8313
+ if (!config.ideVersion) {
8314
+ defaultLogger.error('缺少配置 ideVersion,请在配置文件中添加,或在环境变量中配置 NASL_IDE_VERSION');
8315
+ return defaultLogger.exit(1);
8316
+ }
8317
+ }
8318
+ if (!config.serverBaseURL) {
8319
+ config.serverBaseURL = process.env.NASL_SERVER_BASE_URL || '';
8320
+ if (!config.serverBaseURL) {
8321
+ defaultLogger.error('缺少配置 serverBaseURL,请在配置文件中添加,或在环境变量中配置 NASL_SERVER_BASE_URL');
8322
+ return defaultLogger.exit(1);
8323
+ }
8324
+ }
8325
+ if (!config.useOPENAPI)
8326
+ config.useOPENAPI = process.env.USE_LCAP_OPENAPI === 'true';
8327
+ if (!config.OPENAPI_AK)
8328
+ config.OPENAPI_AK = process.env.LCAP_OPENAPI_AK;
8329
+ if (!config.OPENAPI_SK)
8330
+ config.OPENAPI_SK = process.env.LCAP_OPENAPI_SK;
8331
+ if (config.useOPENAPI) {
8332
+ if (!config.OPENAPI_AK || !config.OPENAPI_SK) {
8333
+ defaultLogger.error(`配置了 useOPENAPI,但缺少配置 OPENAPI_AK 和 OPENAPI_SK:
8334
+ - 在 nasl.config.json 中配置 OPENAPI_AK 和 OPENAPI_SK,或者在环境变量中配置 LCAP_OPENAPI_AK 和 LCAP_OPENAPI_SK
8335
+ - 或将 useOPENAPI 配置为 false
8336
+ `);
8337
+ return defaultLogger.exit(1);
8338
+ }
8339
+ }
8311
8340
  return config;
8312
8341
  }
8313
8342
  catch (error) {
@@ -22077,7 +22106,7 @@ function requireForm_data () {
22077
22106
  var parseUrl = require$$0$6.parse;
22078
22107
  var fs = require$$0$2;
22079
22108
  var Stream = stream$4.Stream;
22080
- var crypto = require$$8;
22109
+ var crypto = crypto$1;
22081
22110
  var mime = requireMimeTypes();
22082
22111
  var asynckit = requireAsynckit();
22083
22112
  var setToStringTag = /*@__PURE__*/ requireEsSetTostringtag();
@@ -22986,7 +23015,7 @@ const generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {
22986
23015
  let str = '';
22987
23016
  const {length} = alphabet;
22988
23017
  const randomValues = new Uint32Array(size);
22989
- require$$8.randomFillSync(randomValues);
23018
+ crypto$1.randomFillSync(randomValues);
22990
23019
  for (let i = 0; i < size; i++) {
22991
23020
  str += alphabet[randomValues[i] % length];
22992
23021
  }
@@ -28771,14 +28800,286 @@ const {
28771
28800
  mergeConfig
28772
28801
  } = axios;
28773
28802
 
28774
- function createAxios(baseURL) {
28775
- return axios.create({
28803
+ // Unique ID creation requires a high quality random # generator. In the browser we therefore
28804
+ // require the crypto API and do not support built-in fallback to lower quality random number
28805
+ // generators (like Math.random()).
28806
+ let getRandomValues;
28807
+ const rnds8 = new Uint8Array(16);
28808
+ function rng() {
28809
+ // lazy load so that environments that need to polyfill have a chance to do so
28810
+ if (!getRandomValues) {
28811
+ // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
28812
+ getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
28813
+
28814
+ if (!getRandomValues) {
28815
+ throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
28816
+ }
28817
+ }
28818
+
28819
+ return getRandomValues(rnds8);
28820
+ }
28821
+
28822
+ /**
28823
+ * Convert array of 16 byte values to UUID string format of the form:
28824
+ * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
28825
+ */
28826
+
28827
+ const byteToHex = [];
28828
+
28829
+ for (let i = 0; i < 256; ++i) {
28830
+ byteToHex.push((i + 0x100).toString(16).slice(1));
28831
+ }
28832
+
28833
+ function unsafeStringify(arr, offset = 0) {
28834
+ // Note: Be careful editing this code! It's been tuned for performance
28835
+ // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
28836
+ return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
28837
+ }
28838
+
28839
+ const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
28840
+ var native = {
28841
+ randomUUID
28842
+ };
28843
+
28844
+ function v4(options, buf, offset) {
28845
+ if (native.randomUUID && true && !options) {
28846
+ return native.randomUUID();
28847
+ }
28848
+
28849
+ options = options || {};
28850
+ const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
28851
+
28852
+ rnds[6] = rnds[6] & 0x0f | 0x40;
28853
+ rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
28854
+
28855
+ return unsafeStringify(rnds);
28856
+ }
28857
+
28858
+ function generateHash(params) {
28859
+ const hash = createHash('sha256');
28860
+ hash.update(JSON.stringify(params));
28861
+ return hash.digest('hex');
28862
+ }
28863
+ async function getCachePathWithTimestamp(hash) {
28864
+ const cacheDir = join(process.cwd(), '.cache');
28865
+ await promises.mkdir(cacheDir, { recursive: true });
28866
+ return join(cacheDir, `${hash}_${Date.now()}.json`);
28867
+ }
28868
+ /**
28869
+ * 查找指定 hash 的有效缓存文件
28870
+ * @param hash 缓存标识
28871
+ * @param ttl 缓存有效期(毫秒)
28872
+ * @returns 缓存文件路径和缓存内容,如果没有有效缓存则返回 null
28873
+ */
28874
+ async function findValidCache(hash, ttl) {
28875
+ const cacheDir = join(process.cwd(), '.cache');
28876
+ try {
28877
+ await promises.mkdir(cacheDir, { recursive: true });
28878
+ const files = await promises.readdir(cacheDir);
28879
+ const now = Date.now();
28880
+ // 查找所有匹配的缓存文件
28881
+ const matchingFiles = files
28882
+ .filter((file) => file.startsWith(`${hash}_`) && file.endsWith('.json'))
28883
+ .map((file) => {
28884
+ const match = file.match(/_(\d+)\.json$/);
28885
+ if (!match)
28886
+ return null;
28887
+ const timestamp = parseInt(match[1], 10);
28888
+ return {
28889
+ path: join(cacheDir, file),
28890
+ timestamp,
28891
+ isExpired: now - timestamp > ttl,
28892
+ };
28893
+ })
28894
+ .filter((item) => item !== null);
28895
+ // 删除过期的缓存文件
28896
+ const expiredFiles = matchingFiles.filter((item) => item.isExpired);
28897
+ await Promise.all(expiredFiles.map((item) => promises.unlink(item.path).catch(() => { })));
28898
+ // 查找有效的缓存文件(按时间戳降序排序,获取最新的)
28899
+ const validFiles = matchingFiles.filter((item) => !item.isExpired).sort((a, b) => b.timestamp - a.timestamp);
28900
+ if (validFiles.length > 0) {
28901
+ const cacheFile = validFiles[0];
28902
+ const cacheContent = await promises.readFile(cacheFile.path, 'utf-8');
28903
+ const cachedResult = JSON.parse(cacheContent);
28904
+ return { path: cacheFile.path, data: cachedResult };
28905
+ }
28906
+ return null;
28907
+ }
28908
+ catch (error) {
28909
+ return null;
28910
+ }
28911
+ }
28912
+ /**
28913
+ * 高阶函数,为异步函数添加带时间戳的缓存功能
28914
+ * @param fn 需要添加缓存的函数
28915
+ * @param ttl 缓存有效期(毫秒),默认 1 小时
28916
+ * @param getCacheKey 可选的自定义缓存 key 生成函数,如果不提供则使用整个 params
28917
+ * @returns 带缓存的函数版本
28918
+ */
28919
+ function cachableWithTTL(fn, ttl = 3600 * 1000, // 默认 1 小时
28920
+ getCacheKey) {
28921
+ return async (params, extraParams) => {
28922
+ const functionName = fn.name;
28923
+ const logPrefix = functionName ? `[${functionName}]` : '[cachableWithTTL]';
28924
+ // 检查是否启用缓存
28925
+ if (process.env.NO_AI_CACHE) {
28926
+ return fn(params, extraParams);
28927
+ }
28928
+ // 使用自定义的 getCacheKey 或默认使用整个 params
28929
+ const cacheKey = getCacheKey ? getCacheKey(params) : params;
28930
+ const hash = generateHash(cacheKey);
28931
+ // 查找有效的缓存
28932
+ const validCache = await findValidCache(hash, ttl);
28933
+ if (validCache) {
28934
+ console.log(`${logPrefix} ✓ 使用缓存`);
28935
+ return validCache.data;
28936
+ }
28937
+ // 调用原函数
28938
+ const result = await fn(params, extraParams);
28939
+ // 保存结果到缓存(带时间戳)
28940
+ try {
28941
+ const cachePath = await getCachePathWithTimestamp(hash);
28942
+ await promises.writeFile(cachePath, JSON.stringify(result, null, 2), 'utf-8');
28943
+ }
28944
+ catch (error) {
28945
+ // 缓存写入失败,但不影响返回结果
28946
+ }
28947
+ return result;
28948
+ };
28949
+ }
28950
+
28951
+ /**
28952
+ * 生成客户端签名信息
28953
+ * @param appKey AppKey
28954
+ * @param secretKey SecretKey
28955
+ * @returns 签名信息
28956
+ */
28957
+ function generateClientSignature(appKey, secretKey) {
28958
+ const timestamp = Math.floor(Date.now() / 1000).toString();
28959
+ const nonce = v4();
28960
+ const plainText = `${appKey}&${nonce}&${timestamp}&${secretKey}`;
28961
+ const signature = crypto$1.createHash('md5').update(plainText).digest('hex');
28962
+ return {
28963
+ appKey,
28964
+ timestamp,
28965
+ nonce,
28966
+ signature,
28967
+ };
28968
+ }
28969
+ /**
28970
+ * 生成基础认证头
28971
+ * @param ak AppKey
28972
+ * @param sk SecretKey
28973
+ * @returns 基础认证头
28974
+ */
28975
+ function generateBaseHeaders(ak, sk) {
28976
+ const { timestamp, signature, nonce } = generateClientSignature(ak, sk);
28977
+ return {
28978
+ 'Content-Type': 'application/json',
28979
+ 'x-appKey': ak,
28980
+ 'x-timestamp': timestamp,
28981
+ 'x-nonce': nonce,
28982
+ 'x-signature': signature,
28983
+ };
28984
+ }
28985
+ /**
28986
+ * 获取租户的 signInfo(内部实现)
28987
+ * @param options 服务器选项
28988
+ * @param baseHeaders 基础认证头
28989
+ * @returns x-signInfo 值
28990
+ */
28991
+ async function _fetchSignInfo({ options, baseHeaders }) {
28992
+ const tenantName = options.tenantName || 'defaulttenant';
28993
+ const userName = tenantName === 'defaulttenant' ? 'admin' : `${tenantName}-admin`;
28994
+ const data = {
28995
+ tenantName,
28996
+ userName,
28997
+ source: 'Normal',
28998
+ };
28999
+ const url = `${options.serverBaseURL}/openapi/v3/auth/getSignInfo`;
29000
+ try {
29001
+ const tempAxios = axios.create({
29002
+ headers: baseHeaders,
29003
+ timeout: 120000,
29004
+ });
29005
+ const response = await tempAxios.post(url, data);
29006
+ return response?.data?.result || null;
29007
+ }
29008
+ catch (error) {
29009
+ console.error('Error fetching sign info:', error.response?.data);
29010
+ return null;
29011
+ }
29012
+ }
29013
+ /**
29014
+ * 获取租户的 signInfo(带缓存,1 小时过期)
29015
+ * @param options 服务器选项
29016
+ * @param baseHeaders 基础认证头
29017
+ * @returns x-signInfo 值
29018
+ */
29019
+ const fetchSignInfo = cachableWithTTL(_fetchSignInfo, 3600 * 1000, // 1 小时
29020
+ (params) => params.options);
29021
+ /**
29022
+ * 生成完整的认证头(包含 x-signInfo)
29023
+ * @param options 服务器选项
29024
+ * @returns 完整的认证头
29025
+ */
29026
+ async function generateCompleteHeaders(options) {
29027
+ const headers = {
29028
+ 'Content-Type': 'application/json',
29029
+ };
29030
+ // 如果没有提供 ak 和 sk,返回基础 headers
29031
+ if (!options.OPENAPI_AK || !options.OPENAPI_SK) {
29032
+ throw new Error(`配置了 useOPENAPI,但缺少配置 OPENAPI_AK 和 OPENAPI_SK:
29033
+ - 在 nasl.config.json 中配置 OPENAPI_AK 和 OPENAPI_SK,或者在环境变量中配置 LCAP_OPENAPI_AK 和 LCAP_OPENAPI_SK
29034
+ - 或将 useOPENAPI 配置为 false
29035
+ `);
29036
+ }
29037
+ // 生成基础认证头
29038
+ const baseHeaders = generateBaseHeaders(options.OPENAPI_AK, options.OPENAPI_SK);
29039
+ Object.assign(headers, baseHeaders);
29040
+ // 获取 signInfo
29041
+ const signInfo = await fetchSignInfo({ options, baseHeaders: headers });
29042
+ if (signInfo) {
29043
+ headers['x-signInfo'] = signInfo;
29044
+ }
29045
+ return headers;
29046
+ }
29047
+
29048
+ /**
29049
+ * 创建 Axios 实例
29050
+ * @param options 服务器选项,包含认证信息
29051
+ * @returns Axios 实例
29052
+ */
29053
+ async function createAxios(options) {
29054
+ // 如果需要鉴权,拼接 /openapi/v3/nasl;否则使用原始 URL
29055
+ const serverBaseURL = new URL(options.serverBaseURL).origin;
29056
+ const baseURL = options.useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
29057
+ // 如果需要鉴权,生成完整的认证头;否则只使用基础 headers
29058
+ const headers = options.useOPENAPI ? await generateCompleteHeaders(options) : { 'Content-Type': 'application/json' };
29059
+ console.log('本次服务调用方为:', baseURL);
29060
+ const instance = axios.create({
28776
29061
  baseURL,
28777
- headers: {
28778
- 'Content-Type': 'application/json',
28779
- },
29062
+ headers,
28780
29063
  timeout: 120000,
28781
29064
  });
29065
+ const oldPost = instance.post;
29066
+ instance.post = async (url, data, config) => {
29067
+ return oldPost(url, data, config).then((res) => {
29068
+ const data = res.data;
29069
+ if (data.code !== 200)
29070
+ throw new Error(JSON.stringify(data));
29071
+ return res;
29072
+ }).catch((err) => {
29073
+ // console.log(err.response ? err.response.data : err);
29074
+ if (err.response) {
29075
+ throw new Error(JSON.stringify(err.response.data));
29076
+ }
29077
+ else {
29078
+ throw err;
29079
+ }
29080
+ });
29081
+ };
29082
+ return instance;
28782
29083
  }
28783
29084
 
28784
29085
  /**
@@ -28788,13 +29089,11 @@ function createAxios(baseURL) {
28788
29089
  async function compileApi(fullNaturalTS, options) {
28789
29090
  // 这里需要调用实际的编译服务接口
28790
29091
  // 示例实现:
28791
- const axios = createAxios(options.serverBaseURL);
29092
+ const axios = await createAxios(options);
28792
29093
  const res = await axios.post(`/compile/tsx?ideVersion=${options.ideVersion}&needAnnotation=true`, fullNaturalTS, {
28793
29094
  headers: { 'Content-Type': 'text/plain' },
28794
29095
  });
28795
29096
  const data = res.data;
28796
- if (data.code !== 200)
28797
- throw new Error(data.message);
28798
29097
  const { bundle } = data.result;
28799
29098
  const fileMap = bundle.frontendBundle.files;
28800
29099
  const files = Object.keys(fileMap).map((key) => {
@@ -37667,10 +37966,7 @@ async function compile(entry, options) {
37667
37966
  logger.info('正在调用编译服务...');
37668
37967
  try {
37669
37968
  const fullNaturalTS = composeToString(collectedFiles);
37670
- const outputFiles = await compileApi(fullNaturalTS, {
37671
- serverBaseURL: config.serverBaseURL,
37672
- ideVersion: config.ideVersion,
37673
- });
37969
+ const outputFiles = await compileApi(fullNaturalTS, config);
37674
37970
  logger.success('编译成功!');
37675
37971
  // 写入输出文件
37676
37972
  for (const file of outputFiles) {
@@ -37697,7 +37993,7 @@ async function tryCompile(entry, options) {
37697
37993
  }
37698
37994
  }
37699
37995
 
37700
- var version = "0.1.16";
37996
+ var version = "0.1.18";
37701
37997
  var pkg = {
37702
37998
  version: version};
37703
37999