@nasl/cli 0.1.17 → 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.
- package/README.md +113 -11
- package/dist/bin/nasl.mjs +151 -34
- package/dist/bin/nasl.mjs.map +1 -1
- package/dist/bin/naslc.mjs +143 -27
- package/dist/bin/naslc.mjs.map +1 -1
- package/dist/index.mjs +150 -33
- package/dist/index.mjs.map +1 -1
- package/out/apis/cachable.d.ts +16 -0
- package/out/apis/cachable.d.ts.map +1 -0
- package/out/apis/cachable.js +142 -0
- package/out/apis/cachable.js.map +1 -0
- package/out/apis/createAxios.d.ts.map +1 -1
- package/out/apis/createAxios.js +2 -3
- package/out/apis/createAxios.js.map +1 -1
- package/out/apis/openapi.d.ts +5 -2
- package/out/apis/openapi.d.ts.map +1 -1
- package/out/apis/openapi.js +21 -25
- package/out/apis/openapi.js.map +1 -1
- package/out/commands/createAppInIde.d.ts.map +1 -1
- package/out/commands/createAppInIde.js +4 -0
- package/out/commands/createAppInIde.js.map +1 -1
- package/out/commands/transform.d.ts.map +1 -1
- package/out/commands/transform.js +1 -4
- package/out/commands/transform.js.map +1 -1
- package/out/utils/config.d.ts.map +1 -1
- package/out/utils/config.js +31 -2
- package/out/utils/config.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/naslc.mjs
CHANGED
|
@@ -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 crypto$1 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.
|
|
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) {
|
|
@@ -28826,18 +28855,99 @@ function v4(options, buf, offset) {
|
|
|
28826
28855
|
return unsafeStringify(rnds);
|
|
28827
28856
|
}
|
|
28828
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
|
+
}
|
|
28829
28868
|
/**
|
|
28830
|
-
*
|
|
28869
|
+
* 查找指定 hash 的有效缓存文件
|
|
28870
|
+
* @param hash 缓存标识
|
|
28871
|
+
* @param ttl 缓存有效期(毫秒)
|
|
28872
|
+
* @returns 缓存文件路径和缓存内容,如果没有有效缓存则返回 null
|
|
28831
28873
|
*/
|
|
28832
|
-
function
|
|
28833
|
-
|
|
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
|
+
}
|
|
28834
28911
|
}
|
|
28835
28912
|
/**
|
|
28836
|
-
*
|
|
28913
|
+
* 高阶函数,为异步函数添加带时间戳的缓存功能
|
|
28914
|
+
* @param fn 需要添加缓存的函数
|
|
28915
|
+
* @param ttl 缓存有效期(毫秒),默认 1 小时
|
|
28916
|
+
* @param getCacheKey 可选的自定义缓存 key 生成函数,如果不提供则使用整个 params
|
|
28917
|
+
* @returns 带缓存的函数版本
|
|
28837
28918
|
*/
|
|
28838
|
-
function
|
|
28839
|
-
|
|
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
|
+
};
|
|
28840
28949
|
}
|
|
28950
|
+
|
|
28841
28951
|
/**
|
|
28842
28952
|
* 生成客户端签名信息
|
|
28843
28953
|
* @param appKey AppKey
|
|
@@ -28847,8 +28957,8 @@ function generateSignature(plainText) {
|
|
|
28847
28957
|
function generateClientSignature(appKey, secretKey) {
|
|
28848
28958
|
const timestamp = Math.floor(Date.now() / 1000).toString();
|
|
28849
28959
|
const nonce = v4();
|
|
28850
|
-
const plainText =
|
|
28851
|
-
const signature =
|
|
28960
|
+
const plainText = `${appKey}&${nonce}&${timestamp}&${secretKey}`;
|
|
28961
|
+
const signature = crypto$1.createHash('md5').update(plainText).digest('hex');
|
|
28852
28962
|
return {
|
|
28853
28963
|
appKey,
|
|
28854
28964
|
timestamp,
|
|
@@ -28873,12 +28983,12 @@ function generateBaseHeaders(ak, sk) {
|
|
|
28873
28983
|
};
|
|
28874
28984
|
}
|
|
28875
28985
|
/**
|
|
28876
|
-
* 获取租户的 signInfo
|
|
28986
|
+
* 获取租户的 signInfo(内部实现)
|
|
28877
28987
|
* @param options 服务器选项
|
|
28878
28988
|
* @param baseHeaders 基础认证头
|
|
28879
28989
|
* @returns x-signInfo 值
|
|
28880
28990
|
*/
|
|
28881
|
-
async function
|
|
28991
|
+
async function _fetchSignInfo({ options, baseHeaders }) {
|
|
28882
28992
|
const tenantName = options.tenantName || 'defaulttenant';
|
|
28883
28993
|
const userName = tenantName === 'defaulttenant' ? 'admin' : `${tenantName}-admin`;
|
|
28884
28994
|
const data = {
|
|
@@ -28900,6 +29010,14 @@ async function fetchSignInfo(options, baseHeaders) {
|
|
|
28900
29010
|
return null;
|
|
28901
29011
|
}
|
|
28902
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);
|
|
28903
29021
|
/**
|
|
28904
29022
|
* 生成完整的认证头(包含 x-signInfo)
|
|
28905
29023
|
* @param options 服务器选项
|
|
@@ -28909,19 +29027,18 @@ async function generateCompleteHeaders(options) {
|
|
|
28909
29027
|
const headers = {
|
|
28910
29028
|
'Content-Type': 'application/json',
|
|
28911
29029
|
};
|
|
28912
|
-
const OPENAPI_AK = options.OPENAPI_AK || process.env.LCAP_OPENAPI_AK;
|
|
28913
|
-
const OPENAPI_SK = options.OPENAPI_SK || process.env.LCAP_OPENAPI_SK;
|
|
28914
29030
|
// 如果没有提供 ak 和 sk,返回基础 headers
|
|
28915
|
-
if (!OPENAPI_AK || !OPENAPI_SK) {
|
|
28916
|
-
throw new Error(`配置了 useOPENAPI
|
|
28917
|
-
-
|
|
28918
|
-
-
|
|
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
|
+
`);
|
|
28919
29036
|
}
|
|
28920
29037
|
// 生成基础认证头
|
|
28921
|
-
const baseHeaders = generateBaseHeaders(OPENAPI_AK, OPENAPI_SK);
|
|
29038
|
+
const baseHeaders = generateBaseHeaders(options.OPENAPI_AK, options.OPENAPI_SK);
|
|
28922
29039
|
Object.assign(headers, baseHeaders);
|
|
28923
29040
|
// 获取 signInfo
|
|
28924
|
-
const signInfo = await fetchSignInfo(options, headers);
|
|
29041
|
+
const signInfo = await fetchSignInfo({ options, baseHeaders: headers });
|
|
28925
29042
|
if (signInfo) {
|
|
28926
29043
|
headers['x-signInfo'] = signInfo;
|
|
28927
29044
|
}
|
|
@@ -28936,10 +29053,9 @@ async function generateCompleteHeaders(options) {
|
|
|
28936
29053
|
async function createAxios(options) {
|
|
28937
29054
|
// 如果需要鉴权,拼接 /openapi/v3/nasl;否则使用原始 URL
|
|
28938
29055
|
const serverBaseURL = new URL(options.serverBaseURL).origin;
|
|
28939
|
-
const
|
|
28940
|
-
const baseURL = useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
|
|
29056
|
+
const baseURL = options.useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
|
|
28941
29057
|
// 如果需要鉴权,生成完整的认证头;否则只使用基础 headers
|
|
28942
|
-
const headers = useOPENAPI ? await generateCompleteHeaders(options) : { 'Content-Type': 'application/json' };
|
|
29058
|
+
const headers = options.useOPENAPI ? await generateCompleteHeaders(options) : { 'Content-Type': 'application/json' };
|
|
28943
29059
|
console.log('本次服务调用方为:', baseURL);
|
|
28944
29060
|
const instance = axios.create({
|
|
28945
29061
|
baseURL,
|
|
@@ -37877,7 +37993,7 @@ async function tryCompile(entry, options) {
|
|
|
37877
37993
|
}
|
|
37878
37994
|
}
|
|
37879
37995
|
|
|
37880
|
-
var version = "0.1.
|
|
37996
|
+
var version = "0.1.18";
|
|
37881
37997
|
var pkg = {
|
|
37882
37998
|
version: version};
|
|
37883
37999
|
|