@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.
- package/README.md +113 -11
- package/dist/bin/nasl.mjs +340 -43
- package/dist/bin/nasl.mjs.map +1 -1
- package/dist/bin/naslc.mjs +316 -20
- package/dist/bin/naslc.mjs.map +1 -1
- package/dist/index.mjs +336 -39
- 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/compileApi.d.ts.map +1 -1
- package/out/apis/compileApi.js +2 -4
- package/out/apis/compileApi.js.map +1 -1
- package/out/apis/createAppApi.js +1 -1
- package/out/apis/createAppApi.js.map +1 -1
- package/out/apis/createAxios.d.ts +7 -1
- package/out/apis/createAxios.d.ts.map +1 -1
- package/out/apis/createAxios.js +33 -5
- package/out/apis/createAxios.js.map +1 -1
- package/out/apis/openapi.d.ts +37 -0
- package/out/apis/openapi.d.ts.map +1 -0
- package/out/apis/openapi.js +110 -0
- package/out/apis/openapi.js.map +1 -0
- package/out/apis/transformApi.d.ts +1 -1
- package/out/apis/transformApi.d.ts.map +1 -1
- package/out/apis/transformApi.js +4 -6
- package/out/apis/transformApi.js.map +1 -1
- package/out/bin/nasl.js +3 -3
- package/out/bin/nasl.js.map +1 -1
- package/out/commands/check.d.ts.map +1 -1
- package/out/commands/check.js +1 -4
- package/out/commands/check.js.map +1 -1
- package/out/commands/compile.d.ts.map +1 -1
- package/out/commands/compile.js +1 -4
- package/out/commands/compile.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 +6 -4
- package/out/commands/transform.js.map +1 -1
- package/out/types/api.d.ts +8 -0
- package/out/types/api.d.ts.map +1 -1
- package/out/types/config.d.ts +6 -0
- package/out/types/config.d.ts.map +1 -1
- package/out/types/config.js +2 -2
- package/out/types/config.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 +3 -1
package/dist/bin/nasl.mjs
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import require$$0$1, { EventEmitter } from 'events';
|
|
4
4
|
import require$$1, { spawn, spawnSync } from 'child_process';
|
|
5
5
|
import * as sysPath from 'path';
|
|
6
|
-
import sysPath__default from 'path';
|
|
7
|
-
import require$$0$2, { unwatchFile, watchFile, watch as watch$1, stat as stat$3 } from 'fs';
|
|
6
|
+
import sysPath__default, { join } from 'path';
|
|
7
|
+
import require$$0$2, { promises, unwatchFile, watchFile, watch as watch$1, stat as stat$3 } from 'fs';
|
|
8
8
|
import require$$4 from 'process';
|
|
9
9
|
import require$$0$3 from 'constants';
|
|
10
10
|
import stream$4, { Readable } from 'stream';
|
|
@@ -15,14 +15,14 @@ import require$$1$1 from 'tty';
|
|
|
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
|
|
18
|
+
import crypto$1, { createHash } from 'crypto';
|
|
19
19
|
import http2 from 'http2';
|
|
20
20
|
import zlib from 'zlib';
|
|
21
21
|
import * as readline from 'readline';
|
|
22
22
|
import { realpath as realpath$1, stat as stat$2, lstat as lstat$1, open, readdir as readdir$1 } from 'fs/promises';
|
|
23
23
|
import { lstat, stat as stat$1, readdir, realpath } from 'node:fs/promises';
|
|
24
24
|
import { Readable as Readable$1 } from 'node:stream';
|
|
25
|
-
import { resolve, join, relative, sep } from 'node:path';
|
|
25
|
+
import { resolve, join as join$1, relative, sep } from 'node:path';
|
|
26
26
|
|
|
27
27
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
28
28
|
|
|
@@ -6192,10 +6192,10 @@ var libExports = /*@__PURE__*/ requireLib();
|
|
|
6192
6192
|
* 默认配置
|
|
6193
6193
|
*/
|
|
6194
6194
|
const DEFAULT_CONFIG = {
|
|
6195
|
-
serverBaseURL: 'https://nasl.lcap.163yun.com
|
|
6195
|
+
serverBaseURL: 'https://nasl.lcap.163yun.com',
|
|
6196
6196
|
representation: 'NaturalTS',
|
|
6197
6197
|
namespaceResolution: 'filename-as-namespace',
|
|
6198
|
-
ideVersion: '4.
|
|
6198
|
+
ideVersion: '4.4',
|
|
6199
6199
|
srcDir: 'src',
|
|
6200
6200
|
outDir: 'out',
|
|
6201
6201
|
};
|
|
@@ -8338,10 +8338,39 @@ function loadConfig(configDir) {
|
|
|
8338
8338
|
const content = libExports.readFileSync(configPath, 'utf-8');
|
|
8339
8339
|
const config = JSON.parse(content);
|
|
8340
8340
|
// 验证必需字段
|
|
8341
|
-
if (!config.
|
|
8342
|
-
defaultLogger.error('
|
|
8341
|
+
if (!config.srcDir || !config.outDir) {
|
|
8342
|
+
defaultLogger.error('配置文件格式不正确,缺少必需的 srcDir 或 outDir 字段');
|
|
8343
8343
|
return defaultLogger.exit(1);
|
|
8344
8344
|
}
|
|
8345
|
+
if (!config.ideVersion) {
|
|
8346
|
+
config.ideVersion = process.env.NASL_IDE_VERSION || '';
|
|
8347
|
+
if (!config.ideVersion) {
|
|
8348
|
+
defaultLogger.error('缺少配置 ideVersion,请在配置文件中添加,或在环境变量中配置 NASL_IDE_VERSION');
|
|
8349
|
+
return defaultLogger.exit(1);
|
|
8350
|
+
}
|
|
8351
|
+
}
|
|
8352
|
+
if (!config.serverBaseURL) {
|
|
8353
|
+
config.serverBaseURL = process.env.NASL_SERVER_BASE_URL || '';
|
|
8354
|
+
if (!config.serverBaseURL) {
|
|
8355
|
+
defaultLogger.error('缺少配置 serverBaseURL,请在配置文件中添加,或在环境变量中配置 NASL_SERVER_BASE_URL');
|
|
8356
|
+
return defaultLogger.exit(1);
|
|
8357
|
+
}
|
|
8358
|
+
}
|
|
8359
|
+
if (!config.useOPENAPI)
|
|
8360
|
+
config.useOPENAPI = process.env.USE_LCAP_OPENAPI === 'true';
|
|
8361
|
+
if (!config.OPENAPI_AK)
|
|
8362
|
+
config.OPENAPI_AK = process.env.LCAP_OPENAPI_AK;
|
|
8363
|
+
if (!config.OPENAPI_SK)
|
|
8364
|
+
config.OPENAPI_SK = process.env.LCAP_OPENAPI_SK;
|
|
8365
|
+
if (config.useOPENAPI) {
|
|
8366
|
+
if (!config.OPENAPI_AK || !config.OPENAPI_SK) {
|
|
8367
|
+
defaultLogger.error(`配置了 useOPENAPI,但缺少配置 OPENAPI_AK 和 OPENAPI_SK:
|
|
8368
|
+
- 在 nasl.config.json 中配置 OPENAPI_AK 和 OPENAPI_SK,或者在环境变量中配置 LCAP_OPENAPI_AK 和 LCAP_OPENAPI_SK
|
|
8369
|
+
- 或将 useOPENAPI 配置为 false
|
|
8370
|
+
`);
|
|
8371
|
+
return defaultLogger.exit(1);
|
|
8372
|
+
}
|
|
8373
|
+
}
|
|
8345
8374
|
return config;
|
|
8346
8375
|
}
|
|
8347
8376
|
catch (error) {
|
|
@@ -22146,7 +22175,7 @@ function requireForm_data () {
|
|
|
22146
22175
|
var parseUrl = require$$0$6.parse;
|
|
22147
22176
|
var fs = require$$0$2;
|
|
22148
22177
|
var Stream = stream$4.Stream;
|
|
22149
|
-
var crypto =
|
|
22178
|
+
var crypto = crypto$1;
|
|
22150
22179
|
var mime = requireMimeTypes();
|
|
22151
22180
|
var asynckit = requireAsynckit();
|
|
22152
22181
|
var setToStringTag = /*@__PURE__*/ requireEsSetTostringtag();
|
|
@@ -23055,7 +23084,7 @@ const generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {
|
|
|
23055
23084
|
let str = '';
|
|
23056
23085
|
const {length} = alphabet;
|
|
23057
23086
|
const randomValues = new Uint32Array(size);
|
|
23058
|
-
|
|
23087
|
+
crypto$1.randomFillSync(randomValues);
|
|
23059
23088
|
for (let i = 0; i < size; i++) {
|
|
23060
23089
|
str += alphabet[randomValues[i] % length];
|
|
23061
23090
|
}
|
|
@@ -28840,14 +28869,286 @@ const {
|
|
|
28840
28869
|
mergeConfig
|
|
28841
28870
|
} = axios;
|
|
28842
28871
|
|
|
28843
|
-
|
|
28844
|
-
|
|
28872
|
+
// Unique ID creation requires a high quality random # generator. In the browser we therefore
|
|
28873
|
+
// require the crypto API and do not support built-in fallback to lower quality random number
|
|
28874
|
+
// generators (like Math.random()).
|
|
28875
|
+
let getRandomValues;
|
|
28876
|
+
const rnds8 = new Uint8Array(16);
|
|
28877
|
+
function rng() {
|
|
28878
|
+
// lazy load so that environments that need to polyfill have a chance to do so
|
|
28879
|
+
if (!getRandomValues) {
|
|
28880
|
+
// getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
|
|
28881
|
+
getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
|
|
28882
|
+
|
|
28883
|
+
if (!getRandomValues) {
|
|
28884
|
+
throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
|
|
28885
|
+
}
|
|
28886
|
+
}
|
|
28887
|
+
|
|
28888
|
+
return getRandomValues(rnds8);
|
|
28889
|
+
}
|
|
28890
|
+
|
|
28891
|
+
/**
|
|
28892
|
+
* Convert array of 16 byte values to UUID string format of the form:
|
|
28893
|
+
* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
28894
|
+
*/
|
|
28895
|
+
|
|
28896
|
+
const byteToHex = [];
|
|
28897
|
+
|
|
28898
|
+
for (let i = 0; i < 256; ++i) {
|
|
28899
|
+
byteToHex.push((i + 0x100).toString(16).slice(1));
|
|
28900
|
+
}
|
|
28901
|
+
|
|
28902
|
+
function unsafeStringify(arr, offset = 0) {
|
|
28903
|
+
// Note: Be careful editing this code! It's been tuned for performance
|
|
28904
|
+
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
|
|
28905
|
+
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]];
|
|
28906
|
+
}
|
|
28907
|
+
|
|
28908
|
+
const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
28909
|
+
var native = {
|
|
28910
|
+
randomUUID
|
|
28911
|
+
};
|
|
28912
|
+
|
|
28913
|
+
function v4(options, buf, offset) {
|
|
28914
|
+
if (native.randomUUID && true && !options) {
|
|
28915
|
+
return native.randomUUID();
|
|
28916
|
+
}
|
|
28917
|
+
|
|
28918
|
+
options = options || {};
|
|
28919
|
+
const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
28920
|
+
|
|
28921
|
+
rnds[6] = rnds[6] & 0x0f | 0x40;
|
|
28922
|
+
rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
|
|
28923
|
+
|
|
28924
|
+
return unsafeStringify(rnds);
|
|
28925
|
+
}
|
|
28926
|
+
|
|
28927
|
+
function generateHash(params) {
|
|
28928
|
+
const hash = createHash('sha256');
|
|
28929
|
+
hash.update(JSON.stringify(params));
|
|
28930
|
+
return hash.digest('hex');
|
|
28931
|
+
}
|
|
28932
|
+
async function getCachePathWithTimestamp(hash) {
|
|
28933
|
+
const cacheDir = join(process.cwd(), '.cache');
|
|
28934
|
+
await promises.mkdir(cacheDir, { recursive: true });
|
|
28935
|
+
return join(cacheDir, `${hash}_${Date.now()}.json`);
|
|
28936
|
+
}
|
|
28937
|
+
/**
|
|
28938
|
+
* 查找指定 hash 的有效缓存文件
|
|
28939
|
+
* @param hash 缓存标识
|
|
28940
|
+
* @param ttl 缓存有效期(毫秒)
|
|
28941
|
+
* @returns 缓存文件路径和缓存内容,如果没有有效缓存则返回 null
|
|
28942
|
+
*/
|
|
28943
|
+
async function findValidCache(hash, ttl) {
|
|
28944
|
+
const cacheDir = join(process.cwd(), '.cache');
|
|
28945
|
+
try {
|
|
28946
|
+
await promises.mkdir(cacheDir, { recursive: true });
|
|
28947
|
+
const files = await promises.readdir(cacheDir);
|
|
28948
|
+
const now = Date.now();
|
|
28949
|
+
// 查找所有匹配的缓存文件
|
|
28950
|
+
const matchingFiles = files
|
|
28951
|
+
.filter((file) => file.startsWith(`${hash}_`) && file.endsWith('.json'))
|
|
28952
|
+
.map((file) => {
|
|
28953
|
+
const match = file.match(/_(\d+)\.json$/);
|
|
28954
|
+
if (!match)
|
|
28955
|
+
return null;
|
|
28956
|
+
const timestamp = parseInt(match[1], 10);
|
|
28957
|
+
return {
|
|
28958
|
+
path: join(cacheDir, file),
|
|
28959
|
+
timestamp,
|
|
28960
|
+
isExpired: now - timestamp > ttl,
|
|
28961
|
+
};
|
|
28962
|
+
})
|
|
28963
|
+
.filter((item) => item !== null);
|
|
28964
|
+
// 删除过期的缓存文件
|
|
28965
|
+
const expiredFiles = matchingFiles.filter((item) => item.isExpired);
|
|
28966
|
+
await Promise.all(expiredFiles.map((item) => promises.unlink(item.path).catch(() => { })));
|
|
28967
|
+
// 查找有效的缓存文件(按时间戳降序排序,获取最新的)
|
|
28968
|
+
const validFiles = matchingFiles.filter((item) => !item.isExpired).sort((a, b) => b.timestamp - a.timestamp);
|
|
28969
|
+
if (validFiles.length > 0) {
|
|
28970
|
+
const cacheFile = validFiles[0];
|
|
28971
|
+
const cacheContent = await promises.readFile(cacheFile.path, 'utf-8');
|
|
28972
|
+
const cachedResult = JSON.parse(cacheContent);
|
|
28973
|
+
return { path: cacheFile.path, data: cachedResult };
|
|
28974
|
+
}
|
|
28975
|
+
return null;
|
|
28976
|
+
}
|
|
28977
|
+
catch (error) {
|
|
28978
|
+
return null;
|
|
28979
|
+
}
|
|
28980
|
+
}
|
|
28981
|
+
/**
|
|
28982
|
+
* 高阶函数,为异步函数添加带时间戳的缓存功能
|
|
28983
|
+
* @param fn 需要添加缓存的函数
|
|
28984
|
+
* @param ttl 缓存有效期(毫秒),默认 1 小时
|
|
28985
|
+
* @param getCacheKey 可选的自定义缓存 key 生成函数,如果不提供则使用整个 params
|
|
28986
|
+
* @returns 带缓存的函数版本
|
|
28987
|
+
*/
|
|
28988
|
+
function cachableWithTTL(fn, ttl = 3600 * 1000, // 默认 1 小时
|
|
28989
|
+
getCacheKey) {
|
|
28990
|
+
return async (params, extraParams) => {
|
|
28991
|
+
const functionName = fn.name;
|
|
28992
|
+
const logPrefix = functionName ? `[${functionName}]` : '[cachableWithTTL]';
|
|
28993
|
+
// 检查是否启用缓存
|
|
28994
|
+
if (process.env.NO_AI_CACHE) {
|
|
28995
|
+
return fn(params, extraParams);
|
|
28996
|
+
}
|
|
28997
|
+
// 使用自定义的 getCacheKey 或默认使用整个 params
|
|
28998
|
+
const cacheKey = getCacheKey ? getCacheKey(params) : params;
|
|
28999
|
+
const hash = generateHash(cacheKey);
|
|
29000
|
+
// 查找有效的缓存
|
|
29001
|
+
const validCache = await findValidCache(hash, ttl);
|
|
29002
|
+
if (validCache) {
|
|
29003
|
+
console.log(`${logPrefix} ✓ 使用缓存`);
|
|
29004
|
+
return validCache.data;
|
|
29005
|
+
}
|
|
29006
|
+
// 调用原函数
|
|
29007
|
+
const result = await fn(params, extraParams);
|
|
29008
|
+
// 保存结果到缓存(带时间戳)
|
|
29009
|
+
try {
|
|
29010
|
+
const cachePath = await getCachePathWithTimestamp(hash);
|
|
29011
|
+
await promises.writeFile(cachePath, JSON.stringify(result, null, 2), 'utf-8');
|
|
29012
|
+
}
|
|
29013
|
+
catch (error) {
|
|
29014
|
+
// 缓存写入失败,但不影响返回结果
|
|
29015
|
+
}
|
|
29016
|
+
return result;
|
|
29017
|
+
};
|
|
29018
|
+
}
|
|
29019
|
+
|
|
29020
|
+
/**
|
|
29021
|
+
* 生成客户端签名信息
|
|
29022
|
+
* @param appKey AppKey
|
|
29023
|
+
* @param secretKey SecretKey
|
|
29024
|
+
* @returns 签名信息
|
|
29025
|
+
*/
|
|
29026
|
+
function generateClientSignature(appKey, secretKey) {
|
|
29027
|
+
const timestamp = Math.floor(Date.now() / 1000).toString();
|
|
29028
|
+
const nonce = v4();
|
|
29029
|
+
const plainText = `${appKey}&${nonce}&${timestamp}&${secretKey}`;
|
|
29030
|
+
const signature = crypto$1.createHash('md5').update(plainText).digest('hex');
|
|
29031
|
+
return {
|
|
29032
|
+
appKey,
|
|
29033
|
+
timestamp,
|
|
29034
|
+
nonce,
|
|
29035
|
+
signature,
|
|
29036
|
+
};
|
|
29037
|
+
}
|
|
29038
|
+
/**
|
|
29039
|
+
* 生成基础认证头
|
|
29040
|
+
* @param ak AppKey
|
|
29041
|
+
* @param sk SecretKey
|
|
29042
|
+
* @returns 基础认证头
|
|
29043
|
+
*/
|
|
29044
|
+
function generateBaseHeaders(ak, sk) {
|
|
29045
|
+
const { timestamp, signature, nonce } = generateClientSignature(ak, sk);
|
|
29046
|
+
return {
|
|
29047
|
+
'Content-Type': 'application/json',
|
|
29048
|
+
'x-appKey': ak,
|
|
29049
|
+
'x-timestamp': timestamp,
|
|
29050
|
+
'x-nonce': nonce,
|
|
29051
|
+
'x-signature': signature,
|
|
29052
|
+
};
|
|
29053
|
+
}
|
|
29054
|
+
/**
|
|
29055
|
+
* 获取租户的 signInfo(内部实现)
|
|
29056
|
+
* @param options 服务器选项
|
|
29057
|
+
* @param baseHeaders 基础认证头
|
|
29058
|
+
* @returns x-signInfo 值
|
|
29059
|
+
*/
|
|
29060
|
+
async function _fetchSignInfo({ options, baseHeaders }) {
|
|
29061
|
+
const tenantName = options.tenantName || 'defaulttenant';
|
|
29062
|
+
const userName = tenantName === 'defaulttenant' ? 'admin' : `${tenantName}-admin`;
|
|
29063
|
+
const data = {
|
|
29064
|
+
tenantName,
|
|
29065
|
+
userName,
|
|
29066
|
+
source: 'Normal',
|
|
29067
|
+
};
|
|
29068
|
+
const url = `${options.serverBaseURL}/openapi/v3/auth/getSignInfo`;
|
|
29069
|
+
try {
|
|
29070
|
+
const tempAxios = axios.create({
|
|
29071
|
+
headers: baseHeaders,
|
|
29072
|
+
timeout: 120000,
|
|
29073
|
+
});
|
|
29074
|
+
const response = await tempAxios.post(url, data);
|
|
29075
|
+
return response?.data?.result || null;
|
|
29076
|
+
}
|
|
29077
|
+
catch (error) {
|
|
29078
|
+
console.error('Error fetching sign info:', error.response?.data);
|
|
29079
|
+
return null;
|
|
29080
|
+
}
|
|
29081
|
+
}
|
|
29082
|
+
/**
|
|
29083
|
+
* 获取租户的 signInfo(带缓存,1 小时过期)
|
|
29084
|
+
* @param options 服务器选项
|
|
29085
|
+
* @param baseHeaders 基础认证头
|
|
29086
|
+
* @returns x-signInfo 值
|
|
29087
|
+
*/
|
|
29088
|
+
const fetchSignInfo = cachableWithTTL(_fetchSignInfo, 3600 * 1000, // 1 小时
|
|
29089
|
+
(params) => params.options);
|
|
29090
|
+
/**
|
|
29091
|
+
* 生成完整的认证头(包含 x-signInfo)
|
|
29092
|
+
* @param options 服务器选项
|
|
29093
|
+
* @returns 完整的认证头
|
|
29094
|
+
*/
|
|
29095
|
+
async function generateCompleteHeaders(options) {
|
|
29096
|
+
const headers = {
|
|
29097
|
+
'Content-Type': 'application/json',
|
|
29098
|
+
};
|
|
29099
|
+
// 如果没有提供 ak 和 sk,返回基础 headers
|
|
29100
|
+
if (!options.OPENAPI_AK || !options.OPENAPI_SK) {
|
|
29101
|
+
throw new Error(`配置了 useOPENAPI,但缺少配置 OPENAPI_AK 和 OPENAPI_SK:
|
|
29102
|
+
- 在 nasl.config.json 中配置 OPENAPI_AK 和 OPENAPI_SK,或者在环境变量中配置 LCAP_OPENAPI_AK 和 LCAP_OPENAPI_SK
|
|
29103
|
+
- 或将 useOPENAPI 配置为 false
|
|
29104
|
+
`);
|
|
29105
|
+
}
|
|
29106
|
+
// 生成基础认证头
|
|
29107
|
+
const baseHeaders = generateBaseHeaders(options.OPENAPI_AK, options.OPENAPI_SK);
|
|
29108
|
+
Object.assign(headers, baseHeaders);
|
|
29109
|
+
// 获取 signInfo
|
|
29110
|
+
const signInfo = await fetchSignInfo({ options, baseHeaders: headers });
|
|
29111
|
+
if (signInfo) {
|
|
29112
|
+
headers['x-signInfo'] = signInfo;
|
|
29113
|
+
}
|
|
29114
|
+
return headers;
|
|
29115
|
+
}
|
|
29116
|
+
|
|
29117
|
+
/**
|
|
29118
|
+
* 创建 Axios 实例
|
|
29119
|
+
* @param options 服务器选项,包含认证信息
|
|
29120
|
+
* @returns Axios 实例
|
|
29121
|
+
*/
|
|
29122
|
+
async function createAxios(options) {
|
|
29123
|
+
// 如果需要鉴权,拼接 /openapi/v3/nasl;否则使用原始 URL
|
|
29124
|
+
const serverBaseURL = new URL(options.serverBaseURL).origin;
|
|
29125
|
+
const baseURL = options.useOPENAPI ? `${serverBaseURL}/openapi/v3/nasl` : `${serverBaseURL}/api/v1/nasl`;
|
|
29126
|
+
// 如果需要鉴权,生成完整的认证头;否则只使用基础 headers
|
|
29127
|
+
const headers = options.useOPENAPI ? await generateCompleteHeaders(options) : { 'Content-Type': 'application/json' };
|
|
29128
|
+
console.log('本次服务调用方为:', baseURL);
|
|
29129
|
+
const instance = axios.create({
|
|
28845
29130
|
baseURL,
|
|
28846
|
-
headers
|
|
28847
|
-
'Content-Type': 'application/json',
|
|
28848
|
-
},
|
|
29131
|
+
headers,
|
|
28849
29132
|
timeout: 120000,
|
|
28850
29133
|
});
|
|
29134
|
+
const oldPost = instance.post;
|
|
29135
|
+
instance.post = async (url, data, config) => {
|
|
29136
|
+
return oldPost(url, data, config).then((res) => {
|
|
29137
|
+
const data = res.data;
|
|
29138
|
+
if (data.code !== 200)
|
|
29139
|
+
throw new Error(JSON.stringify(data));
|
|
29140
|
+
return res;
|
|
29141
|
+
}).catch((err) => {
|
|
29142
|
+
// console.log(err.response ? err.response.data : err);
|
|
29143
|
+
if (err.response) {
|
|
29144
|
+
throw new Error(JSON.stringify(err.response.data));
|
|
29145
|
+
}
|
|
29146
|
+
else {
|
|
29147
|
+
throw err;
|
|
29148
|
+
}
|
|
29149
|
+
});
|
|
29150
|
+
};
|
|
29151
|
+
return instance;
|
|
28851
29152
|
}
|
|
28852
29153
|
|
|
28853
29154
|
function truncate(str, maxLength) {
|
|
@@ -28861,13 +29162,11 @@ function truncate(str, maxLength) {
|
|
|
28861
29162
|
async function compileApi(fullNaturalTS, options) {
|
|
28862
29163
|
// 这里需要调用实际的编译服务接口
|
|
28863
29164
|
// 示例实现:
|
|
28864
|
-
const axios = createAxios(options
|
|
29165
|
+
const axios = await createAxios(options);
|
|
28865
29166
|
const res = await axios.post(`/compile/tsx?ideVersion=${options.ideVersion}&needAnnotation=true`, fullNaturalTS, {
|
|
28866
29167
|
headers: { 'Content-Type': 'text/plain' },
|
|
28867
29168
|
});
|
|
28868
29169
|
const data = res.data;
|
|
28869
|
-
if (data.code !== 200)
|
|
28870
|
-
throw new Error(data.message);
|
|
28871
29170
|
const { bundle } = data.result;
|
|
28872
29171
|
const fileMap = bundle.frontendBundle.files;
|
|
28873
29172
|
const files = Object.keys(fileMap).map((key) => {
|
|
@@ -28895,7 +29194,7 @@ window.backendApp = app;
|
|
|
28895
29194
|
* TODO: 实现具体的 API 调用逻辑
|
|
28896
29195
|
*/
|
|
28897
29196
|
async function checkApi(fullNaturalTS, options) {
|
|
28898
|
-
const axios = createAxios(options
|
|
29197
|
+
const axios = await createAxios(options);
|
|
28899
29198
|
const res = await axios.post(`/check/tsx?ideVersion=${options.ideVersion}`, fullNaturalTS, {
|
|
28900
29199
|
headers: { 'Content-Type': 'text/plain' },
|
|
28901
29200
|
});
|
|
@@ -28913,7 +29212,7 @@ async function checkApi(fullNaturalTS, options) {
|
|
|
28913
29212
|
async function createAppSyncApi(fullNaturalTS, options) {
|
|
28914
29213
|
const url = new URL(options.serverBaseURL);
|
|
28915
29214
|
const origin = url.origin + '/app-ai-creator';
|
|
28916
|
-
const axios = createAxios(origin);
|
|
29215
|
+
const axios = await createAxios({ serverBaseURL: origin, ideVersion: options.ideVersion });
|
|
28917
29216
|
try {
|
|
28918
29217
|
const res = await axios.post('/api/createAppSync', {
|
|
28919
29218
|
fullNaturalTS,
|
|
@@ -37796,10 +38095,7 @@ async function compile(entry, options) {
|
|
|
37796
38095
|
logger.info('正在调用编译服务...');
|
|
37797
38096
|
try {
|
|
37798
38097
|
const fullNaturalTS = composeToString(collectedFiles);
|
|
37799
|
-
const outputFiles = await compileApi(fullNaturalTS,
|
|
37800
|
-
serverBaseURL: config.serverBaseURL,
|
|
37801
|
-
ideVersion: config.ideVersion,
|
|
37802
|
-
});
|
|
38098
|
+
const outputFiles = await compileApi(fullNaturalTS, config);
|
|
37803
38099
|
logger.success('编译成功!');
|
|
37804
38100
|
// 写入输出文件
|
|
37805
38101
|
for (const file of outputFiles) {
|
|
@@ -37846,10 +38142,7 @@ async function check(entry, options) {
|
|
|
37846
38142
|
result = error.message.trim();
|
|
37847
38143
|
}
|
|
37848
38144
|
if (!result && fullNaturalTS) {
|
|
37849
|
-
result = (await checkApi(fullNaturalTS,
|
|
37850
|
-
serverBaseURL: config.serverBaseURL,
|
|
37851
|
-
ideVersion: config.ideVersion,
|
|
37852
|
-
})).trim();
|
|
38145
|
+
result = (await checkApi(fullNaturalTS, config)).trim();
|
|
37853
38146
|
}
|
|
37854
38147
|
const checkResult = {
|
|
37855
38148
|
success: !result,
|
|
@@ -38128,6 +38421,10 @@ async function createAppInIde(entry, options) {
|
|
|
38128
38421
|
logger.info('开始创建应用在 IDE 中...');
|
|
38129
38422
|
// 收集需要处理的文件
|
|
38130
38423
|
const { collectedFiles, config } = await resolveNASLFiles(entry, logger, false, options?.verbose);
|
|
38424
|
+
if (config.useOPENAPI) {
|
|
38425
|
+
logger.error('create-app-in-ide 暂不支持 useOPENAPI 模式');
|
|
38426
|
+
logger.exit(1);
|
|
38427
|
+
}
|
|
38131
38428
|
// 生成 fullNaturalTS
|
|
38132
38429
|
logger.newLine();
|
|
38133
38430
|
logger.info('正在生成 NaturalTS 代码...');
|
|
@@ -38189,15 +38486,13 @@ async function createAppInIde(entry, options) {
|
|
|
38189
38486
|
* 编译 NASL 代码
|
|
38190
38487
|
* TODO: 实现具体的 API 调用逻辑
|
|
38191
38488
|
*/
|
|
38192
|
-
async function transformJson2FilesApi(
|
|
38489
|
+
async function transformJson2FilesApi(json, options) {
|
|
38193
38490
|
// 示例实现:
|
|
38194
|
-
const axios = createAxios(options
|
|
38195
|
-
const res = await axios.post(`/transform/json2files?ideVersion=${options.ideVersion}`,
|
|
38196
|
-
headers: { 'Content-Type': '
|
|
38491
|
+
const axios = await createAxios(options);
|
|
38492
|
+
const res = await axios.post(`/transform/json2files?ideVersion=${options.ideVersion}`, json, {
|
|
38493
|
+
headers: { 'Content-Type': 'application/json' },
|
|
38197
38494
|
});
|
|
38198
38495
|
const data = res.data;
|
|
38199
|
-
if (data.code !== 200)
|
|
38200
|
-
throw new Error(data.message);
|
|
38201
38496
|
return data.result;
|
|
38202
38497
|
}
|
|
38203
38498
|
|
|
@@ -38237,17 +38532,19 @@ const transformFns = {
|
|
|
38237
38532
|
const projectRoot = getProjectRoot();
|
|
38238
38533
|
logger.info(`项目根目录: ${projectRoot}`);
|
|
38239
38534
|
logger.info(`源代码目录: ${config.srcDir}`);
|
|
38535
|
+
if (!libExports.existsSync(config.srcDir)) {
|
|
38536
|
+
logger.error(`当前目录下 ${config.srcDir} 目录不存在,请先创建`);
|
|
38537
|
+
logger.exit(1);
|
|
38538
|
+
}
|
|
38240
38539
|
let jsonContent = '';
|
|
38241
38540
|
if (!entry) {
|
|
38242
38541
|
logger.warn('没有指定 JSON 文件路径,按照默认 IDE 版本的基础模板转换');
|
|
38243
38542
|
}
|
|
38244
38543
|
else {
|
|
38245
38544
|
jsonContent = libExports.readFileSync(entry, 'utf-8');
|
|
38545
|
+
logger.info(`读取到 JSON 文件: ${entry}`);
|
|
38246
38546
|
}
|
|
38247
|
-
const files = await transformJson2FilesApi(jsonContent,
|
|
38248
|
-
serverBaseURL: config.serverBaseURL,
|
|
38249
|
-
ideVersion: config.ideVersion,
|
|
38250
|
-
});
|
|
38547
|
+
const files = await transformJson2FilesApi(jsonContent ? JSON.parse(jsonContent) : {}, config);
|
|
38251
38548
|
await Promise.all(files.map(async (file) => {
|
|
38252
38549
|
const outputPath = sysPath.join(projectRoot, config.srcDir, file.path);
|
|
38253
38550
|
await libExports.writeFile(outputPath, file.content);
|
|
@@ -38276,7 +38573,7 @@ async function transform(transformType, entry, options) {
|
|
|
38276
38573
|
await transformFn(entry, options);
|
|
38277
38574
|
}
|
|
38278
38575
|
|
|
38279
|
-
var version = "0.1.
|
|
38576
|
+
var version = "0.1.18";
|
|
38280
38577
|
var pkg = {
|
|
38281
38578
|
version: version};
|
|
38282
38579
|
|
|
@@ -38385,8 +38682,8 @@ program
|
|
|
38385
38682
|
// 如果不是 quiet 模式,询问用户确认
|
|
38386
38683
|
if (!options?.quiet) {
|
|
38387
38684
|
defaultLogger.newLine();
|
|
38388
|
-
defaultLogger.info('即将在 IDE
|
|
38389
|
-
const confirmed = await askForConfirmation('
|
|
38685
|
+
defaultLogger.info('即将在 IDE 中创建新的应用,此操作将调用远程接口。');
|
|
38686
|
+
const confirmed = await askForConfirmation('请确认是否继续?(y/N): ');
|
|
38390
38687
|
if (!confirmed) {
|
|
38391
38688
|
defaultLogger.info('已取消操作');
|
|
38392
38689
|
process.exit(0);
|
|
@@ -38402,7 +38699,7 @@ program
|
|
|
38402
38699
|
});
|
|
38403
38700
|
program
|
|
38404
38701
|
.command('transform <transformType> [entry]')
|
|
38405
|
-
.description('转换文件格式\n transformType: files2full (将 src 文件组合成 fullNaturalTS), json2files (将 JSON
|
|
38702
|
+
.description('转换文件格式\n transformType: files2full (将 src 文件组合成 fullNaturalTS), json2files (将 JSON 转换为文件), files2json (将 src 文件转换为 JSON)')
|
|
38406
38703
|
.option('-o, --output <outputPath>', '指定输出路径')
|
|
38407
38704
|
.option('-v, --verbose', '显示详细信息,如依赖分析树')
|
|
38408
38705
|
.action(async (transformType, entry, options) => {
|
|
@@ -38580,7 +38877,7 @@ class ReaddirpStream extends Readable$1 {
|
|
|
38580
38877
|
let entry;
|
|
38581
38878
|
const basename = this._isDirent ? dirent.name : dirent;
|
|
38582
38879
|
try {
|
|
38583
|
-
const fullPath = resolve(join(path, basename));
|
|
38880
|
+
const fullPath = resolve(join$1(path, basename));
|
|
38584
38881
|
entry = { path: relative(this._root, fullPath), fullPath, basename };
|
|
38585
38882
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
38586
38883
|
}
|