dsh-cloudq 0.2.1 → 0.3.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/lib/client.js +1 -1
- package/lib/index.js +235 -189
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -3385,7 +3385,7 @@ display: none;
|
|
|
3385
3385
|
});
|
|
3386
3386
|
} catch (error) {
|
|
3387
3387
|
setValidated(false);
|
|
3388
|
-
const invalid = error instanceof CloudQApiError && error.code !== "network-error" && error.code !== "invalid-response"
|
|
3388
|
+
const invalid = error instanceof CloudQApiError && error.code !== "network-error" && error.code !== "invalid-response";
|
|
3389
3389
|
setFeedback({
|
|
3390
3390
|
kind: "error",
|
|
3391
3391
|
text: invalid ? "AKSK 无效,请检查后重新配置。" : error.message
|
package/lib/index.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { spawn
|
|
3
|
-
import { existsSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
|
-
import { get } from "node:https";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { get, request } from "node:https";
|
|
5
5
|
import { dirname, join, resolve } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import Schema from "@deepseek-ai/schemastery";
|
|
8
|
-
import { Buffer
|
|
8
|
+
import { Buffer } from "node:buffer";
|
|
9
9
|
import yaml from "js-yaml";
|
|
10
|
+
import { createHash, createHmac } from "node:crypto";
|
|
11
|
+
import { homedir } from "node:os";
|
|
10
12
|
//#region src/http.js
|
|
11
13
|
/** Maximum accepted JSON request body size. */
|
|
12
14
|
const MAX_JSON_BODY_BYTES = 65536;
|
|
@@ -115,7 +117,7 @@ function readJsonBody(request, { maxBytes = MAX_JSON_BODY_BYTES } = {}) {
|
|
|
115
117
|
};
|
|
116
118
|
request.on("data", (chunk) => {
|
|
117
119
|
if (settled) return;
|
|
118
|
-
const buffer = Buffer
|
|
120
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
119
121
|
bytes += buffer.byteLength;
|
|
120
122
|
if (bytes > maxBytes) {
|
|
121
123
|
rejectOnce(new HttpError(413, "payload-too-large", "The JSON request body is too large."));
|
|
@@ -131,7 +133,7 @@ function readJsonBody(request, { maxBytes = MAX_JSON_BODY_BYTES } = {}) {
|
|
|
131
133
|
return;
|
|
132
134
|
}
|
|
133
135
|
try {
|
|
134
|
-
resolveBody(JSON.parse(Buffer
|
|
136
|
+
resolveBody(JSON.parse(Buffer.concat(chunks).toString("utf8")));
|
|
135
137
|
} catch {
|
|
136
138
|
rejectBody(new HttpError(400, "invalid-json", "The request body is not valid JSON."));
|
|
137
139
|
}
|
|
@@ -288,118 +290,157 @@ function setPluginDisabled(baseUrl, id, disabled) {
|
|
|
288
290
|
};
|
|
289
291
|
}
|
|
290
292
|
//#endregion
|
|
291
|
-
//#region src/
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
return "
|
|
293
|
+
//#region src/tcloud.js
|
|
294
|
+
/**
|
|
295
|
+
* Node-native Tencent Cloud API client (TC3-HMAC-SHA256) and credential
|
|
296
|
+
* store for the dsh-cloudq host.
|
|
297
|
+
*
|
|
298
|
+
* The DSH host itself runs on Node, so — same as dsh-cos — every panel API
|
|
299
|
+
* call happens in-process with zero external runtime dependency. Python only
|
|
300
|
+
* remains for the agent-driven skill conversation flow.
|
|
301
|
+
*
|
|
302
|
+
* @module dsh-cloudq/tcloud
|
|
303
|
+
*/
|
|
304
|
+
const CREDENTIAL_FILE = join(homedir(), ".tencent-cloudq", "credential.json");
|
|
305
|
+
const sha256 = (value) => createHash("sha256").update(value, "utf8").digest("hex");
|
|
306
|
+
const hmacSha256 = (key, value) => createHmac("sha256", key).update(value, "utf8").digest();
|
|
307
|
+
const hmacSha256Hex = (key, value) => createHmac("sha256", key).update(value, "utf8").digest("hex");
|
|
308
|
+
/** Mask a SecretId exactly like the Python helpers: keep only the last 4. */
|
|
309
|
+
function maskSecretId(value) {
|
|
310
|
+
const text = String(value ?? "");
|
|
311
|
+
return text.length <= 4 ? "*".repeat(text.length) : "*".repeat(text.length - 4) + text.slice(-4);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Read the stored credential shared with the CloudQ skill.
|
|
315
|
+
* Only the AK/SK entries (`type: "ak"`, optional STS token) can TC3-sign;
|
|
316
|
+
* OAuth/Connector entries carry no SecretKey and surface as NeedAuth.
|
|
317
|
+
*/
|
|
318
|
+
function readCredential() {
|
|
319
|
+
let data;
|
|
320
|
+
try {
|
|
321
|
+
data = JSON.parse(readFileSync(CREDENTIAL_FILE, "utf8"));
|
|
322
|
+
} catch {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
const secretId = typeof data?.secretId === "string" ? data.secretId : "";
|
|
326
|
+
const secretKey = typeof data?.secretKey === "string" ? data.secretKey : "";
|
|
327
|
+
if (!secretId || !secretKey) return null;
|
|
328
|
+
return {
|
|
329
|
+
secretId,
|
|
330
|
+
secretKey,
|
|
331
|
+
token: typeof data?.token === "string" ? data.token : "",
|
|
332
|
+
authType: typeof data?.type === "string" ? data.type : "ak"
|
|
333
|
+
};
|
|
310
334
|
}
|
|
311
|
-
|
|
312
|
-
|
|
335
|
+
/** Credential state for the settings UI (never exposes the SecretKey). */
|
|
336
|
+
function credentialStatus$1() {
|
|
337
|
+
const credential = readCredential();
|
|
338
|
+
if (!credential) return { logged_in: false };
|
|
339
|
+
return {
|
|
340
|
+
logged_in: true,
|
|
341
|
+
secret_id_masked: maskSecretId(credential.secretId),
|
|
342
|
+
auth_type: credential.authType
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
/** Persist an AK/SK pair atomically, mirroring credential_manager (dir 700, file 600). */
|
|
346
|
+
function saveCredential(secretId, secretKey) {
|
|
347
|
+
const data = {
|
|
348
|
+
type: "ak",
|
|
349
|
+
secretId,
|
|
350
|
+
secretKey,
|
|
351
|
+
token: "",
|
|
352
|
+
expiresAt: 0,
|
|
353
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
354
|
+
};
|
|
355
|
+
const directory = dirname(CREDENTIAL_FILE);
|
|
356
|
+
mkdirSync(directory, { recursive: true });
|
|
357
|
+
const temporary = `${CREDENTIAL_FILE}.tmp-${process.pid}`;
|
|
358
|
+
writeFileSync(temporary, JSON.stringify(data, null, 2), {
|
|
359
|
+
encoding: "utf8",
|
|
360
|
+
mode: 384
|
|
361
|
+
});
|
|
362
|
+
renameSync(temporary, CREDENTIAL_FILE);
|
|
363
|
+
if (process.platform !== "win32") try {
|
|
364
|
+
chmodSync(directory, 448);
|
|
365
|
+
chmodSync(CREDENTIAL_FILE, 384);
|
|
366
|
+
} catch {}
|
|
313
367
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
368
|
+
/** Remove the stored credential (退出登录). */
|
|
369
|
+
function deleteCredential() {
|
|
370
|
+
try {
|
|
371
|
+
unlinkSync(CREDENTIAL_FILE);
|
|
372
|
+
} catch {}
|
|
318
373
|
}
|
|
319
374
|
/**
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
* @param {object} options Execution options.
|
|
325
|
-
* @returns {Promise<Record<string, unknown>>} Parsed helper response.
|
|
375
|
+
* Call a Tencent Cloud API with TC3-HMAC-SHA256 signing.
|
|
376
|
+
* Returns the unwrapped `Response` payload; API errors become HttpError with
|
|
377
|
+
* the upstream code (AuthFailure.* etc.) so callers can map them like the
|
|
378
|
+
* Python helpers did.
|
|
326
379
|
*/
|
|
327
|
-
function
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
})
|
|
368
|
-
|
|
369
|
-
|
|
380
|
+
async function callTcloudApi({ service, host, action, version, payload = {} }, credential = readCredential()) {
|
|
381
|
+
if (!credential) throw new HttpError(401, "NeedAuth", "尚未配置 AK/SK,请前往「设置 → 插件 → CloudQ」完成配置。");
|
|
382
|
+
const body = JSON.stringify(payload);
|
|
383
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
384
|
+
const date = (/* @__PURE__ */ new Date(timestamp * 1e3)).toISOString().slice(0, 10);
|
|
385
|
+
const canonicalRequest = [
|
|
386
|
+
"POST",
|
|
387
|
+
"/",
|
|
388
|
+
"",
|
|
389
|
+
`content-type:application/json\nhost:${host}\nx-tc-action:${action.toLowerCase()}`,
|
|
390
|
+
"",
|
|
391
|
+
"content-type;host;x-tc-action",
|
|
392
|
+
sha256(body)
|
|
393
|
+
].join("\n");
|
|
394
|
+
const stringToSign = [
|
|
395
|
+
"TC3-HMAC-SHA256",
|
|
396
|
+
String(timestamp),
|
|
397
|
+
`${date}/${service}/tc3_request`,
|
|
398
|
+
sha256(canonicalRequest)
|
|
399
|
+
].join("\n");
|
|
400
|
+
const keyDate = hmacSha256(`TC3${credential.secretKey}`, date);
|
|
401
|
+
const keyService = hmacSha256(keyDate, service);
|
|
402
|
+
const keySigning = hmacSha256(keyService, "tc3_request");
|
|
403
|
+
const signature = hmacSha256Hex(keySigning, stringToSign);
|
|
404
|
+
const authorization = `TC3-HMAC-SHA256 Credential=${credential.secretId}/${date}/${service}/tc3_request, SignedHeaders=content-type;host;x-tc-action, Signature=${signature}`;
|
|
405
|
+
const headers = {
|
|
406
|
+
"Content-Type": "application/json",
|
|
407
|
+
"X-TC-Action": action,
|
|
408
|
+
"X-TC-Version": version,
|
|
409
|
+
"X-TC-Timestamp": String(timestamp),
|
|
410
|
+
Authorization: authorization
|
|
411
|
+
};
|
|
412
|
+
if (credential.token) headers["X-TC-Token"] = credential.token;
|
|
413
|
+
const text = await new Promise((resolveRequest, rejectRequest) => {
|
|
414
|
+
const request$1 = request({
|
|
415
|
+
host,
|
|
416
|
+
path: "/",
|
|
417
|
+
method: "POST",
|
|
418
|
+
headers,
|
|
419
|
+
timeout: 3e4
|
|
420
|
+
}, (response) => {
|
|
421
|
+
let bodyText = "";
|
|
422
|
+
response.on("data", (chunk) => {
|
|
423
|
+
bodyText += chunk;
|
|
424
|
+
if (bodyText.length > 1048576) request$1.destroy();
|
|
425
|
+
});
|
|
426
|
+
response.on("end", () => resolveRequest(bodyText));
|
|
370
427
|
});
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if (code !== 0) rejectOnce(new HttpError(502, "script-failed", "The CloudQ helper failed."));
|
|
376
|
-
else resolveOnce({
|
|
377
|
-
success: true,
|
|
378
|
-
message: redact(trimmed, sensitiveValues)
|
|
379
|
-
});
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
let parsed;
|
|
383
|
-
try {
|
|
384
|
-
parsed = trimmed ? JSON.parse(trimmed) : {};
|
|
385
|
-
} catch {
|
|
386
|
-
rejectOnce(new HttpError(502, "script-invalid-output", "The CloudQ helper returned an invalid response."));
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
if (code !== 0 || parsed?.ok === false || parsed?.success === false) {
|
|
390
|
-
const codeValue = safeCode(parsed?.error?.code ?? parsed?.code);
|
|
391
|
-
rejectOnce(new HttpError(502, codeValue, "The CloudQ helper failed."));
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
resolveOnce(parsed);
|
|
428
|
+
request$1.on("error", () => rejectRequest(new HttpError(502, "network-error", "无法连接腾讯云服务,请检查网络后重试。")));
|
|
429
|
+
request$1.on("timeout", () => {
|
|
430
|
+
request$1.destroy();
|
|
431
|
+
rejectRequest(new HttpError(504, "network-timeout", "腾讯云服务响应超时,请稍后重试。"));
|
|
395
432
|
});
|
|
396
|
-
|
|
397
|
-
child.stdin.on("error", () => {
|
|
398
|
-
rejectOnce(new HttpError(502, "script-input-failed", "The CloudQ helper could not receive its input."));
|
|
399
|
-
});
|
|
400
|
-
child.stdin.end(stdin);
|
|
401
|
-
}
|
|
433
|
+
request$1.end(body);
|
|
402
434
|
});
|
|
435
|
+
let parsed;
|
|
436
|
+
try {
|
|
437
|
+
parsed = JSON.parse(text);
|
|
438
|
+
} catch {
|
|
439
|
+
throw new HttpError(502, "invalid-response", "腾讯云服务返回了无法识别的响应。");
|
|
440
|
+
}
|
|
441
|
+
const envelope = parsed?.Response ?? {};
|
|
442
|
+
if (envelope.Error) throw new HttpError(502, String(envelope.Error.Code ?? "api-error"), String(envelope.Error.Message ?? "腾讯云接口调用失败。"));
|
|
443
|
+
return envelope;
|
|
403
444
|
}
|
|
404
445
|
//#endregion
|
|
405
446
|
//#region src/index.js
|
|
@@ -554,119 +595,124 @@ function renderedSkillContent() {
|
|
|
554
595
|
const baseDir = skillDirectory();
|
|
555
596
|
return rawSkillContent().replace(/\{baseDir\}/g, baseDir);
|
|
556
597
|
}
|
|
557
|
-
/**
|
|
558
|
-
|
|
598
|
+
/** Map upstream TC error codes to stable, actionable client-facing errors. */
|
|
599
|
+
function normalizeApiError(error) {
|
|
600
|
+
if (error instanceof HttpError) {
|
|
601
|
+
if (error.code === "NeedAuth") throw error;
|
|
602
|
+
if (typeof error.code === "string" && error.code.startsWith("AuthFailure")) throw new HttpError(401, "AuthFailure", "AK/SK 无效或权限不足,请前往「设置 → 插件 → CloudQ」检查配置。");
|
|
603
|
+
}
|
|
604
|
+
throw error;
|
|
605
|
+
}
|
|
606
|
+
/** Wrap one API call with the credential-error mapping. */
|
|
607
|
+
async function callCloudq(spec) {
|
|
559
608
|
try {
|
|
560
|
-
return await
|
|
609
|
+
return { data: await callTcloudApi(spec) };
|
|
561
610
|
} catch (error) {
|
|
562
|
-
|
|
563
|
-
if (error.code === "NeedAuth") throw new HttpError(401, "NeedAuth", "尚未配置 AK/SK,请前往「设置 → 插件 → CloudQ」完成配置。");
|
|
564
|
-
if (error.code === "CredentialExpired") throw new HttpError(401, "CredentialExpired", "凭证已过期,请前往「设置 → 插件 → CloudQ」重新配置。");
|
|
565
|
-
if (typeof error.code === "string" && error.code.startsWith("AuthFailure")) throw new HttpError(401, "AuthFailure", "AK/SK 无效或权限不足,请前往「设置 → 插件 → CloudQ」检查配置。");
|
|
566
|
-
}
|
|
611
|
+
normalizeApiError(error);
|
|
567
612
|
throw error;
|
|
568
613
|
}
|
|
569
614
|
}
|
|
570
|
-
/**
|
|
571
|
-
function
|
|
572
|
-
|
|
573
|
-
const safeStatus = { ...status };
|
|
574
|
-
delete safeStatus.credential_file;
|
|
575
|
-
return safeStatus;
|
|
576
|
-
}
|
|
577
|
-
/** Wrap runScript so failures keep a stable envelope for the client. */
|
|
578
|
-
async function credentialStatus() {
|
|
579
|
-
return publicCredentialStatus(await runScript("login.py", ["--status"]));
|
|
615
|
+
/** Credential state for the settings UI (never exposes the SecretKey). */
|
|
616
|
+
function credentialStatus() {
|
|
617
|
+
return credentialStatus$1();
|
|
580
618
|
}
|
|
581
619
|
function logout() {
|
|
582
|
-
|
|
620
|
+
deleteCredential();
|
|
621
|
+
return { message: "已退出登录。" };
|
|
583
622
|
}
|
|
584
623
|
/**
|
|
585
624
|
* Validate a long-lived Tencent Cloud AK/SK pair without persisting it.
|
|
586
|
-
*
|
|
625
|
+
* DescribeCloudQUsageOverview is read-only, parameterless, and CloudQ's own
|
|
626
|
+
* API — a successful call proves both the key and the CloudQ enrollment.
|
|
587
627
|
*/
|
|
588
|
-
function testAccessKey(secretId, secretKey) {
|
|
589
|
-
|
|
590
|
-
|
|
628
|
+
async function testAccessKey(secretId, secretKey) {
|
|
629
|
+
try {
|
|
630
|
+
await callTcloudApi({
|
|
631
|
+
service: "advisor",
|
|
632
|
+
host: "advisor.tencentcloudapi.com",
|
|
633
|
+
action: "DescribeCloudQUsageOverview",
|
|
634
|
+
version: "2020-07-21"
|
|
635
|
+
}, {
|
|
591
636
|
secretId,
|
|
592
|
-
secretKey
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
637
|
+
secretKey,
|
|
638
|
+
token: ""
|
|
639
|
+
});
|
|
640
|
+
return {
|
|
641
|
+
valid: true,
|
|
642
|
+
secret_id_masked: maskSecretId(secretId)
|
|
643
|
+
};
|
|
644
|
+
} catch (error) {
|
|
645
|
+
normalizeApiError(error);
|
|
646
|
+
throw error;
|
|
647
|
+
}
|
|
596
648
|
}
|
|
597
649
|
/** Validate then persist a long-lived AK/SK pair as `type:"ak"`. */
|
|
598
650
|
async function saveAccessKey(secretId, secretKey) {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
secretKey
|
|
603
|
-
}),
|
|
604
|
-
sensitiveValues: [secretId, secretKey]
|
|
605
|
-
}));
|
|
651
|
+
await testAccessKey(secretId, secretKey);
|
|
652
|
+
saveCredential(secretId, secretKey);
|
|
653
|
+
return credentialStatus$1();
|
|
606
654
|
}
|
|
607
655
|
function cloudqUsageOverview() {
|
|
608
|
-
return
|
|
609
|
-
"advisor",
|
|
610
|
-
"advisor.tencentcloudapi.com",
|
|
611
|
-
"DescribeCloudQUsageOverview",
|
|
612
|
-
"2020-07-21"
|
|
613
|
-
|
|
614
|
-
]);
|
|
656
|
+
return callCloudq({
|
|
657
|
+
service: "advisor",
|
|
658
|
+
host: "advisor.tencentcloudapi.com",
|
|
659
|
+
action: "DescribeCloudQUsageOverview",
|
|
660
|
+
version: "2020-07-21"
|
|
661
|
+
});
|
|
615
662
|
}
|
|
616
663
|
function cloudqUsageDetail({ startTime, endTime, limit = 20, offset = 0 }) {
|
|
617
|
-
return
|
|
618
|
-
"advisor",
|
|
619
|
-
"advisor.tencentcloudapi.com",
|
|
620
|
-
"DescribeCloudQUsageDetail",
|
|
621
|
-
"2020-07-21",
|
|
622
|
-
|
|
664
|
+
return callCloudq({
|
|
665
|
+
service: "advisor",
|
|
666
|
+
host: "advisor.tencentcloudapi.com",
|
|
667
|
+
action: "DescribeCloudQUsageDetail",
|
|
668
|
+
version: "2020-07-21",
|
|
669
|
+
payload: {
|
|
623
670
|
StartTime: startTime,
|
|
624
671
|
EndTime: endTime,
|
|
625
672
|
Limit: limit,
|
|
626
673
|
Offset: offset
|
|
627
|
-
}
|
|
628
|
-
|
|
674
|
+
}
|
|
675
|
+
});
|
|
629
676
|
}
|
|
630
677
|
function cloudqInspirationList() {
|
|
631
|
-
return
|
|
632
|
-
"advisor",
|
|
633
|
-
"advisor.tencentcloudapi.com",
|
|
634
|
-
"DescribeCloudQInspirationList",
|
|
635
|
-
"2020-07-21",
|
|
636
|
-
|
|
637
|
-
|
|
678
|
+
return callCloudq({
|
|
679
|
+
service: "advisor",
|
|
680
|
+
host: "advisor.tencentcloudapi.com",
|
|
681
|
+
action: "DescribeCloudQInspirationList",
|
|
682
|
+
version: "2020-07-21",
|
|
683
|
+
payload: { Category: 0 }
|
|
684
|
+
});
|
|
638
685
|
}
|
|
639
686
|
/** Fetch all CloudQ artifact sessions and their archived files. */
|
|
640
687
|
function cloudqArtifactLibrary() {
|
|
641
|
-
return
|
|
642
|
-
"advisor",
|
|
643
|
-
"advisor.tencentcloudapi.com",
|
|
644
|
-
"DescribeCloudQArtifactLibrary",
|
|
645
|
-
"2020-07-21"
|
|
646
|
-
|
|
647
|
-
]);
|
|
688
|
+
return callCloudq({
|
|
689
|
+
service: "advisor",
|
|
690
|
+
host: "advisor.tencentcloudapi.com",
|
|
691
|
+
action: "DescribeCloudQArtifactLibrary",
|
|
692
|
+
version: "2020-07-21"
|
|
693
|
+
});
|
|
648
694
|
}
|
|
649
695
|
/** Fetch the architecture directory tree available to the current account. */
|
|
650
696
|
function cloudqArchitectureDirectories() {
|
|
651
|
-
return
|
|
652
|
-
"advisor",
|
|
653
|
-
"advisor.tencentcloudapi.com",
|
|
654
|
-
"ListDirectoryV2",
|
|
655
|
-
"2020-07-21",
|
|
656
|
-
|
|
697
|
+
return callCloudq({
|
|
698
|
+
service: "advisor",
|
|
699
|
+
host: "advisor.tencentcloudapi.com",
|
|
700
|
+
action: "ListDirectoryV2",
|
|
701
|
+
version: "2020-07-21",
|
|
702
|
+
payload: {
|
|
657
703
|
Tags: [],
|
|
658
704
|
TagKeys: []
|
|
659
|
-
}
|
|
660
|
-
|
|
705
|
+
}
|
|
706
|
+
});
|
|
661
707
|
}
|
|
662
708
|
/** Fetch one page of diagrams in a CloudQ architecture directory. */
|
|
663
709
|
function cloudqArchitectureList({ folderId, pageNumber = 1, pageSize = 30 }) {
|
|
664
|
-
return
|
|
665
|
-
"advisor",
|
|
666
|
-
"advisor.tencentcloudapi.com",
|
|
667
|
-
"DescribeArchList",
|
|
668
|
-
"2020-07-21",
|
|
669
|
-
|
|
710
|
+
return callCloudq({
|
|
711
|
+
service: "advisor",
|
|
712
|
+
host: "advisor.tencentcloudapi.com",
|
|
713
|
+
action: "DescribeArchList",
|
|
714
|
+
version: "2020-07-21",
|
|
715
|
+
payload: {
|
|
670
716
|
PageNumber: pageNumber,
|
|
671
717
|
PageSize: pageSize,
|
|
672
718
|
SearchKey: "",
|
|
@@ -674,8 +720,8 @@ function cloudqArchitectureList({ folderId, pageNumber = 1, pageSize = 30 }) {
|
|
|
674
720
|
WithSvgURL: true,
|
|
675
721
|
Tags: [],
|
|
676
722
|
TagKeys: []
|
|
677
|
-
}
|
|
678
|
-
|
|
723
|
+
}
|
|
724
|
+
});
|
|
679
725
|
}
|
|
680
726
|
/**
|
|
681
727
|
* Extract and validate an AK/SK pair from a request body.
|