bukesiyi-cli 0.1.2 → 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/README.md +24 -13
- package/dist/main.js +1860 -97
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -49,11 +49,13 @@ var EXIT = {
|
|
|
49
49
|
NOT_FOUND: 10,
|
|
50
50
|
INTERRUPTED: 130
|
|
51
51
|
};
|
|
52
|
-
function exitCodeForHttpStatus(
|
|
53
|
-
if (
|
|
54
|
-
if (
|
|
55
|
-
if (
|
|
56
|
-
if (
|
|
52
|
+
function exitCodeForHttpStatus(status4) {
|
|
53
|
+
if (status4 === 401 || status4 === 403) return EXIT.AUTH;
|
|
54
|
+
if (status4 === 402) return EXIT.FUNDS;
|
|
55
|
+
if (status4 === 404) return EXIT.NOT_FOUND;
|
|
56
|
+
if (status4 === 409) return EXIT.QUOTE_CHANGED;
|
|
57
|
+
if (status4 === 429) return EXIT.RETRY_LATER;
|
|
58
|
+
if (status4 >= 400 && status4 < 500) return EXIT.USAGE;
|
|
57
59
|
return EXIT.SERVER;
|
|
58
60
|
}
|
|
59
61
|
|
|
@@ -111,11 +113,11 @@ var CliError = class _CliError extends Error {
|
|
|
111
113
|
});
|
|
112
114
|
}
|
|
113
115
|
};
|
|
114
|
-
function usageError(
|
|
115
|
-
return new CliError({ code: "CLI_USAGE", exitCode: EXIT.USAGE, message: `${
|
|
116
|
+
function usageError(message2) {
|
|
117
|
+
return new CliError({ code: "CLI_USAGE", exitCode: EXIT.USAGE, message: `${message2}\u3002\u8FD0\u884C buke --help \u770B\u7528\u6CD5` });
|
|
116
118
|
}
|
|
117
|
-
function interruptedError(
|
|
118
|
-
return new CliError({ code: "CLI_INTERRUPTED", exitCode: EXIT.INTERRUPTED, message });
|
|
119
|
+
function interruptedError(message2 = "\u5DF2\u4E2D\u65AD") {
|
|
120
|
+
return new CliError({ code: "CLI_INTERRUPTED", exitCode: EXIT.INTERRUPTED, message: message2 });
|
|
119
121
|
}
|
|
120
122
|
function isRecord(value) {
|
|
121
123
|
return typeof value === "object" && value !== null;
|
|
@@ -215,8 +217,8 @@ function malformedKey() {
|
|
|
215
217
|
message: "\u8FD9\u4E0D\u50CF\u4E00\u628A API \u5BC6\u94A5\uFF1A\u5E94\u4EE5 bk_ \u5F00\u5934\uFF0C\u4E2D\u95F4\u6CA1\u6709\u7A7A\u683C\u6216\u6362\u884C"
|
|
216
218
|
});
|
|
217
219
|
}
|
|
218
|
-
function missingKey(
|
|
219
|
-
return new CliError({ code: "CLI_KEY_MISSING", exitCode: EXIT.USAGE, message });
|
|
220
|
+
function missingKey(message2) {
|
|
221
|
+
return new CliError({ code: "CLI_KEY_MISSING", exitCode: EXIT.USAGE, message: message2 });
|
|
220
222
|
}
|
|
221
223
|
var NO_KEY_READ = "\u6CA1\u6709\u8BFB\u5230\u5BC6\u94A5\u3002\u8BF7\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF BUKE_API_KEY\uFF0C\u6216\u8005\u901A\u8FC7\u7BA1\u9053\u628A\u5BC6\u94A5\u4F20\u7ED9 buke login";
|
|
222
224
|
function assertKeyFormat(key) {
|
|
@@ -239,10 +241,10 @@ function toBuffer(chunk) {
|
|
|
239
241
|
return Buffer.from(chunk);
|
|
240
242
|
}
|
|
241
243
|
function readToEnd(stdin, timeoutMs, signal) {
|
|
242
|
-
return new Promise((
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
243
245
|
const state = stdin;
|
|
244
246
|
if (state.readableEnded === true || state.destroyed === true) {
|
|
245
|
-
|
|
247
|
+
resolve("");
|
|
246
248
|
return;
|
|
247
249
|
}
|
|
248
250
|
const chunks = [];
|
|
@@ -270,7 +272,7 @@ function readToEnd(stdin, timeoutMs, signal) {
|
|
|
270
272
|
}
|
|
271
273
|
chunks.push(piece);
|
|
272
274
|
};
|
|
273
|
-
const onEnd = () => settle(() =>
|
|
275
|
+
const onEnd = () => settle(() => resolve(Buffer.concat(chunks).toString("utf8").trim()));
|
|
274
276
|
const onError = (error) => settle(() => reject(missingKey(`\u6CA1\u6709\u8BFB\u5230\u5BC6\u94A5\uFF1A\u6807\u51C6\u8F93\u5165\u51FA\u9519\uFF08${briefReason(error)}\uFF09`)));
|
|
275
277
|
const timer = setTimeout(() => {
|
|
276
278
|
settle(
|
|
@@ -290,7 +292,7 @@ function readToEnd(stdin, timeoutMs, signal) {
|
|
|
290
292
|
});
|
|
291
293
|
}
|
|
292
294
|
function readHiddenLine(stdin, signal) {
|
|
293
|
-
return new Promise((
|
|
295
|
+
return new Promise((resolve, reject) => {
|
|
294
296
|
let typed = "";
|
|
295
297
|
let escape = "none";
|
|
296
298
|
let settled = false;
|
|
@@ -321,7 +323,7 @@ function readHiddenLine(stdin, signal) {
|
|
|
321
323
|
continue;
|
|
322
324
|
}
|
|
323
325
|
if (char === "\r" || char === "\n") {
|
|
324
|
-
settle(() =>
|
|
326
|
+
settle(() => resolve(typed));
|
|
325
327
|
return;
|
|
326
328
|
}
|
|
327
329
|
if (char === CTRL_C) {
|
|
@@ -329,7 +331,7 @@ function readHiddenLine(stdin, signal) {
|
|
|
329
331
|
return;
|
|
330
332
|
}
|
|
331
333
|
if (char === CTRL_D) {
|
|
332
|
-
settle(() => typed === "" ? reject(missingKey(NO_KEY_READ)) :
|
|
334
|
+
settle(() => typed === "" ? reject(missingKey(NO_KEY_READ)) : resolve(typed));
|
|
333
335
|
return;
|
|
334
336
|
}
|
|
335
337
|
if (char === DELETE || char === BACKSPACE) {
|
|
@@ -349,7 +351,7 @@ function readHiddenLine(stdin, signal) {
|
|
|
349
351
|
}
|
|
350
352
|
if (escape === "started") escape = "carried";
|
|
351
353
|
};
|
|
352
|
-
const onEnd = () => settle(() =>
|
|
354
|
+
const onEnd = () => settle(() => resolve(typed));
|
|
353
355
|
const onError = (error) => settle(() => reject(missingKey(`\u6CA1\u6709\u8BFB\u5230\u5BC6\u94A5\uFF1A\u6807\u51C6\u8F93\u5165\u51FA\u9519\uFF08${briefReason(error)}\uFF09`)));
|
|
354
356
|
const onAbort = () => settle(() => reject(interruptedError(CANCELLED)));
|
|
355
357
|
stdin.on("data", onData);
|
|
@@ -394,7 +396,7 @@ async function readNewKey(io) {
|
|
|
394
396
|
|
|
395
397
|
// package.json
|
|
396
398
|
var name = "bukesiyi-cli";
|
|
397
|
-
var version = "0.
|
|
399
|
+
var version = "0.3.0";
|
|
398
400
|
|
|
399
401
|
// src/version.ts
|
|
400
402
|
var PACKAGE_NAME = name;
|
|
@@ -402,27 +404,45 @@ var VERSION = version;
|
|
|
402
404
|
|
|
403
405
|
// src/client.ts
|
|
404
406
|
var DEFAULT_REQUEST_TIMEOUT_MS = 15e3;
|
|
407
|
+
var DEFAULT_DOWNLOAD_TIMEOUT_MS = 12e4;
|
|
408
|
+
var MAX_DOWNLOAD_BYTES = 1024 * 1024 * 1024;
|
|
405
409
|
var ME_PATH = "/api/open/v1/me";
|
|
406
410
|
var MAX_BODY_BYTES = 1024 * 1024;
|
|
407
411
|
var NOT_FOUND_HINT = "\u8FD9\u4E2A\u5730\u5740\u4E0D\u63D0\u4F9B API \u8C03\u7528\uFF1A\u53EF\u80FD\u8FD8\u6CA1\u6709\u5BF9\u5916\u5F00\u901A\uFF0C\u6216\u8005 --base-url \u5199\u9519\u4E86";
|
|
412
|
+
var EXIT_BY_SERVER_CODE = {
|
|
413
|
+
OPEN_API_INSUFFICIENT_BALANCE: EXIT.FUNDS,
|
|
414
|
+
OPEN_API_QUOTE_CHANGED: EXIT.QUOTE_CHANGED,
|
|
415
|
+
OPEN_API_QUOTE_REQUIRED: EXIT.QUOTE_CHANGED,
|
|
416
|
+
OPEN_API_ORDER_NOT_READY: EXIT.RETRY_LATER,
|
|
417
|
+
OPEN_API_QUOTA_EXCEEDED: EXIT.RETRY_LATER,
|
|
418
|
+
OPEN_API_ORDER_NOT_FOUND: EXIT.NOT_FOUND,
|
|
419
|
+
OPEN_API_PRODUCT_NOT_FOUND: EXIT.NOT_FOUND,
|
|
420
|
+
OPEN_API_TEMPLATE_NOT_FOUND: EXIT.NOT_FOUND,
|
|
421
|
+
// 「这单已交付/已失败,不能取消」也是 409,按状态码会被当成「报价变了」(6);
|
|
422
|
+
// 它说的是这个动作对当前状态不成立,重试也不会变,按「用法不对」(2)定。
|
|
423
|
+
OPEN_API_ORDER_NOT_CANCELLABLE: EXIT.USAGE
|
|
424
|
+
};
|
|
408
425
|
function userAgent() {
|
|
409
426
|
return `${PACKAGE_NAME}/${VERSION} node/${process.versions.node}`;
|
|
410
427
|
}
|
|
411
428
|
function isRecord2(value) {
|
|
412
429
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
413
430
|
}
|
|
414
|
-
function
|
|
415
|
-
return
|
|
431
|
+
function numberOrUndefined(value) {
|
|
432
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
433
|
+
}
|
|
434
|
+
function retryableStatus(status4) {
|
|
435
|
+
return status4 === 429 || status4 >= 500;
|
|
416
436
|
}
|
|
417
|
-
function unreadableResponse(
|
|
418
|
-
const retryable = retryableStatus(
|
|
437
|
+
function unreadableResponse(status4) {
|
|
438
|
+
const retryable = retryableStatus(status4);
|
|
419
439
|
const advice = retryable ? "\u53EF\u80FD\u662F\u7F51\u5173\u6216\u4E2D\u95F4\u5C42\u51FA\u7684\u9519\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" : "\u53EF\u80FD\u662F\u7F51\u5173\u6216\u4E2D\u95F4\u5C42\u51FA\u7684\u9519\uFF0C\u4E5F\u53EF\u80FD\u662F\u670D\u52A1\u5730\u5740\u6307\u5230\u4E86\u522B\u5904\uFF1B\u91CD\u8BD5\u591A\u534A\u6CA1\u6709\u7528\uFF0C\u8BF7\u5148\u6838\u5BF9\u670D\u52A1\u5730\u5740";
|
|
420
440
|
return new CliError({
|
|
421
441
|
code: "CLI_BAD_RESPONSE",
|
|
422
442
|
exitCode: EXIT.SERVER,
|
|
423
443
|
retryable,
|
|
424
|
-
message: `\u670D\u52A1\u5668\u56DE\u4E86\u4E00\u4E2A\u770B\u4E0D\u61C2\u7684\u56DE\u5E94\uFF08HTTP ${
|
|
425
|
-
hints:
|
|
444
|
+
message: `\u670D\u52A1\u5668\u56DE\u4E86\u4E00\u4E2A\u770B\u4E0D\u61C2\u7684\u56DE\u5E94\uFF08HTTP ${status4}\uFF09\uFF0C${advice}`,
|
|
445
|
+
hints: status4 === 404 ? [NOT_FOUND_HINT] : []
|
|
426
446
|
});
|
|
427
447
|
}
|
|
428
448
|
function redirectTarget(response, requestUrl) {
|
|
@@ -442,11 +462,15 @@ function discardBody(response) {
|
|
|
442
462
|
}
|
|
443
463
|
}
|
|
444
464
|
async function readBody(response, abandoned) {
|
|
465
|
+
const bytes = await readBodyBytes(response, abandoned, MAX_BODY_BYTES);
|
|
466
|
+
return bytes === null ? null : bytes.toString("utf8");
|
|
467
|
+
}
|
|
468
|
+
async function readBodyBytes(response, abandoned, maxBytes) {
|
|
445
469
|
const body = response.body;
|
|
446
|
-
if (body === null) return
|
|
470
|
+
if (body === null) return Buffer.alloc(0);
|
|
447
471
|
if (body === void 0) {
|
|
448
472
|
const text = await response.text();
|
|
449
|
-
return Buffer.byteLength(text, "utf8") >
|
|
473
|
+
return Buffer.byteLength(text, "utf8") > maxBytes ? null : Buffer.from(text, "utf8");
|
|
450
474
|
}
|
|
451
475
|
const reader = body.getReader();
|
|
452
476
|
const release2 = () => void reader.cancel().catch(() => void 0);
|
|
@@ -459,7 +483,7 @@ async function readBody(response, abandoned) {
|
|
|
459
483
|
const { done, value } = await reader.read();
|
|
460
484
|
if (done) break;
|
|
461
485
|
size += value.byteLength;
|
|
462
|
-
if (size >
|
|
486
|
+
if (size > maxBytes) {
|
|
463
487
|
await reader.cancel().catch(() => void 0);
|
|
464
488
|
return null;
|
|
465
489
|
}
|
|
@@ -468,7 +492,7 @@ async function readBody(response, abandoned) {
|
|
|
468
492
|
} finally {
|
|
469
493
|
abandoned.removeEventListener("abort", release2);
|
|
470
494
|
}
|
|
471
|
-
return Buffer.concat(chunks)
|
|
495
|
+
return Buffer.concat(chunks);
|
|
472
496
|
}
|
|
473
497
|
function isTimeout(error) {
|
|
474
498
|
const name2 = typeof error === "object" && error !== null ? error.name : void 0;
|
|
@@ -478,9 +502,9 @@ function proxyHints(origin, deps) {
|
|
|
478
502
|
const variable = deps.env ? envProxyFor(origin, deps.env) : null;
|
|
479
503
|
return variable === null ? [] : [`\u73AF\u5883\u91CC\u5F00\u7740\u4EE3\u7406\uFF08${variable}\uFF09\uFF0C\u8FD9\u6B21\u8BF7\u6C42\u53EF\u80FD\u662F\u7ECF\u5B83\u53D1\u51FA\u7684\uFF1A\u51FA\u95EE\u9898\u7684\u4E5F\u53EF\u80FD\u662F\u4EE3\u7406`];
|
|
480
504
|
}
|
|
481
|
-
async function exchange(url, apiKey, deps, origin) {
|
|
505
|
+
async function exchange(url, apiKey, plan, deps, origin) {
|
|
482
506
|
if (deps.signal?.aborted) throw interruptedError();
|
|
483
|
-
const timeoutMs = deps.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
507
|
+
const timeoutMs = plan.timeoutMs ?? deps.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
484
508
|
const controller = new AbortController();
|
|
485
509
|
let timedOut = false;
|
|
486
510
|
let timer;
|
|
@@ -500,15 +524,20 @@ async function exchange(url, apiKey, deps, origin) {
|
|
|
500
524
|
};
|
|
501
525
|
});
|
|
502
526
|
deps.signal?.addEventListener("abort", stop, { once: true });
|
|
527
|
+
const headers = {
|
|
528
|
+
Authorization: `Bearer ${apiKey}`,
|
|
529
|
+
Accept: "application/json",
|
|
530
|
+
"User-Agent": userAgent()
|
|
531
|
+
};
|
|
532
|
+
if (plan.contentType !== void 0) headers["Content-Type"] = plan.contentType;
|
|
533
|
+
if (plan.idempotencyKey !== void 0) headers["Idempotency-Key"] = plan.idempotencyKey;
|
|
534
|
+
const asBytes = plan.asBytes === true;
|
|
503
535
|
const send = deps.fetch;
|
|
504
536
|
const work = (async () => {
|
|
505
537
|
const response = await send(url, {
|
|
506
|
-
method:
|
|
507
|
-
headers
|
|
508
|
-
|
|
509
|
-
Accept: "application/json",
|
|
510
|
-
"User-Agent": userAgent()
|
|
511
|
-
},
|
|
538
|
+
method: plan.method,
|
|
539
|
+
headers,
|
|
540
|
+
...plan.body === void 0 ? {} : { body: plan.body },
|
|
512
541
|
// 跟着跳转走,密钥就会被带到一个使用者没有点头的地方。
|
|
513
542
|
redirect: "manual",
|
|
514
543
|
signal: controller.signal
|
|
@@ -517,6 +546,11 @@ async function exchange(url, apiKey, deps, origin) {
|
|
|
517
546
|
discardBody(response);
|
|
518
547
|
return { status: response.status, redirectedTo: redirectTarget(response, url) };
|
|
519
548
|
}
|
|
549
|
+
if (asBytes) {
|
|
550
|
+
const bytes = await readBodyBytes(response, controller.signal, MAX_DOWNLOAD_BYTES);
|
|
551
|
+
if (bytes === null) throw unreadableResponse(response.status);
|
|
552
|
+
return { status: response.status, bytes, headers: response.headers };
|
|
553
|
+
}
|
|
520
554
|
return { status: response.status, text: await readBody(response, controller.signal) };
|
|
521
555
|
})();
|
|
522
556
|
work.catch(() => void 0);
|
|
@@ -554,36 +588,40 @@ function parseJson(text) {
|
|
|
554
588
|
return null;
|
|
555
589
|
}
|
|
556
590
|
}
|
|
557
|
-
function serverError(
|
|
591
|
+
function serverError(status4, body, apiKey) {
|
|
558
592
|
const error = isRecord2(body) ? body.error : void 0;
|
|
559
593
|
if (!isRecord2(error) || typeof error.code !== "string" || typeof error.message !== "string") return null;
|
|
560
594
|
const retryAfter = error.retryAfterSeconds;
|
|
561
595
|
return new CliError({
|
|
562
596
|
code: error.code,
|
|
563
597
|
// 对面把收到的密钥抄回话里时,在这一层就抹掉。
|
|
564
|
-
message: error.message.trim() === "" ? `\u670D\u52A1\u5668\u62D2\u7EDD\u4E86\u8FD9\u6B21\u8BF7\u6C42\uFF08HTTP ${
|
|
565
|
-
|
|
566
|
-
|
|
598
|
+
message: error.message.trim() === "" ? `\u670D\u52A1\u5668\u62D2\u7EDD\u4E86\u8FD9\u6B21\u8BF7\u6C42\uFF08HTTP ${status4}\uFF09` : redactSecret(error.message, apiKey),
|
|
599
|
+
// 列进显式表的码按表定(409 在业务里分「报价变了」和「还没好」两种),其余按状态码。
|
|
600
|
+
exitCode: EXIT_BY_SERVER_CODE[error.code] ?? exitCodeForHttpStatus(status4),
|
|
601
|
+
retryable: typeof error.retryable === "boolean" ? error.retryable : retryableStatus(status4),
|
|
567
602
|
traceId: typeof error.traceId === "string" ? error.traceId : null,
|
|
568
603
|
retryAfterSeconds: typeof retryAfter === "number" && Number.isFinite(retryAfter) ? retryAfter : void 0,
|
|
569
|
-
httpStatus:
|
|
570
|
-
|
|
604
|
+
httpStatus: status4,
|
|
605
|
+
// 那句「这个地址不提供 API 调用」只对端点级的 404 有意义:业务里的 404(单不存在、产品不存在)
|
|
606
|
+
// 说的是东西没找到,不是地址写错。
|
|
607
|
+
hints: status4 === 404 && error.code === "OPEN_API_NOT_FOUND" ? [NOT_FOUND_HINT] : []
|
|
571
608
|
});
|
|
572
609
|
}
|
|
573
|
-
|
|
610
|
+
function redirectError(redirectedTo) {
|
|
611
|
+
const where = redirectedTo ? `\uFF08${redirectedTo}\uFF09` : "";
|
|
612
|
+
return new CliError({
|
|
613
|
+
code: "CLI_REDIRECT",
|
|
614
|
+
exitCode: EXIT.SERVER,
|
|
615
|
+
retryable: false,
|
|
616
|
+
message: `\u670D\u52A1\u5668\u628A\u8BF7\u6C42\u8F6C\u5230\u4E86\u522B\u5904${where}\uFF0C\u4E3A\u4E86\u4E0D\u628A\u5BC6\u94A5\u5E26\u8FC7\u53BB\u6CA1\u6709\u8DDF\u968F\u3002\u8BF7\u6838\u5BF9 --base-url`
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
async function requestJson(baseUrl, apiKey, plan, deps) {
|
|
574
620
|
const origin = normalizeBaseUrl(baseUrl);
|
|
575
621
|
assertKeyFormat(apiKey);
|
|
576
622
|
assertReachedDirectly(origin, deps.env);
|
|
577
|
-
const result = await exchange(`${origin}${path}`, apiKey, deps, origin);
|
|
578
|
-
if ("redirectedTo" in result)
|
|
579
|
-
const where = result.redirectedTo ? `\uFF08${result.redirectedTo}\uFF09` : "";
|
|
580
|
-
throw new CliError({
|
|
581
|
-
code: "CLI_REDIRECT",
|
|
582
|
-
exitCode: EXIT.SERVER,
|
|
583
|
-
retryable: false,
|
|
584
|
-
message: `\u670D\u52A1\u5668\u628A\u8BF7\u6C42\u8F6C\u5230\u4E86\u522B\u5904${where}\uFF0C\u4E3A\u4E86\u4E0D\u628A\u5BC6\u94A5\u5E26\u8FC7\u53BB\u6CA1\u6709\u8DDF\u968F\u3002\u8BF7\u6838\u5BF9 --base-url`
|
|
585
|
-
});
|
|
586
|
-
}
|
|
623
|
+
const result = await exchange(`${origin}${plan.path}`, apiKey, plan, deps, origin);
|
|
624
|
+
if ("redirectedTo" in result) throw redirectError(result.redirectedTo);
|
|
587
625
|
const parsed = parseJson(result.text);
|
|
588
626
|
if (result.status >= 200 && result.status < 300) {
|
|
589
627
|
if (!parsed) throw unreadableResponse(result.status);
|
|
@@ -591,6 +629,357 @@ async function getJson(baseUrl, apiKey, path, deps) {
|
|
|
591
629
|
}
|
|
592
630
|
throw (parsed && serverError(result.status, parsed.value, apiKey)) ?? unreadableResponse(result.status);
|
|
593
631
|
}
|
|
632
|
+
async function getJson(baseUrl, apiKey, path, deps) {
|
|
633
|
+
return requestJson(baseUrl, apiKey, { method: "GET", path }, deps);
|
|
634
|
+
}
|
|
635
|
+
async function postJson(baseUrl, apiKey, path, body, idempotencyKey, deps) {
|
|
636
|
+
return requestJson(
|
|
637
|
+
baseUrl,
|
|
638
|
+
apiKey,
|
|
639
|
+
{ method: "POST", path, body: JSON.stringify(body), contentType: "application/json", idempotencyKey },
|
|
640
|
+
deps
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
async function putRaw(baseUrl, apiKey, path, bytes, contentType, idempotencyKey, deps) {
|
|
644
|
+
return requestJson(baseUrl, apiKey, { method: "PUT", path, body: bytes, contentType, idempotencyKey }, deps);
|
|
645
|
+
}
|
|
646
|
+
async function postRaw(baseUrl, apiKey, path, bytes, contentType, idempotencyKey, deps) {
|
|
647
|
+
return requestJson(baseUrl, apiKey, { method: "POST", path, body: bytes, contentType, idempotencyKey }, deps);
|
|
648
|
+
}
|
|
649
|
+
async function downloadFile(baseUrl, apiKey, path, deps) {
|
|
650
|
+
const origin = normalizeBaseUrl(baseUrl);
|
|
651
|
+
assertKeyFormat(apiKey);
|
|
652
|
+
assertReachedDirectly(origin, deps.env);
|
|
653
|
+
const result = await exchange(`${origin}${path}`, apiKey, downloadPlan(path, deps), deps, origin);
|
|
654
|
+
if ("redirectedTo" in result) throw redirectError(result.redirectedTo);
|
|
655
|
+
if (result.status < 200 || result.status >= 300) {
|
|
656
|
+
const text = result.bytes.toString("utf8");
|
|
657
|
+
const parsed = parseJson(text);
|
|
658
|
+
throw (parsed && serverError(result.status, parsed.value, apiKey)) ?? unreadableResponse(result.status);
|
|
659
|
+
}
|
|
660
|
+
return { bytes: result.bytes, filename: filenameFromDisposition(result.headers.get("content-disposition")) };
|
|
661
|
+
}
|
|
662
|
+
function downloadPlan(path, deps) {
|
|
663
|
+
return {
|
|
664
|
+
method: "GET",
|
|
665
|
+
path,
|
|
666
|
+
// 下载不共用 JSON 请求 15 秒的默认时限;调用方在 deps 里给了更短的,照他的。
|
|
667
|
+
timeoutMs: deps.requestTimeoutMs !== void 0 ? Math.max(deps.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS) : DEFAULT_DOWNLOAD_TIMEOUT_MS,
|
|
668
|
+
asBytes: true
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function filenameFromDisposition(value) {
|
|
672
|
+
if (typeof value !== "string" || value === "") return null;
|
|
673
|
+
const star = /filename\*=(?:UTF-8|utf-8)''([^;]+)/.exec(value);
|
|
674
|
+
if (star !== null) {
|
|
675
|
+
try {
|
|
676
|
+
const decoded = decodeURIComponent(star[1]);
|
|
677
|
+
if (decoded !== "") return decoded;
|
|
678
|
+
} catch {
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
const plain = /filename="?([^";]+)"?/.exec(value);
|
|
682
|
+
return plain !== null ? plain[1] : null;
|
|
683
|
+
}
|
|
684
|
+
function required(report) {
|
|
685
|
+
return (value) => {
|
|
686
|
+
if (typeof value !== "string" || value === "") {
|
|
687
|
+
report.push("\u5B57\u6BB5\u5F62\u72B6\u4E0D\u5BF9");
|
|
688
|
+
return "";
|
|
689
|
+
}
|
|
690
|
+
return value;
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function parseBalance(body) {
|
|
694
|
+
const raw = isRecord2(body) ? body.balance : void 0;
|
|
695
|
+
if (!isRecord2(raw)) return null;
|
|
696
|
+
const problems = [];
|
|
697
|
+
const text = required(problems);
|
|
698
|
+
const currency = text(raw.currency);
|
|
699
|
+
const updatedAt = text(raw.updatedAt);
|
|
700
|
+
const available = numberOrUndefined(raw.available);
|
|
701
|
+
const held = numberOrUndefined(raw.held);
|
|
702
|
+
const spent = numberOrUndefined(raw.spent);
|
|
703
|
+
if (problems.length > 0 || available === void 0 || held === void 0 || spent === void 0) return null;
|
|
704
|
+
return { currency, available, held, spent, updatedAt };
|
|
705
|
+
}
|
|
706
|
+
function parseProductImages(value) {
|
|
707
|
+
if (!Array.isArray(value)) return null;
|
|
708
|
+
const images = [];
|
|
709
|
+
for (const item of value) {
|
|
710
|
+
if (!isRecord2(item)) return null;
|
|
711
|
+
const problems = [];
|
|
712
|
+
const text = required(problems);
|
|
713
|
+
const image = {
|
|
714
|
+
id: text(item.id),
|
|
715
|
+
angle: typeof item.angle === "string" ? item.angle : "",
|
|
716
|
+
url: text(item.url),
|
|
717
|
+
mime: text(item.mime),
|
|
718
|
+
bytes: numberOrUndefined(item.bytes) ?? -1,
|
|
719
|
+
sha256: text(item.sha256)
|
|
720
|
+
};
|
|
721
|
+
if (problems.length > 0 || image.bytes < 0) return null;
|
|
722
|
+
images.push(image);
|
|
723
|
+
}
|
|
724
|
+
return images;
|
|
725
|
+
}
|
|
726
|
+
function parseProduct(body) {
|
|
727
|
+
const product = isRecord2(body) ? body.product : void 0;
|
|
728
|
+
if (!isRecord2(product)) return null;
|
|
729
|
+
const problems = [];
|
|
730
|
+
const text = required(problems);
|
|
731
|
+
const images = parseProductImages(product.images);
|
|
732
|
+
const sku = typeof product.sku === "string" ? product.sku : null;
|
|
733
|
+
const parsed = {
|
|
734
|
+
id: text(product.id),
|
|
735
|
+
name: text(product.name),
|
|
736
|
+
category: text(product.category),
|
|
737
|
+
sku,
|
|
738
|
+
createdAt: text(product.createdAt),
|
|
739
|
+
images: images ?? []
|
|
740
|
+
};
|
|
741
|
+
if (problems.length > 0 || images === null) return null;
|
|
742
|
+
return parsed;
|
|
743
|
+
}
|
|
744
|
+
function parseProductLock(body) {
|
|
745
|
+
const lock = isRecord2(body) ? body.productLock : void 0;
|
|
746
|
+
if (!isRecord2(lock)) return null;
|
|
747
|
+
const problems = [];
|
|
748
|
+
const text = required(problems);
|
|
749
|
+
const parsed = { colorName: text(lock.colorName), silhouette: text(lock.silhouette), material: text(lock.material) };
|
|
750
|
+
return problems.length > 0 ? null : parsed;
|
|
751
|
+
}
|
|
752
|
+
function parseCatalogTemplate(item) {
|
|
753
|
+
if (!isRecord2(item)) return null;
|
|
754
|
+
const problems = [];
|
|
755
|
+
const text = required(problems);
|
|
756
|
+
const durationSeconds = numberOrUndefined(item.durationSeconds);
|
|
757
|
+
const needsList = Array.isArray(item.needs) && item.needs.every((need) => typeof need === "string") ? item.needs : null;
|
|
758
|
+
if (needsList === null) problems.push("needs");
|
|
759
|
+
const parsed = {
|
|
760
|
+
id: text(item.id),
|
|
761
|
+
title: text(item.title),
|
|
762
|
+
tier: text(item.tier),
|
|
763
|
+
summary: typeof item.summary === "string" ? item.summary : "",
|
|
764
|
+
durationSeconds: durationSeconds ?? -1,
|
|
765
|
+
needs: needsList ?? [],
|
|
766
|
+
defaultProps: isRecord2(item.defaultProps) ? item.defaultProps : {}
|
|
767
|
+
};
|
|
768
|
+
if (problems.length > 0 || durationSeconds === void 0) return null;
|
|
769
|
+
return parsed;
|
|
770
|
+
}
|
|
771
|
+
function parseCatalog(body) {
|
|
772
|
+
const catalog2 = isRecord2(body) ? body.catalog : void 0;
|
|
773
|
+
if (!isRecord2(catalog2)) return null;
|
|
774
|
+
const category = isRecord2(catalog2.category) ? catalog2.category : null;
|
|
775
|
+
const templates = Array.isArray(catalog2.templates) ? catalog2.templates : null;
|
|
776
|
+
if (!category || templates === null) return null;
|
|
777
|
+
const problems = [];
|
|
778
|
+
const text = required(problems);
|
|
779
|
+
const parsedTemplates = [];
|
|
780
|
+
for (const item of templates) {
|
|
781
|
+
const parsed2 = parseCatalogTemplate(item);
|
|
782
|
+
if (parsed2 === null) problems.push("template");
|
|
783
|
+
else parsedTemplates.push(parsed2);
|
|
784
|
+
}
|
|
785
|
+
const parsed = {
|
|
786
|
+
category: { id: text(category.id), name: text(category.name), badge: text(category.badge) },
|
|
787
|
+
templates: parsedTemplates
|
|
788
|
+
};
|
|
789
|
+
return problems.length > 0 ? null : parsed;
|
|
790
|
+
}
|
|
791
|
+
function parseUpload(body) {
|
|
792
|
+
if (!isRecord2(body)) return null;
|
|
793
|
+
const problems = [];
|
|
794
|
+
const text = required(problems);
|
|
795
|
+
const bytes = numberOrUndefined(body.bytes);
|
|
796
|
+
const parsed = { url: text(body.url), sha256: text(body.sha256), bytes: bytes ?? -1 };
|
|
797
|
+
if (problems.length > 0 || bytes === void 0) return null;
|
|
798
|
+
return parsed;
|
|
799
|
+
}
|
|
800
|
+
function parseQuoteValue(value) {
|
|
801
|
+
if (!isRecord2(value)) return null;
|
|
802
|
+
const problems = [];
|
|
803
|
+
const text = required(problems);
|
|
804
|
+
const numbers = ["durationMilliseconds", "memberMilliseconds", "excessMilliseconds", "credits"].map(
|
|
805
|
+
(field) => numberOrUndefined(value[field])
|
|
806
|
+
);
|
|
807
|
+
if (problems.length > 0 || numbers.some((entry) => entry === void 0)) return null;
|
|
808
|
+
const [durationMilliseconds, memberMilliseconds, excessMilliseconds, credits] = numbers;
|
|
809
|
+
return {
|
|
810
|
+
quoteHash: text(value.quoteHash),
|
|
811
|
+
templateId: text(value.templateId),
|
|
812
|
+
durationMilliseconds,
|
|
813
|
+
memberMilliseconds,
|
|
814
|
+
excessMilliseconds,
|
|
815
|
+
credits
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
function parseQuote(body) {
|
|
819
|
+
return parseQuoteValue(isRecord2(body) ? body.quote : void 0);
|
|
820
|
+
}
|
|
821
|
+
function parseOrder(body) {
|
|
822
|
+
const order2 = isRecord2(body) ? body.order : void 0;
|
|
823
|
+
if (!isRecord2(order2)) return null;
|
|
824
|
+
const problems = [];
|
|
825
|
+
const text = required(problems);
|
|
826
|
+
const durationSeconds = numberOrUndefined(order2.durationSeconds);
|
|
827
|
+
const bytes = numberOrUndefined(order2.bytes);
|
|
828
|
+
const quoteValue = order2.quote === void 0 ? void 0 : parseQuoteValue(order2.quote);
|
|
829
|
+
if (order2.quote !== void 0 && quoteValue === null) problems.push("quote");
|
|
830
|
+
const parsed = {
|
|
831
|
+
id: text(order2.id),
|
|
832
|
+
status: text(order2.status),
|
|
833
|
+
templateId: text(order2.templateId),
|
|
834
|
+
templateTitle: text(order2.templateTitle),
|
|
835
|
+
createdAt: text(order2.createdAt),
|
|
836
|
+
...typeof order2.finishedAt === "string" ? { finishedAt: order2.finishedAt } : {},
|
|
837
|
+
...durationSeconds !== void 0 ? { durationSeconds } : {},
|
|
838
|
+
...typeof order2.error === "string" ? { error: order2.error } : {},
|
|
839
|
+
...typeof order2.videoUrl === "string" ? { videoUrl: order2.videoUrl } : {},
|
|
840
|
+
...bytes !== void 0 ? { bytes } : {},
|
|
841
|
+
...quoteValue !== void 0 && quoteValue !== null ? { quote: quoteValue } : {}
|
|
842
|
+
};
|
|
843
|
+
return problems.length > 0 ? null : parsed;
|
|
844
|
+
}
|
|
845
|
+
function parseDramaMoney(value) {
|
|
846
|
+
if (!isRecord2(value)) return null;
|
|
847
|
+
const problems = [];
|
|
848
|
+
const text = required(problems);
|
|
849
|
+
const numbers = ["held", "settled", "released", "refunded"].map((field) => numberOrUndefined(value[field]));
|
|
850
|
+
if (numbers.some((entry) => entry === void 0)) return null;
|
|
851
|
+
const [held, settled, released, refunded] = numbers;
|
|
852
|
+
const currency = text(value.currency);
|
|
853
|
+
return problems.length > 0 ? null : { currency, held, settled, released, refunded };
|
|
854
|
+
}
|
|
855
|
+
function parseDramaGap(value) {
|
|
856
|
+
if (!isRecord2(value)) return null;
|
|
857
|
+
const problems = [];
|
|
858
|
+
const text = required(problems);
|
|
859
|
+
const sceneNos = Array.isArray(value.sceneNos) && value.sceneNos.every((no) => numberOrUndefined(no) !== void 0) ? value.sceneNos : null;
|
|
860
|
+
if (sceneNos === null) problems.push("sceneNos");
|
|
861
|
+
const label = typeof value.label === "string" ? value.label : "";
|
|
862
|
+
const parsed = { kind: text(value.kind), key: text(value.key), label, sceneNos: sceneNos ?? [] };
|
|
863
|
+
return problems.length > 0 ? null : parsed;
|
|
864
|
+
}
|
|
865
|
+
function parseDramaOrder(body) {
|
|
866
|
+
const order2 = isRecord2(body) ? body.order : void 0;
|
|
867
|
+
if (!isRecord2(order2)) return null;
|
|
868
|
+
const problems = [];
|
|
869
|
+
const text = required(problems);
|
|
870
|
+
const money = parseDramaMoney(order2.money);
|
|
871
|
+
if (money === null) problems.push("money");
|
|
872
|
+
const actionsValue = Array.isArray(order2.nextActions) ? order2.nextActions : null;
|
|
873
|
+
const actions = actionsValue === null ? [] : actionsValue.filter((action) => typeof action === "string");
|
|
874
|
+
if (actionsValue === null || actions.length !== actionsValue.length) problems.push("nextActions");
|
|
875
|
+
const gapsValue = order2.gaps === void 0 ? void 0 : Array.isArray(order2.gaps) ? order2.gaps : null;
|
|
876
|
+
if (order2.gaps !== void 0 && gapsValue === null) problems.push("gaps");
|
|
877
|
+
const gaps = gapsValue === void 0 || gapsValue === null ? void 0 : gapsValue.map((item) => {
|
|
878
|
+
const parsed2 = parseDramaGap(item);
|
|
879
|
+
if (parsed2 === null) problems.push("gap");
|
|
880
|
+
return parsed2;
|
|
881
|
+
});
|
|
882
|
+
if (gaps !== void 0 && gaps.some((gap) => gap === null)) problems.push("gap");
|
|
883
|
+
const parsed = {
|
|
884
|
+
id: text(order2.id),
|
|
885
|
+
projectId: text(order2.projectId),
|
|
886
|
+
status: text(order2.status),
|
|
887
|
+
productId: text(order2.productId),
|
|
888
|
+
genreId: text(order2.genreId),
|
|
889
|
+
durationKey: text(order2.durationKey),
|
|
890
|
+
videoModel: typeof order2.videoModel === "string" ? order2.videoModel : null,
|
|
891
|
+
resolution: typeof order2.resolution === "string" ? order2.resolution : null,
|
|
892
|
+
money: money ?? { currency: "", held: 0, settled: 0, released: 0, refunded: 0 },
|
|
893
|
+
nextActions: actions,
|
|
894
|
+
...typeof order2.reason === "string" ? { reason: order2.reason } : {},
|
|
895
|
+
...gaps === void 0 ? {} : { gaps },
|
|
896
|
+
createdAt: text(order2.createdAt),
|
|
897
|
+
updatedAt: text(order2.updatedAt)
|
|
898
|
+
};
|
|
899
|
+
return problems.length > 0 ? null : parsed;
|
|
900
|
+
}
|
|
901
|
+
function parseDramaQuote(body) {
|
|
902
|
+
if (!isRecord2(body)) return null;
|
|
903
|
+
const problems = [];
|
|
904
|
+
const text = required(problems);
|
|
905
|
+
const quote3 = isRecord2(body.quote) ? body.quote : null;
|
|
906
|
+
if (quote3 === null) problems.push("quote");
|
|
907
|
+
const totalCredits = quote3 === null ? void 0 : numberOrUndefined(quote3.totalCredits);
|
|
908
|
+
const shotCount = quote3 === null ? void 0 : numberOrUndefined(quote3.shotCount);
|
|
909
|
+
if (totalCredits === void 0 || shotCount === void 0) problems.push("quote");
|
|
910
|
+
const shotCreditCost = quote3 === null ? void 0 : numberOrUndefined(quote3.shotCreditCost);
|
|
911
|
+
const videoModel = quote3 !== null && typeof quote3.videoModel === "string" ? quote3.videoModel : void 0;
|
|
912
|
+
const resolution = quote3 !== null && typeof quote3.resolution === "string" ? quote3.resolution : void 0;
|
|
913
|
+
const parsed = {
|
|
914
|
+
quoteHash: text(body.quoteHash),
|
|
915
|
+
sufficient: typeof body.sufficient === "boolean" ? body.sufficient : null,
|
|
916
|
+
totalCredits: totalCredits ?? -1,
|
|
917
|
+
shotCount: shotCount ?? -1,
|
|
918
|
+
...shotCreditCost !== void 0 ? { shotCreditCost } : {},
|
|
919
|
+
...videoModel !== void 0 ? { videoModel } : {},
|
|
920
|
+
...resolution !== void 0 ? { resolution } : {}
|
|
921
|
+
};
|
|
922
|
+
return problems.length > 0 ? null : parsed;
|
|
923
|
+
}
|
|
924
|
+
function parseRunAction(value) {
|
|
925
|
+
if (!isRecord2(value) || typeof value.type !== "string" || value.type === "") return null;
|
|
926
|
+
return {
|
|
927
|
+
type: value.type,
|
|
928
|
+
...numberOrUndefined(value.credits) !== void 0 ? { credits: numberOrUndefined(value.credits) } : {},
|
|
929
|
+
...typeof value.confirmKind === "string" ? { confirmKind: value.confirmKind } : {},
|
|
930
|
+
...value.confirmation !== void 0 ? { confirmation: value.confirmation } : {}
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
function parseRun(body) {
|
|
934
|
+
const run2 = isRecord2(body) ? body.run : void 0;
|
|
935
|
+
if (!isRecord2(run2)) return null;
|
|
936
|
+
const problems = [];
|
|
937
|
+
const text = required(problems);
|
|
938
|
+
const version2 = numberOrUndefined(run2.version);
|
|
939
|
+
const pollAfterMs = numberOrUndefined(run2.pollAfterMs);
|
|
940
|
+
const product = isRecord2(run2.product) ? run2.product : null;
|
|
941
|
+
if (!product) problems.push("product");
|
|
942
|
+
const actions = Array.isArray(run2.nextActions) ? run2.nextActions : null;
|
|
943
|
+
if (actions === null) problems.push("nextActions");
|
|
944
|
+
const messagesValue = Array.isArray(run2.messages) ? run2.messages : null;
|
|
945
|
+
if (messagesValue === null) problems.push("messages");
|
|
946
|
+
const messages = messagesValue === null ? [] : messagesValue.map((message2) => {
|
|
947
|
+
if (!isRecord2(message2) || typeof message2.text !== "string") {
|
|
948
|
+
problems.push("message");
|
|
949
|
+
return { role: "", text: "" };
|
|
950
|
+
}
|
|
951
|
+
return { role: typeof message2.role === "string" ? message2.role : "", text: message2.text };
|
|
952
|
+
});
|
|
953
|
+
const failureValue = isRecord2(run2.failure) ? run2.failure : null;
|
|
954
|
+
const failure = failureValue ? {
|
|
955
|
+
code: text(failureValue.code),
|
|
956
|
+
title: text(failureValue.title),
|
|
957
|
+
detail: typeof failureValue.detail === "string" ? failureValue.detail : "",
|
|
958
|
+
retryable: failureValue.retryable === true
|
|
959
|
+
} : null;
|
|
960
|
+
const currentProductionCredits = numberOrUndefined(run2.currentProductionCredits);
|
|
961
|
+
const parsed = {
|
|
962
|
+
rootRunId: text(run2.rootRunId),
|
|
963
|
+
version: version2 ?? -1,
|
|
964
|
+
status: text(run2.status),
|
|
965
|
+
stage: text(run2.stage),
|
|
966
|
+
label: text(run2.label),
|
|
967
|
+
updatedAt: text(run2.updatedAt),
|
|
968
|
+
pollAfterMs: pollAfterMs ?? null,
|
|
969
|
+
productionConfirmed: run2.productionConfirmed === true,
|
|
970
|
+
...currentProductionCredits !== void 0 ? { currentProductionCredits } : {},
|
|
971
|
+
product: product ? { id: text(product.id), name: text(product.name) } : { id: "", name: "" },
|
|
972
|
+
nextActions: actions === null ? [] : actions.map((action) => {
|
|
973
|
+
const parsed2 = parseRunAction(action);
|
|
974
|
+
if (parsed2 === null) problems.push("action");
|
|
975
|
+
return parsed2 ?? { type: "" };
|
|
976
|
+
}),
|
|
977
|
+
messages,
|
|
978
|
+
failure
|
|
979
|
+
};
|
|
980
|
+
if (problems.length > 0 || version2 === void 0) return null;
|
|
981
|
+
return parsed;
|
|
982
|
+
}
|
|
594
983
|
function parseMe(body) {
|
|
595
984
|
if (!isRecord2(body)) return null;
|
|
596
985
|
const { key, account, workspace } = body;
|
|
@@ -613,6 +1002,274 @@ async function getMe(baseUrl, apiKey, deps) {
|
|
|
613
1002
|
if (!me) throw unreadableResponse(reply.status);
|
|
614
1003
|
return me;
|
|
615
1004
|
}
|
|
1005
|
+
async function getBalance(baseUrl, apiKey, deps) {
|
|
1006
|
+
const reply = await getJson(baseUrl, apiKey, "/api/open/v1/balance", deps);
|
|
1007
|
+
const balance2 = parseBalance(reply.body);
|
|
1008
|
+
if (!balance2 || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1009
|
+
return { view: balance2, raw: reply.body };
|
|
1010
|
+
}
|
|
1011
|
+
async function createProduct(baseUrl, apiKey, name2, category, idempotencyKey, deps) {
|
|
1012
|
+
const reply = await postJson(
|
|
1013
|
+
baseUrl,
|
|
1014
|
+
apiKey,
|
|
1015
|
+
"/api/open/v1/products",
|
|
1016
|
+
{ name: name2, ...category === void 0 ? {} : { category } },
|
|
1017
|
+
idempotencyKey,
|
|
1018
|
+
deps
|
|
1019
|
+
);
|
|
1020
|
+
const product = parseProduct(reply.body);
|
|
1021
|
+
if (!product || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1022
|
+
return { view: product, raw: reply.body, replayed: reply.status === 200 };
|
|
1023
|
+
}
|
|
1024
|
+
async function putProductImage(baseUrl, apiKey, productId, angle, bytes, contentType, idempotencyKey, deps) {
|
|
1025
|
+
const reply = await putRaw(
|
|
1026
|
+
baseUrl,
|
|
1027
|
+
apiKey,
|
|
1028
|
+
`/api/open/v1/products/${encodeURIComponent(productId)}/images?angle=${angle}`,
|
|
1029
|
+
bytes,
|
|
1030
|
+
contentType,
|
|
1031
|
+
idempotencyKey,
|
|
1032
|
+
deps
|
|
1033
|
+
);
|
|
1034
|
+
const product = parseProduct(reply.body);
|
|
1035
|
+
if (!product || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1036
|
+
return { view: product, raw: reply.body, replayed: reply.status === 200 };
|
|
1037
|
+
}
|
|
1038
|
+
async function confirmProductLock(baseUrl, apiKey, productId, lock, idempotencyKey, deps) {
|
|
1039
|
+
const reply = await postJson(
|
|
1040
|
+
baseUrl,
|
|
1041
|
+
apiKey,
|
|
1042
|
+
`/api/open/v1/products/${encodeURIComponent(productId)}/lock/confirm`,
|
|
1043
|
+
{ productLock: lock },
|
|
1044
|
+
idempotencyKey,
|
|
1045
|
+
deps
|
|
1046
|
+
);
|
|
1047
|
+
const productLock = parseProductLock(reply.body);
|
|
1048
|
+
const product = parseProduct(reply.body);
|
|
1049
|
+
if (!productLock || !product || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1050
|
+
return { view: { productLock, product }, raw: reply.body };
|
|
1051
|
+
}
|
|
1052
|
+
async function getTemplateShortCatalog(baseUrl, apiKey, deps) {
|
|
1053
|
+
const reply = await getJson(baseUrl, apiKey, "/api/open/v1/template-shorts", deps);
|
|
1054
|
+
const catalog2 = parseCatalog(reply.body);
|
|
1055
|
+
if (!catalog2 || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1056
|
+
return { view: catalog2, raw: reply.body };
|
|
1057
|
+
}
|
|
1058
|
+
async function uploadTemplateShortAsset(baseUrl, apiKey, bytes, contentType, idempotencyKey, deps) {
|
|
1059
|
+
const reply = await postRaw(baseUrl, apiKey, "/api/open/v1/template-shorts/uploads", bytes, contentType, idempotencyKey, deps);
|
|
1060
|
+
const upload2 = parseUpload(reply.body);
|
|
1061
|
+
if (!upload2 || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1062
|
+
return { view: upload2, raw: reply.body };
|
|
1063
|
+
}
|
|
1064
|
+
async function quoteTemplateShort(baseUrl, apiKey, templateId, props, idempotencyKey, deps) {
|
|
1065
|
+
const reply = await postJson(
|
|
1066
|
+
baseUrl,
|
|
1067
|
+
apiKey,
|
|
1068
|
+
"/api/open/v1/template-shorts/quote",
|
|
1069
|
+
{ templateId, props },
|
|
1070
|
+
idempotencyKey,
|
|
1071
|
+
deps
|
|
1072
|
+
);
|
|
1073
|
+
const quote3 = parseQuote(reply.body);
|
|
1074
|
+
if (!quote3 || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1075
|
+
return { view: quote3, raw: reply.body };
|
|
1076
|
+
}
|
|
1077
|
+
async function createTemplateShortOrder(baseUrl, apiKey, templateId, props, expectedQuoteHash, idempotencyKey, deps) {
|
|
1078
|
+
return orderReplyOf(
|
|
1079
|
+
await postJson(
|
|
1080
|
+
baseUrl,
|
|
1081
|
+
apiKey,
|
|
1082
|
+
"/api/open/v1/template-shorts/orders",
|
|
1083
|
+
{ templateId, props, ...expectedQuoteHash === void 0 ? {} : { expectedQuoteHash } },
|
|
1084
|
+
idempotencyKey,
|
|
1085
|
+
deps
|
|
1086
|
+
)
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
async function getTemplateShortOrder(baseUrl, apiKey, orderId, deps) {
|
|
1090
|
+
return orderReplyOf(
|
|
1091
|
+
await getJson(baseUrl, apiKey, `/api/open/v1/template-shorts/orders/${encodeURIComponent(orderId)}`, deps)
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
async function cancelTemplateShortOrder(baseUrl, apiKey, orderId, idempotencyKey, deps) {
|
|
1095
|
+
return orderReplyOf(
|
|
1096
|
+
await postJson(
|
|
1097
|
+
baseUrl,
|
|
1098
|
+
apiKey,
|
|
1099
|
+
`/api/open/v1/template-shorts/orders/${encodeURIComponent(orderId)}/cancel`,
|
|
1100
|
+
{},
|
|
1101
|
+
idempotencyKey,
|
|
1102
|
+
deps
|
|
1103
|
+
)
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
async function orderReplyOf(reply) {
|
|
1107
|
+
const order2 = parseOrder(reply.body);
|
|
1108
|
+
if (!order2 || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1109
|
+
return { view: order2, raw: reply.body };
|
|
1110
|
+
}
|
|
1111
|
+
async function downloadTemplateShort(baseUrl, apiKey, orderId, deps) {
|
|
1112
|
+
return downloadFile(baseUrl, apiKey, `/api/open/v1/template-shorts/orders/${encodeURIComponent(orderId)}/download`, deps);
|
|
1113
|
+
}
|
|
1114
|
+
async function runReplyOf(reply) {
|
|
1115
|
+
const run2 = parseRun(reply.body);
|
|
1116
|
+
if (!run2 || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1117
|
+
return { view: run2, raw: reply.body };
|
|
1118
|
+
}
|
|
1119
|
+
async function createVideoRun(baseUrl, apiKey, body, idempotencyKey, deps) {
|
|
1120
|
+
return runReplyOf(await postJson(baseUrl, apiKey, "/api/open/v1/videos", body, idempotencyKey, deps));
|
|
1121
|
+
}
|
|
1122
|
+
async function getVideoRun(baseUrl, apiKey, runId, deps) {
|
|
1123
|
+
return runReplyOf(await getJson(baseUrl, apiKey, `/api/open/v1/videos/${encodeURIComponent(runId)}`, deps));
|
|
1124
|
+
}
|
|
1125
|
+
async function postVideoMessage(baseUrl, apiKey, runId, text, idempotencyKey, deps) {
|
|
1126
|
+
return runReplyOf(
|
|
1127
|
+
await postJson(
|
|
1128
|
+
baseUrl,
|
|
1129
|
+
apiKey,
|
|
1130
|
+
`/api/open/v1/videos/${encodeURIComponent(runId)}/messages`,
|
|
1131
|
+
{ text },
|
|
1132
|
+
idempotencyKey,
|
|
1133
|
+
deps
|
|
1134
|
+
)
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
async function confirmVideoProduction(baseUrl, apiKey, runId, expectedVersion, confirmation, idempotencyKey, deps) {
|
|
1138
|
+
return runReplyOf(
|
|
1139
|
+
await postJson(
|
|
1140
|
+
baseUrl,
|
|
1141
|
+
apiKey,
|
|
1142
|
+
`/api/open/v1/videos/${encodeURIComponent(runId)}/confirm`,
|
|
1143
|
+
{ expectedVersion, confirmation },
|
|
1144
|
+
idempotencyKey,
|
|
1145
|
+
deps
|
|
1146
|
+
)
|
|
1147
|
+
);
|
|
1148
|
+
}
|
|
1149
|
+
async function downloadVideo(baseUrl, apiKey, runId, deps) {
|
|
1150
|
+
return downloadFile(baseUrl, apiKey, `/api/open/v1/videos/${encodeURIComponent(runId)}/download`, deps);
|
|
1151
|
+
}
|
|
1152
|
+
async function createDramaOrder(baseUrl, apiKey, body, idempotencyKey, deps) {
|
|
1153
|
+
const reply = await postJson(baseUrl, apiKey, "/api/open/v1/drama/orders", body, idempotencyKey, deps);
|
|
1154
|
+
const view = parseDramaOrder(reply.body);
|
|
1155
|
+
if (!view || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1156
|
+
return { view, raw: reply.body, replayed: reply.status === 200 };
|
|
1157
|
+
}
|
|
1158
|
+
async function getDramaOrder(baseUrl, apiKey, orderId, deps) {
|
|
1159
|
+
const reply = await getJson(baseUrl, apiKey, `/api/open/v1/drama/orders/${encodeURIComponent(orderId)}`, deps);
|
|
1160
|
+
const view = parseDramaOrder(reply.body);
|
|
1161
|
+
if (!view || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1162
|
+
return { view, raw: reply.body, replayed: false };
|
|
1163
|
+
}
|
|
1164
|
+
async function getDramaQuote(baseUrl, apiKey, orderId, deps) {
|
|
1165
|
+
const reply = await getJson(baseUrl, apiKey, `/api/open/v1/drama/orders/${encodeURIComponent(orderId)}/quote`, deps);
|
|
1166
|
+
const view = parseDramaQuote(reply.body);
|
|
1167
|
+
if (!view || !isRecord2(reply.body)) throw unreadableResponse(reply.status);
|
|
1168
|
+
return { view, raw: reply.body };
|
|
1169
|
+
}
|
|
1170
|
+
async function confirmDramaOrder(baseUrl, apiKey, orderId, expectedQuoteHash, idempotencyKey, deps) {
|
|
1171
|
+
const reply = await postJson(
|
|
1172
|
+
baseUrl,
|
|
1173
|
+
apiKey,
|
|
1174
|
+
`/api/open/v1/drama/orders/${encodeURIComponent(orderId)}/confirm`,
|
|
1175
|
+
{ expectedQuoteHash },
|
|
1176
|
+
idempotencyKey,
|
|
1177
|
+
deps
|
|
1178
|
+
);
|
|
1179
|
+
const view = parseDramaOrder(reply.body);
|
|
1180
|
+
const started = isRecord2(reply.body) ? reply.body.productionStarted : void 0;
|
|
1181
|
+
if (!view || !isRecord2(reply.body) || typeof started !== "boolean") throw unreadableResponse(reply.status);
|
|
1182
|
+
return { view, productionStarted: started, raw: reply.body };
|
|
1183
|
+
}
|
|
1184
|
+
async function cancelDramaOrder(baseUrl, apiKey, orderId, idempotencyKey, deps) {
|
|
1185
|
+
const reply = await postJson(
|
|
1186
|
+
baseUrl,
|
|
1187
|
+
apiKey,
|
|
1188
|
+
`/api/open/v1/drama/orders/${encodeURIComponent(orderId)}/cancel`,
|
|
1189
|
+
{},
|
|
1190
|
+
idempotencyKey,
|
|
1191
|
+
deps
|
|
1192
|
+
);
|
|
1193
|
+
const view = parseDramaOrder(reply.body);
|
|
1194
|
+
const canceled = isRecord2(reply.body) ? reply.body.canceled : void 0;
|
|
1195
|
+
if (!view || !isRecord2(reply.body) || typeof canceled !== "boolean") throw unreadableResponse(reply.status);
|
|
1196
|
+
return { view, canceled, raw: reply.body };
|
|
1197
|
+
}
|
|
1198
|
+
async function downloadDramaFilm(baseUrl, apiKey, orderId, deps) {
|
|
1199
|
+
return downloadFile(baseUrl, apiKey, `/api/open/v1/drama/orders/${encodeURIComponent(orderId)}/download`, deps);
|
|
1200
|
+
}
|
|
1201
|
+
var DEFAULT_WAIT_TIMEOUT_MS = 6e5;
|
|
1202
|
+
var FIRST_POLL_INTERVAL_MS = 3e3;
|
|
1203
|
+
var MAX_POLL_INTERVAL_MS = 12e3;
|
|
1204
|
+
var ORDER_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["succeeded", "failed", "canceled"]);
|
|
1205
|
+
var RUN_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["succeeded", "failed", "canceled"]);
|
|
1206
|
+
var RUN_WAITING_FOR_USER_STATUSES = /* @__PURE__ */ new Set(["needs_input", "awaiting_reply", "awaiting_confirmation"]);
|
|
1207
|
+
var DRAMA_TERMINAL_STATUSES = /* @__PURE__ */ new Set(["delivered", "failed", "canceled", "partial"]);
|
|
1208
|
+
var DRAMA_WAITING_FOR_USER_STATUSES = /* @__PURE__ */ new Set(["needs_attention"]);
|
|
1209
|
+
async function awaitTemplateShortOrder(baseUrl, apiKey, start, deps, wait) {
|
|
1210
|
+
let current = start;
|
|
1211
|
+
if (ORDER_TERMINAL_STATUSES.has(current.view.status)) return { value: current, timedOut: false };
|
|
1212
|
+
const deadline = wait.now().getTime() + wait.timeoutMs;
|
|
1213
|
+
let interval = FIRST_POLL_INTERVAL_MS;
|
|
1214
|
+
let said = current.view.status;
|
|
1215
|
+
for (; ; ) {
|
|
1216
|
+
const remaining = deadline - wait.now().getTime();
|
|
1217
|
+
if (remaining <= 0) return { value: current, timedOut: true };
|
|
1218
|
+
await wait.sleep(Math.max(Math.min(interval, remaining), 1));
|
|
1219
|
+
interval = Math.min(Math.ceil(interval * 1.5), MAX_POLL_INTERVAL_MS);
|
|
1220
|
+
current = await getTemplateShortOrder(baseUrl, apiKey, current.view.id, deps);
|
|
1221
|
+
if (current.view.status !== said) {
|
|
1222
|
+
wait.note?.(`\u72B6\u6001\u53D8\u6210 ${current.view.status}`);
|
|
1223
|
+
said = current.view.status;
|
|
1224
|
+
}
|
|
1225
|
+
if (ORDER_TERMINAL_STATUSES.has(current.view.status)) return { value: current, timedOut: false };
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
async function awaitVideoRun(baseUrl, apiKey, start, deps, wait) {
|
|
1229
|
+
let current = start;
|
|
1230
|
+
if (runStopped(current.view.status)) return { value: current, timedOut: false };
|
|
1231
|
+
const deadline = wait.now().getTime() + wait.timeoutMs;
|
|
1232
|
+
let interval = FIRST_POLL_INTERVAL_MS;
|
|
1233
|
+
let said = current.view.status;
|
|
1234
|
+
for (; ; ) {
|
|
1235
|
+
const remaining = deadline - wait.now().getTime();
|
|
1236
|
+
if (remaining <= 0) return { value: current, timedOut: true };
|
|
1237
|
+
const preferred = current.view.pollAfterMs !== null && current.view.pollAfterMs > 0 ? current.view.pollAfterMs : interval;
|
|
1238
|
+
await wait.sleep(Math.max(Math.min(preferred, remaining), 1));
|
|
1239
|
+
interval = Math.min(Math.ceil(interval * 1.5), MAX_POLL_INTERVAL_MS);
|
|
1240
|
+
current = await getVideoRun(baseUrl, apiKey, current.view.rootRunId, deps);
|
|
1241
|
+
if (current.view.status !== said) {
|
|
1242
|
+
wait.note?.(`\u72B6\u6001\u53D8\u6210 ${current.view.status}`);
|
|
1243
|
+
said = current.view.status;
|
|
1244
|
+
}
|
|
1245
|
+
if (runStopped(current.view.status)) return { value: current, timedOut: false };
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
function runStopped(status4) {
|
|
1249
|
+
return RUN_TERMINAL_STATUSES.has(status4) || RUN_WAITING_FOR_USER_STATUSES.has(status4);
|
|
1250
|
+
}
|
|
1251
|
+
async function awaitDramaOrder(baseUrl, apiKey, start, deps, wait) {
|
|
1252
|
+
let current = start;
|
|
1253
|
+
if (dramaStopped(current.view.status)) return { value: current, timedOut: false };
|
|
1254
|
+
const deadline = wait.now().getTime() + wait.timeoutMs;
|
|
1255
|
+
let interval = FIRST_POLL_INTERVAL_MS;
|
|
1256
|
+
let said = current.view.status;
|
|
1257
|
+
for (; ; ) {
|
|
1258
|
+
const remaining = deadline - wait.now().getTime();
|
|
1259
|
+
if (remaining <= 0) return { value: current, timedOut: true };
|
|
1260
|
+
await wait.sleep(Math.max(Math.min(interval, remaining), 1));
|
|
1261
|
+
interval = Math.min(Math.ceil(interval * 1.5), MAX_POLL_INTERVAL_MS);
|
|
1262
|
+
current = await getDramaOrder(baseUrl, apiKey, current.view.id, deps);
|
|
1263
|
+
if (current.view.status !== said) {
|
|
1264
|
+
wait.note?.(`\u72B6\u6001\u53D8\u6210 ${current.view.status}`);
|
|
1265
|
+
said = current.view.status;
|
|
1266
|
+
}
|
|
1267
|
+
if (dramaStopped(current.view.status)) return { value: current, timedOut: false };
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
function dramaStopped(status4) {
|
|
1271
|
+
return DRAMA_TERMINAL_STATUSES.has(status4) || DRAMA_WAITING_FOR_USER_STATUSES.has(status4);
|
|
1272
|
+
}
|
|
616
1273
|
|
|
617
1274
|
// src/credentials.ts
|
|
618
1275
|
import { randomBytes } from "node:crypto";
|
|
@@ -636,8 +1293,8 @@ function nonEmpty3(value) {
|
|
|
636
1293
|
function absoluteOnly(value) {
|
|
637
1294
|
return value !== void 0 && isAbsolute(value) ? value : void 0;
|
|
638
1295
|
}
|
|
639
|
-
function configDirError(
|
|
640
|
-
return new CliError({ code: "CLI_CONFIG_DIR_INVALID", exitCode: EXIT.USAGE, message });
|
|
1296
|
+
function configDirError(message2) {
|
|
1297
|
+
return new CliError({ code: "CLI_CONFIG_DIR_INVALID", exitCode: EXIT.USAGE, message: message2 });
|
|
641
1298
|
}
|
|
642
1299
|
function expandHome(value, io) {
|
|
643
1300
|
if (value === "~") return io.homedir();
|
|
@@ -865,6 +1522,601 @@ async function deleteCredentials(io, warn = SILENT) {
|
|
|
865
1522
|
return removed;
|
|
866
1523
|
}
|
|
867
1524
|
|
|
1525
|
+
// src/resolve.ts
|
|
1526
|
+
async function resolveApiKey({ io, out, baseUrl: flag }) {
|
|
1527
|
+
const explicit = explicitBaseUrl(flag, io.env);
|
|
1528
|
+
const fromEnv = keyFromEnv(io.env);
|
|
1529
|
+
if (fromEnv !== null) {
|
|
1530
|
+
assertKeyFormat(fromEnv);
|
|
1531
|
+
out.protect(fromEnv);
|
|
1532
|
+
return { apiKey: fromEnv, baseUrl: explicit ?? DEFAULT_BASE_URL, source: "env" };
|
|
1533
|
+
}
|
|
1534
|
+
const stored = await readCredentials(io, (line) => out.notice(line));
|
|
1535
|
+
if (!stored) {
|
|
1536
|
+
throw new CliError({
|
|
1537
|
+
code: "CLI_NOT_LOGGED_IN",
|
|
1538
|
+
exitCode: EXIT.AUTH,
|
|
1539
|
+
message: "\u8FD8\u6CA1\u6709\u767B\u5F55\u3002\u5148\u8FD0\u884C buke login\uFF0C\u6216\u8005\u8BBE\u7F6E\u73AF\u5883\u53D8\u91CF BUKE_API_KEY"
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
out.protect(stored.apiKey);
|
|
1543
|
+
if (explicit !== null && explicit !== stored.baseUrl) {
|
|
1544
|
+
throw new CliError({
|
|
1545
|
+
code: "CLI_BASE_URL_MISMATCH",
|
|
1546
|
+
exitCode: EXIT.USAGE,
|
|
1547
|
+
message: `\u672C\u673A\u4FDD\u5B58\u7684\u5BC6\u94A5\u662F\u7ED9 ${stored.baseUrl} \u7528\u7684\uFF0C\u4E0D\u4F1A\u53D1\u5230 ${explicit}\u3002\u8981\u6362\u5730\u5740\u8BF7\u91CD\u65B0\u8FD0\u884C buke login --base-url ${explicit}`
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
return { apiKey: stored.apiKey, baseUrl: stored.baseUrl, source: "file", credentialsPath: credentialsPath(io) };
|
|
1551
|
+
}
|
|
1552
|
+
function keySourceLine(resolved) {
|
|
1553
|
+
return resolved.source === "env" ? "\u5BC6\u94A5\u6765\u81EA\uFF1A\u73AF\u5883\u53D8\u91CF BUKE_API_KEY" : `\u5BC6\u94A5\u6765\u81EA\uFF1A${resolved.credentialsPath}`;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// src/commands/balance.ts
|
|
1557
|
+
async function balance(context) {
|
|
1558
|
+
const { io, out } = context;
|
|
1559
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1560
|
+
const { view, raw } = await getBalance(baseUrl, apiKey, io);
|
|
1561
|
+
out.result(
|
|
1562
|
+
[
|
|
1563
|
+
`\u53EF\u7528\u4F59\u989D\uFF1A${view.available} ${singleLine(view.currency)}`,
|
|
1564
|
+
`\u51BB\u7ED3\u4E2D\uFF1A${view.held} ${singleLine(view.currency)}`,
|
|
1565
|
+
`\u5DF2\u652F\u51FA\uFF1A${view.spent} ${singleLine(view.currency)}`,
|
|
1566
|
+
`\u66F4\u65B0\u65F6\u95F4\uFF1A${singleLine(view.updatedAt)}`
|
|
1567
|
+
],
|
|
1568
|
+
{ balance: raw.balance }
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
// src/commands/shorts.ts
|
|
1573
|
+
import { createHash } from "node:crypto";
|
|
1574
|
+
import { writeFile } from "node:fs/promises";
|
|
1575
|
+
|
|
1576
|
+
// src/commands/shared.ts
|
|
1577
|
+
import { randomUUID } from "node:crypto";
|
|
1578
|
+
import { readFile } from "node:fs/promises";
|
|
1579
|
+
var MAX_PROPS_BYTES = 1024 * 1024;
|
|
1580
|
+
var MAX_IMAGE_BYTES = 64 * 1024 * 1024;
|
|
1581
|
+
function idempotencyKeyOf(values) {
|
|
1582
|
+
const supplied = values["idempotency-key"];
|
|
1583
|
+
if (typeof supplied === "string" && supplied.trim() !== "") return supplied.trim();
|
|
1584
|
+
return randomUUID();
|
|
1585
|
+
}
|
|
1586
|
+
function textOption(values, name2) {
|
|
1587
|
+
const value = values[name2];
|
|
1588
|
+
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
1589
|
+
}
|
|
1590
|
+
function timeoutSecondsOf(values, fallbackSeconds) {
|
|
1591
|
+
const raw = values.timeout;
|
|
1592
|
+
if (raw === void 0) return fallbackSeconds;
|
|
1593
|
+
if (typeof raw !== "string") return fallbackSeconds;
|
|
1594
|
+
const parsed = Number(raw);
|
|
1595
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
1596
|
+
throw usageError(`--timeout \u8981\u662F\u6B63\u6574\u6570\u79D2\u6570\uFF0C\u5199\u7684\u662F ${raw}`);
|
|
1597
|
+
}
|
|
1598
|
+
return parsed;
|
|
1599
|
+
}
|
|
1600
|
+
async function readPropsArgument(io, ref, what) {
|
|
1601
|
+
if (ref === void 0) {
|
|
1602
|
+
throw usageError("\u8981\u7ED9 --props\uFF1A\u4E00\u4E2A JSON \u6587\u4EF6\uFF0C\u6216 - \u8868\u793A\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB");
|
|
1603
|
+
}
|
|
1604
|
+
let text;
|
|
1605
|
+
if (ref === "-") {
|
|
1606
|
+
text = await readStdinAll(io, MAX_PROPS_BYTES, what);
|
|
1607
|
+
} else {
|
|
1608
|
+
let bytes;
|
|
1609
|
+
try {
|
|
1610
|
+
bytes = await readFile(ref);
|
|
1611
|
+
} catch (error) {
|
|
1612
|
+
throw new CliError({
|
|
1613
|
+
code: "CLI_USAGE",
|
|
1614
|
+
exitCode: EXIT.USAGE,
|
|
1615
|
+
message: `${what}\u6587\u4EF6\u8BFB\u4E0D\u4E86\uFF1A${ref}\uFF08${briefReason(error)}\uFF09`
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
if (bytes.byteLength > MAX_PROPS_BYTES) {
|
|
1619
|
+
throw new CliError({ code: "CLI_USAGE", exitCode: EXIT.USAGE, message: `${what}\u6587\u4EF6\u592A\u5927\uFF08\u8D85\u8FC7 1 MiB\uFF09\uFF1A${ref}` });
|
|
1620
|
+
}
|
|
1621
|
+
text = bytes.toString("utf8");
|
|
1622
|
+
}
|
|
1623
|
+
let parsed;
|
|
1624
|
+
try {
|
|
1625
|
+
parsed = JSON.parse(text);
|
|
1626
|
+
} catch {
|
|
1627
|
+
throw usageError(`${what}\u4E0D\u662F\u5408\u6CD5\u7684 JSON`);
|
|
1628
|
+
}
|
|
1629
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
1630
|
+
throw usageError(`${what}\u5E94\u662F\u4E00\u4E2A JSON \u5BF9\u8C61`);
|
|
1631
|
+
}
|
|
1632
|
+
return parsed;
|
|
1633
|
+
}
|
|
1634
|
+
async function readStdinAll(io, maxBytes, what) {
|
|
1635
|
+
const stdin = io.stdin;
|
|
1636
|
+
if (stdin.readableEnded === true) return "";
|
|
1637
|
+
const chunks = [];
|
|
1638
|
+
let size = 0;
|
|
1639
|
+
await new Promise((resolve, reject) => {
|
|
1640
|
+
const toBuffer2 = (chunk) => typeof chunk === "string" ? Buffer.from(chunk, "utf8") : Buffer.from(chunk);
|
|
1641
|
+
const onData = (chunk) => {
|
|
1642
|
+
const piece = toBuffer2(chunk);
|
|
1643
|
+
size += piece.byteLength;
|
|
1644
|
+
if (size > maxBytes) {
|
|
1645
|
+
cleanup();
|
|
1646
|
+
reject(usageError(`${what}\u592A\u5927\uFF08\u8D85\u8FC7 1 MiB\uFF09`));
|
|
1647
|
+
return;
|
|
1648
|
+
}
|
|
1649
|
+
chunks.push(piece);
|
|
1650
|
+
};
|
|
1651
|
+
const onEnd = () => {
|
|
1652
|
+
cleanup();
|
|
1653
|
+
resolve();
|
|
1654
|
+
};
|
|
1655
|
+
const onError = (error) => {
|
|
1656
|
+
cleanup();
|
|
1657
|
+
reject(new CliError({ code: "CLI_USAGE", exitCode: EXIT.USAGE, message: `\u6807\u51C6\u8F93\u5165\u8BFB\u4E0D\u4E86\uFF1A${briefReason(error)}` }));
|
|
1658
|
+
};
|
|
1659
|
+
const cleanup = () => {
|
|
1660
|
+
stdin.removeListener("data", onData);
|
|
1661
|
+
stdin.removeListener("end", onEnd);
|
|
1662
|
+
stdin.removeListener("error", onError);
|
|
1663
|
+
stdin.pause();
|
|
1664
|
+
};
|
|
1665
|
+
stdin.on("data", onData);
|
|
1666
|
+
stdin.on("end", onEnd);
|
|
1667
|
+
stdin.on("error", onError);
|
|
1668
|
+
stdin.resume();
|
|
1669
|
+
});
|
|
1670
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
1671
|
+
}
|
|
1672
|
+
async function readImageFile(path) {
|
|
1673
|
+
let bytes;
|
|
1674
|
+
try {
|
|
1675
|
+
bytes = await readFile(path);
|
|
1676
|
+
} catch (error) {
|
|
1677
|
+
throw new CliError({
|
|
1678
|
+
code: "CLI_USAGE",
|
|
1679
|
+
exitCode: EXIT.USAGE,
|
|
1680
|
+
message: `\u56FE\u7247\u6587\u4EF6\u8BFB\u4E0D\u4E86\uFF1A${path}\uFF08${briefReason(error)}\uFF09`
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
if (bytes.byteLength > MAX_IMAGE_BYTES) {
|
|
1684
|
+
throw new CliError({ code: "CLI_USAGE", exitCode: EXIT.USAGE, message: `\u56FE\u7247\u592A\u5927\uFF08\u8D85\u8FC7 64 MiB\uFF09\uFF1A${path}` });
|
|
1685
|
+
}
|
|
1686
|
+
return { bytes, contentType: sniffImageContentType(bytes) };
|
|
1687
|
+
}
|
|
1688
|
+
function sniffImageContentType(bytes) {
|
|
1689
|
+
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "image/jpeg";
|
|
1690
|
+
if (bytes.length >= 4 && bytes.subarray(0, 4).toString("hex") === "89504e47") return "image/png";
|
|
1691
|
+
if (bytes.length >= 12 && bytes.subarray(0, 4).toString("ascii") === "RIFF" && bytes.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
1692
|
+
return "image/webp";
|
|
1693
|
+
}
|
|
1694
|
+
return void 0;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
// src/commands/shorts.ts
|
|
1698
|
+
var SUBCOMMANDS = "catalog\u3001upload\u3001quote\u3001order\u3001status\u3001download \u548C cancel";
|
|
1699
|
+
async function shorts(context) {
|
|
1700
|
+
const { args } = context;
|
|
1701
|
+
const [subcommand] = args;
|
|
1702
|
+
if (subcommand === void 0) {
|
|
1703
|
+
throw usageError(`shorts \u8981\u8DDF\u4E00\u4E2A\u5B50\u547D\u4EE4\uFF1A${SUBCOMMANDS}`);
|
|
1704
|
+
}
|
|
1705
|
+
if (subcommand === "catalog") return catalog(context);
|
|
1706
|
+
if (subcommand === "upload") return upload(context, args[1]);
|
|
1707
|
+
if (subcommand === "quote") return quote(context);
|
|
1708
|
+
if (subcommand === "order") return order(context);
|
|
1709
|
+
if (subcommand === "status") return status(context, args[1]);
|
|
1710
|
+
if (subcommand === "download") return download(context, args[1]);
|
|
1711
|
+
if (subcommand === "cancel") return cancel(context, args[1]);
|
|
1712
|
+
throw usageError(`\u4E0D\u8BA4\u8BC6\u7684\u5B50\u547D\u4EE4 ${subcommand}\uFF1Ashorts \u7684\u5B50\u547D\u4EE4\u662F ${SUBCOMMANDS}`);
|
|
1713
|
+
}
|
|
1714
|
+
function orderIdOf(raw) {
|
|
1715
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
1716
|
+
throw usageError("\u8981\u7ED9\u8BA2\u5355 id\uFF08shorts order \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
1717
|
+
}
|
|
1718
|
+
return raw.trim();
|
|
1719
|
+
}
|
|
1720
|
+
function templateOf(values) {
|
|
1721
|
+
const templateId = textOption(values, "template");
|
|
1722
|
+
if (templateId === void 0) {
|
|
1723
|
+
throw usageError("\u8981\u7ED9 --template <\u6A21\u677Fid>\uFF08shorts catalog \u5217\u51FA\u7684\uFF09");
|
|
1724
|
+
}
|
|
1725
|
+
return templateId;
|
|
1726
|
+
}
|
|
1727
|
+
function waitControls(io, values, note) {
|
|
1728
|
+
return {
|
|
1729
|
+
timeoutMs: timeoutSecondsOf(values, DEFAULT_WAIT_TIMEOUT_MS / 1e3) * 1e3,
|
|
1730
|
+
now: io.now ?? (() => /* @__PURE__ */ new Date()),
|
|
1731
|
+
sleep: io.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
|
|
1732
|
+
note
|
|
1733
|
+
};
|
|
1734
|
+
}
|
|
1735
|
+
function settleOrder(outcome) {
|
|
1736
|
+
const order2 = outcome.value.view;
|
|
1737
|
+
if (outcome.timedOut) {
|
|
1738
|
+
throw new CliError({
|
|
1739
|
+
code: "CLI_WAIT_TIMEOUT",
|
|
1740
|
+
exitCode: EXIT.WAIT_TIMEOUT,
|
|
1741
|
+
message: `\u7B49\u4E86\u8FD9\u4E48\u4E45\u8FD8\u5728 ${order2.status}\uFF1A\u518D\u67E5\u7528 buke shorts status ${order2.id}\uFF0C\u6216\u52A0 --timeout \u5EF6\u957F\u7B49\u5F85`
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
if (order2.status === "failed" || order2.status === "canceled") {
|
|
1745
|
+
throw new CliError({
|
|
1746
|
+
code: "CLI_TASK_FAILED",
|
|
1747
|
+
exitCode: EXIT.TASK_FAILED,
|
|
1748
|
+
message: order2.error === void 0 ? `\u8FD9\u6761\u77ED\u7247${order2.status === "canceled" ? "\u5DF2\u53D6\u6D88" : "\u6CA1\u6709\u6E32\u67D3\u6210\u529F"}` : singleLine(order2.error)
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
return outcome.value;
|
|
1752
|
+
}
|
|
1753
|
+
function orderLines(order2) {
|
|
1754
|
+
return [
|
|
1755
|
+
`\u8BA2\u5355\uFF1A${singleLine(order2.id)}`,
|
|
1756
|
+
`\u72B6\u6001\uFF1A${singleLine(order2.status)}`,
|
|
1757
|
+
`\u6A21\u677F\uFF1A${singleLine(order2.templateTitle)}\uFF08${singleLine(order2.templateId)}\uFF09`,
|
|
1758
|
+
`\u521B\u5EFA\u4E8E\uFF1A${singleLine(order2.createdAt)}`,
|
|
1759
|
+
...order2.durationSeconds !== void 0 ? [`\u65F6\u957F\uFF1A${order2.durationSeconds} \u79D2`] : [],
|
|
1760
|
+
...order2.status === "succeeded" && order2.videoUrl !== void 0 ? [`\u6210\u7247\u5730\u5740\uFF1A${singleLine(order2.videoUrl)}`] : [],
|
|
1761
|
+
...order2.bytes !== void 0 ? [`\u5927\u5C0F\uFF1A${order2.bytes} \u5B57\u8282`] : []
|
|
1762
|
+
];
|
|
1763
|
+
}
|
|
1764
|
+
async function catalog(context) {
|
|
1765
|
+
const { io, out } = context;
|
|
1766
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1767
|
+
const { view, raw } = await getTemplateShortCatalog(baseUrl, apiKey, io);
|
|
1768
|
+
out.result(
|
|
1769
|
+
[
|
|
1770
|
+
`${singleLine(view.category.name)}\uFF08${singleLine(view.category.badge)}\uFF0C\u5171 ${view.templates.length} \u4E2A\u6A21\u677F\uFF09`,
|
|
1771
|
+
...view.templates.map(
|
|
1772
|
+
(template) => `${template.id} ${singleLine(template.title)}\uFF08${singleLine(template.tier)}\uFF0C${template.durationSeconds} \u79D2\uFF09
|
|
1773
|
+
${template.summary}${template.needs.length > 0 ? `\uFF1B\u9700\u8981\uFF1A${template.needs.join("\u3001")}` : ""}`
|
|
1774
|
+
)
|
|
1775
|
+
],
|
|
1776
|
+
// --json 按文档回服务端那份完整的 catalog:slots、defaultProps 都在内。
|
|
1777
|
+
{ catalog: raw.catalog }
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
async function upload(context, rawPath) {
|
|
1781
|
+
const { io, out } = context;
|
|
1782
|
+
if (rawPath === void 0 || rawPath.trim() === "") {
|
|
1783
|
+
throw usageError("\u8981\u7ED9\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84");
|
|
1784
|
+
}
|
|
1785
|
+
const image = await readImageFile(rawPath);
|
|
1786
|
+
const idempotencyKey = idempotencyKeyOf(context.values);
|
|
1787
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1788
|
+
const { view, raw } = await uploadTemplateShortAsset(baseUrl, apiKey, image.bytes, image.contentType, idempotencyKey, io);
|
|
1789
|
+
out.result(
|
|
1790
|
+
[
|
|
1791
|
+
`\u5DF2\u4E0A\u4F20\uFF1A${singleLine(view.url)}`,
|
|
1792
|
+
`\u6821\u9A8C\uFF1Asha256 ${view.sha256}\uFF08${view.bytes} \u5B57\u8282\uFF09`,
|
|
1793
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`
|
|
1794
|
+
],
|
|
1795
|
+
{ upload: raw, idempotencyKey }
|
|
1796
|
+
);
|
|
1797
|
+
}
|
|
1798
|
+
async function quote(context) {
|
|
1799
|
+
const { io, out, values } = context;
|
|
1800
|
+
const templateId = templateOf(values);
|
|
1801
|
+
const props = await readPropsArgument(io, textOption(values, "props"), "\u6A21\u677F\u53C2\u6570\uFF08--props\uFF09");
|
|
1802
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
1803
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1804
|
+
const { view, raw } = await quoteTemplateShort(baseUrl, apiKey, templateId, props, idempotencyKey, io);
|
|
1805
|
+
out.result(
|
|
1806
|
+
[
|
|
1807
|
+
`\u6A21\u677F\uFF1A${singleLine(view.templateId)}\uFF0C\u65F6\u957F ${Math.round(view.durationMilliseconds / 100) / 10} \u79D2`,
|
|
1808
|
+
`\u62A5\u4EF7\uFF1A${view.credits} \u5E03\uFF08\u4F1A\u5458\u65F6\u957F\u5185 ${Math.round(view.memberMilliseconds / 100) / 10} \u79D2\uFF0C\u8D85\u51FA ${Math.round(view.excessMilliseconds / 100) / 10} \u79D2\uFF09`,
|
|
1809
|
+
`\u62A5\u4EF7\u54C8\u5E0C\uFF1A${view.quoteHash}`,
|
|
1810
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`,
|
|
1811
|
+
`\u4E0B\u5355\u65F6\u5E26\u4E0A --quote-hash ${view.quoteHash} \u548C\u540C\u4E00\u628A --idempotency-key ${idempotencyKey}\uFF08\u62A5\u4EF7\u54C8\u5E0C\u548C\u5E42\u7B49\u952E\u7ED1\u5B9A\uFF0C\u6362\u4E00\u628A\u5C31\u5BF9\u4E0D\u4E0A\uFF09`
|
|
1812
|
+
],
|
|
1813
|
+
{ quote: raw.quote, idempotencyKey }
|
|
1814
|
+
);
|
|
1815
|
+
}
|
|
1816
|
+
async function order(context) {
|
|
1817
|
+
const { io, out, values } = context;
|
|
1818
|
+
const templateId = templateOf(values);
|
|
1819
|
+
const props = await readPropsArgument(io, textOption(values, "props"), "\u6A21\u677F\u53C2\u6570\uFF08--props\uFF09");
|
|
1820
|
+
const quoteHash = textOption(values, "quote-hash");
|
|
1821
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
1822
|
+
const shouldWait = values.wait === true;
|
|
1823
|
+
const controls = shouldWait ? waitControls(io, values, (line) => out.notice(line)) : void 0;
|
|
1824
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1825
|
+
const accepted = await createTemplateShortOrder(baseUrl, apiKey, templateId, props, quoteHash, idempotencyKey, io);
|
|
1826
|
+
const final = shouldWait ? settleOrder(await awaitTemplateShortOrder(baseUrl, apiKey, accepted, io, controls)) : accepted;
|
|
1827
|
+
out.result([...orderLines(final.view), `\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`], {
|
|
1828
|
+
order: final.raw.order,
|
|
1829
|
+
idempotencyKey,
|
|
1830
|
+
...shouldWait ? { waited: true } : {}
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
async function status(context, rawId) {
|
|
1834
|
+
const { io, out, values } = context;
|
|
1835
|
+
const orderId = orderIdOf(rawId);
|
|
1836
|
+
const shouldWait = values.wait === true;
|
|
1837
|
+
const controls = shouldWait ? waitControls(io, values, (line) => out.notice(line)) : void 0;
|
|
1838
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1839
|
+
const current = await getTemplateShortOrder(baseUrl, apiKey, orderId, io);
|
|
1840
|
+
const final = shouldWait ? settleOrder(await awaitTemplateShortOrder(baseUrl, apiKey, current, io, controls)) : current;
|
|
1841
|
+
out.result(orderLines(final.view), { order: final.raw.order, ...shouldWait ? { waited: true } : {} });
|
|
1842
|
+
}
|
|
1843
|
+
async function cancel(context, rawId) {
|
|
1844
|
+
const { io, out, values } = context;
|
|
1845
|
+
const orderId = orderIdOf(rawId);
|
|
1846
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
1847
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1848
|
+
const canceled = await cancelTemplateShortOrder(baseUrl, apiKey, orderId, idempotencyKey, io);
|
|
1849
|
+
out.result([...orderLines(canceled.view), `\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`], { order: canceled.raw.order, idempotencyKey });
|
|
1850
|
+
}
|
|
1851
|
+
async function download(context, rawId) {
|
|
1852
|
+
const { io, out, values } = context;
|
|
1853
|
+
const orderId = orderIdOf(rawId);
|
|
1854
|
+
const defaultName = `template-short-${orderId}.mp4`;
|
|
1855
|
+
const target = textOption(values, "out") ?? defaultName;
|
|
1856
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
1857
|
+
const result = await downloadTemplateShort(baseUrl, apiKey, orderId, io);
|
|
1858
|
+
const saved = await saveDownload(target, result.bytes);
|
|
1859
|
+
out.result(
|
|
1860
|
+
[`\u5DF2\u4E0B\u8F7D\uFF1A${saved.path}`, `\u5927\u5C0F\uFF1A${saved.bytes} \u5B57\u8282`, `\u6821\u9A8C\uFF1Asha256 ${saved.sha256}`],
|
|
1861
|
+
{ download: { ...saved, filename: result.filename ?? defaultName } }
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
async function saveDownload(target, bytes) {
|
|
1865
|
+
try {
|
|
1866
|
+
await writeFile(target, bytes);
|
|
1867
|
+
} catch (error) {
|
|
1868
|
+
throw new CliError({
|
|
1869
|
+
code: "CLI_INTERNAL",
|
|
1870
|
+
exitCode: EXIT.SERVER,
|
|
1871
|
+
message: `\u6210\u7247\u5199\u4E0D\u8FDB ${target}\uFF08${briefReason(error)}\uFF09`
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
return { path: target, bytes: bytes.byteLength, sha256: createHash("sha256").update(bytes).digest("hex") };
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
// src/commands/drama.ts
|
|
1878
|
+
var SUBCOMMANDS2 = "create\u3001status\u3001quote\u3001confirm\u3001cancel \u548C download";
|
|
1879
|
+
var DURATION_KEYS = ["30s", "60s", "90s"];
|
|
1880
|
+
async function drama(context) {
|
|
1881
|
+
const { args } = context;
|
|
1882
|
+
const [subcommand] = args;
|
|
1883
|
+
if (subcommand === void 0) {
|
|
1884
|
+
throw usageError(`drama \u8981\u8DDF\u4E00\u4E2A\u5B50\u547D\u4EE4\uFF1A${SUBCOMMANDS2}`);
|
|
1885
|
+
}
|
|
1886
|
+
if (subcommand === "create") return create(context);
|
|
1887
|
+
if (subcommand === "status") return status2(context, args[1]);
|
|
1888
|
+
if (subcommand === "quote") return quote2(context, args[1]);
|
|
1889
|
+
if (subcommand === "confirm") return confirm(context, args[1]);
|
|
1890
|
+
if (subcommand === "cancel") return cancel2(context, args[1]);
|
|
1891
|
+
if (subcommand === "download") return download2(context, args[1]);
|
|
1892
|
+
throw usageError(`\u4E0D\u8BA4\u8BC6\u7684\u5B50\u547D\u4EE4 ${subcommand}\uFF1Adrama \u7684\u5B50\u547D\u4EE4\u662F ${SUBCOMMANDS2}`);
|
|
1893
|
+
}
|
|
1894
|
+
function orderIdOf2(raw) {
|
|
1895
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
1896
|
+
throw usageError("\u8981\u7ED9\u8BA2\u5355 id\uFF08drama create \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
1897
|
+
}
|
|
1898
|
+
return raw.trim();
|
|
1899
|
+
}
|
|
1900
|
+
function waitControls2(io, values, note) {
|
|
1901
|
+
return {
|
|
1902
|
+
timeoutMs: timeoutSecondsOf(values, DEFAULT_WAIT_TIMEOUT_MS / 1e3) * 1e3,
|
|
1903
|
+
now: io.now ?? (() => /* @__PURE__ */ new Date()),
|
|
1904
|
+
sleep: io.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms))),
|
|
1905
|
+
note
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
function settleOrder2(outcome) {
|
|
1909
|
+
const order2 = outcome.value.view;
|
|
1910
|
+
if (outcome.timedOut) {
|
|
1911
|
+
throw new CliError({
|
|
1912
|
+
code: "CLI_WAIT_TIMEOUT",
|
|
1913
|
+
exitCode: EXIT.WAIT_TIMEOUT,
|
|
1914
|
+
message: `\u7B49\u4E86\u8FD9\u4E48\u4E45\u8FD8\u5728 ${order2.status}\uFF1A\u518D\u67E5\u7528 buke drama status ${order2.id}\uFF0C\u6216\u52A0 --timeout \u5EF6\u957F\u7B49\u5F85`
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
if (order2.status === "failed") {
|
|
1918
|
+
throw new CliError({
|
|
1919
|
+
code: "CLI_TASK_FAILED",
|
|
1920
|
+
exitCode: EXIT.TASK_FAILED,
|
|
1921
|
+
message: order2.reason === void 0 || order2.reason.trim() === "" ? "\u8FD9\u5355\u77ED\u5267\u6CA1\u6709\u62CD\u6210" : singleLine(order2.reason)
|
|
1922
|
+
});
|
|
1923
|
+
}
|
|
1924
|
+
if (order2.status === "canceled") {
|
|
1925
|
+
throw new CliError({
|
|
1926
|
+
code: "CLI_TASK_FAILED",
|
|
1927
|
+
exitCode: EXIT.TASK_FAILED,
|
|
1928
|
+
message: "\u8FD9\u5355\u77ED\u5267\u5DF2\u53D6\u6D88\uFF1A\u6CA1\u62CD\u7684\u955C\u5934\u9000\u56DE\u51BB\u7ED3\u989D\u5EA6\uFF0C\u5DF2\u7ECF\u62CD\u6210\u7684\u4FDD\u7559\u7167\u6263"
|
|
1929
|
+
});
|
|
1930
|
+
}
|
|
1931
|
+
return outcome.value;
|
|
1932
|
+
}
|
|
1933
|
+
function orderLines2(order2) {
|
|
1934
|
+
const money = order2.money;
|
|
1935
|
+
const extra = [];
|
|
1936
|
+
if (money.released > 0) extra.push(`\u5DF2\u91CA\u653E ${money.released} ${money.currency}`);
|
|
1937
|
+
if (money.refunded > 0) extra.push(`\u5DF2\u9000\u6B3E ${money.refunded} ${money.currency}`);
|
|
1938
|
+
return [
|
|
1939
|
+
`\u8BA2\u5355\uFF1A${singleLine(order2.id)}`,
|
|
1940
|
+
`\u72B6\u6001\uFF1A${singleLine(order2.status)}`,
|
|
1941
|
+
`\u4EA7\u54C1\uFF1A${singleLine(order2.productId)}\uFF08\u9898\u6750 ${singleLine(order2.genreId)}\uFF0C\u4F53\u91CF ${singleLine(order2.durationKey)}\uFF09`,
|
|
1942
|
+
`\u66F4\u65B0\u65F6\u95F4\uFF1A${singleLine(order2.updatedAt)}`,
|
|
1943
|
+
`\u8D26\uFF1A\u51BB\u7ED3 ${money.held} ${money.currency}\uFF0C\u5DF2\u7ED3\u7B97 ${money.settled} ${money.currency}` + (extra.length > 0 ? `\uFF08${extra.join("\uFF0C")}\uFF09` : "")
|
|
1944
|
+
];
|
|
1945
|
+
}
|
|
1946
|
+
function guidanceLines(order2) {
|
|
1947
|
+
const lines = [];
|
|
1948
|
+
if (order2.reason !== void 0 && order2.reason.trim() !== "") {
|
|
1949
|
+
const label = order2.status === "failed" ? "\u5931\u8D25\u539F\u56E0" : order2.status === "partial" ? "\u6CA1\u62CD\u5B8C\u7684\u90E8\u5206" : "\u505C\u9760\u539F\u56E0";
|
|
1950
|
+
lines.push(`${label}\uFF1A${singleLine(order2.reason)}`);
|
|
1951
|
+
}
|
|
1952
|
+
for (const gap of order2.gaps ?? []) {
|
|
1953
|
+
const kind = gap.kind === "character" ? "\u89D2\u8272" : gap.kind === "scene" ? "\u573A\u666F" : "\u7D20\u6750";
|
|
1954
|
+
const scenes = gap.sceneNos.length > 0 ? `\uFF0C\u51FA\u73B0\u5728\u7B2C ${gap.sceneNos.join("\u3001")} \u955C` : "";
|
|
1955
|
+
lines.push(`\u7F3A\u53E3\uFF1A${kind}\u300C${singleLine(gap.label !== "" ? gap.label : gap.key)}\u300D\u8FD8\u6CA1\u7ED1\u5B9A${scenes}`);
|
|
1956
|
+
}
|
|
1957
|
+
const next = nextStepOf(order2);
|
|
1958
|
+
return next === null ? lines : [...lines, next];
|
|
1959
|
+
}
|
|
1960
|
+
function nextStepOf(order2) {
|
|
1961
|
+
switch (order2.status) {
|
|
1962
|
+
case "preparing":
|
|
1963
|
+
return `\u4E0B\u4E00\u6B65\uFF1A\u7B49\u5199\u7A3F\u4E0E\u6392\u7248\u8DD1\u5B8C\uFF0C\u91CD\u65B0\u67E5\u8BE2\uFF1Abuke drama status ${order2.id}`;
|
|
1964
|
+
case "needs_attention":
|
|
1965
|
+
return `\u4E0B\u4E00\u6B65\uFF1A\u6309\u4E0A\u9762\u7684\u63D0\u793A\u5728 Studio \u6253\u5F00\u8FD9\u90E8\u77ED\u5267\u5904\u7406\uFF0C\u5904\u7406\u5B8C\u91CD\u65B0\u67E5\u8BE2\uFF1Abuke drama status ${order2.id}`;
|
|
1966
|
+
case "quotable":
|
|
1967
|
+
return `\u4E0B\u4E00\u6B65\uFF1A\u770B\u62A5\u4EF7\uFF1Abuke drama quote ${order2.id}\uFF0C\u518D\u786E\u8BA4\u5F00\u62CD\uFF1Abuke drama confirm ${order2.id} --quote-hash <\u62A5\u4EF7\u54C8\u5E0C>`;
|
|
1968
|
+
case "producing":
|
|
1969
|
+
case "stitching":
|
|
1970
|
+
return `\u4E0B\u4E00\u6B65\uFF1A\u7B49\u5B83\u62CD\u5B8C\uFF1Abuke drama status ${order2.id} --wait`;
|
|
1971
|
+
case "partial":
|
|
1972
|
+
return `\u4E0B\u4E00\u6B65\uFF1A\u53EA\u8865\u7F3A\u7684\u955C\u5934\uFF1Abuke drama confirm ${order2.id} --quote-hash <\u62A5\u4EF7\u54C8\u5E0C>\uFF1B\u4E0D\u8981\u4E86\uFF1Abuke drama cancel ${order2.id}`;
|
|
1973
|
+
case "delivered":
|
|
1974
|
+
return `\u4E0B\u8F7D\uFF1Abuke drama download ${order2.id}`;
|
|
1975
|
+
default:
|
|
1976
|
+
return null;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
function sufficientLine(sufficient) {
|
|
1980
|
+
if (sufficient === true) return "\u591F\u8FD9\u4E00\u5355";
|
|
1981
|
+
if (sufficient === false) return "\u4E0D\u591F\u8FD9\u4E00\u5355";
|
|
1982
|
+
return "\u6682\u65F6\u7B97\u4E0D\u51FA\u6765";
|
|
1983
|
+
}
|
|
1984
|
+
function quoteLines(orderId, quote3) {
|
|
1985
|
+
const price = [`\u603B\u4EF7 ${quote3.totalCredits} \u5E03`, `${quote3.shotCount} \u4E2A\u955C\u5934`];
|
|
1986
|
+
if (quote3.shotCreditCost !== void 0) price.push(`\u6BCF\u955C ${quote3.shotCreditCost} \u5E03`);
|
|
1987
|
+
const spec = [quote3.videoModel, quote3.resolution].filter((entry) => entry !== void 0);
|
|
1988
|
+
return [
|
|
1989
|
+
`\u62A5\u4EF7\uFF1A${price.join("\uFF0C")}`,
|
|
1990
|
+
...spec.length > 0 ? [`\u6863\u4F4D\uFF1A${spec.join(" / ")}`] : [],
|
|
1991
|
+
`\u62A5\u4EF7\u54C8\u5E0C\uFF1A${quote3.quoteHash}`,
|
|
1992
|
+
`\u4F59\u989D\uFF1A${sufficientLine(quote3.sufficient)}`,
|
|
1993
|
+
`\u786E\u8BA4\u5F00\u62CD\uFF1Abuke drama confirm ${orderId} --quote-hash ${quote3.quoteHash}`
|
|
1994
|
+
];
|
|
1995
|
+
}
|
|
1996
|
+
async function create(context) {
|
|
1997
|
+
const { io, out, values } = context;
|
|
1998
|
+
const productId = textOption(values, "product");
|
|
1999
|
+
if (productId === void 0) {
|
|
2000
|
+
throw usageError("\u8981\u7ED9 --product <\u4EA7\u54C1id>\uFF08buke products create \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
2001
|
+
}
|
|
2002
|
+
const genreId = textOption(values, "genre");
|
|
2003
|
+
const durationKey = textOption(values, "duration");
|
|
2004
|
+
if (durationKey !== void 0 && !DURATION_KEYS.includes(durationKey)) {
|
|
2005
|
+
throw usageError(`--duration \u53EA\u80FD\u662F ${DURATION_KEYS.join("\u3001")}\uFF0C\u5199\u7684\u662F ${durationKey}`);
|
|
2006
|
+
}
|
|
2007
|
+
const briefRef = textOption(values, "brief");
|
|
2008
|
+
const brief = briefRef === void 0 ? void 0 : await readPropsArgument(io, briefRef, "\u6545\u4E8B\u8BBE\u5B9A\uFF08--brief\uFF09");
|
|
2009
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2010
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2011
|
+
const created = await createDramaOrder(
|
|
2012
|
+
baseUrl,
|
|
2013
|
+
apiKey,
|
|
2014
|
+
{
|
|
2015
|
+
productId,
|
|
2016
|
+
...genreId === void 0 ? {} : { genreId },
|
|
2017
|
+
...durationKey === void 0 ? {} : { durationKey },
|
|
2018
|
+
...brief === void 0 ? {} : { brief }
|
|
2019
|
+
},
|
|
2020
|
+
idempotencyKey,
|
|
2021
|
+
io
|
|
2022
|
+
);
|
|
2023
|
+
out.result(
|
|
2024
|
+
[...orderLines2(created.view), `\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`, `\u67E5\u8FDB\u5EA6\uFF1Abuke drama status ${created.view.id}`],
|
|
2025
|
+
// --json 按文档回服务端那份完整的 order;replayed 说明这次是新建还是同键重放。
|
|
2026
|
+
{ order: created.raw.order, replayed: created.replayed, idempotencyKey }
|
|
2027
|
+
);
|
|
2028
|
+
}
|
|
2029
|
+
async function status2(context, rawId) {
|
|
2030
|
+
const { io, out, values } = context;
|
|
2031
|
+
const orderId = orderIdOf2(rawId);
|
|
2032
|
+
const shouldWait = values.wait === true;
|
|
2033
|
+
const controls = shouldWait ? waitControls2(io, values, (line) => out.notice(line)) : void 0;
|
|
2034
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2035
|
+
const current = await getDramaOrder(baseUrl, apiKey, orderId, io);
|
|
2036
|
+
const final = shouldWait ? settleOrder2(await awaitDramaOrder(baseUrl, apiKey, current, io, controls)) : current;
|
|
2037
|
+
out.result([...orderLines2(final.view), ...guidanceLines(final.view)], {
|
|
2038
|
+
order: final.raw.order,
|
|
2039
|
+
...shouldWait ? { waited: true } : {}
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
async function quote2(context, rawId) {
|
|
2043
|
+
const { io, out } = context;
|
|
2044
|
+
const orderId = orderIdOf2(rawId);
|
|
2045
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2046
|
+
const { view, raw } = await getDramaQuote(baseUrl, apiKey, orderId, io);
|
|
2047
|
+
out.result(quoteLines(orderId, view), { quote: raw.quote, quoteHash: view.quoteHash, sufficient: view.sufficient });
|
|
2048
|
+
}
|
|
2049
|
+
async function confirm(context, rawId) {
|
|
2050
|
+
const { io, out, values } = context;
|
|
2051
|
+
const orderId = orderIdOf2(rawId);
|
|
2052
|
+
const quoteHash = textOption(values, "quote-hash");
|
|
2053
|
+
if (quoteHash === void 0) {
|
|
2054
|
+
throw usageError("\u8981\u7ED9 --quote-hash <\u62A5\u4EF7\u54C8\u5E0C>\uFF08buke drama quote \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
2055
|
+
}
|
|
2056
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2057
|
+
const current = await getDramaOrder(baseUrl, apiKey, orderId, io);
|
|
2058
|
+
const quoted = current.view.status === "quotable" ? await getDramaQuote(baseUrl, apiKey, orderId, io) : null;
|
|
2059
|
+
if (values.yes !== true) {
|
|
2060
|
+
if (!out.json) {
|
|
2061
|
+
out.result(
|
|
2062
|
+
quoted === null ? [`\u8FD9\u5355\u73B0\u5728\u4E0D\u662F\u53EF\u62A5\u4EF7\u72B6\u6001\uFF08${singleLine(current.view.status)}\uFF09\uFF1A\u6CA1\u6709\u5F53\u524D\u62A5\u4EF7\u53EF\u770B\uFF0C\u786E\u8BA4\u4F1A\u6309\u4F60\u5E26\u6765\u7684\u62A5\u4EF7\u54C8\u5E0C\u63D0\u4EA4`] : quoteLines(orderId, quoted.view),
|
|
2063
|
+
void 0
|
|
2064
|
+
);
|
|
2065
|
+
}
|
|
2066
|
+
throw new CliError({
|
|
2067
|
+
code: "CLI_USAGE",
|
|
2068
|
+
exitCode: EXIT.USAGE,
|
|
2069
|
+
message: quoted === null ? "\u52A0 --yes \u6309\u4F60\u5E26\u6765\u7684\u62A5\u4EF7\u54C8\u5E0C\u63D0\u4EA4\u8FD9\u6B21\u786E\u8BA4" : `\u8FD9\u4E00\u5355\u73B0\u5728\u62A5\u4EF7 ${quoted.view.totalCredits} \u5E03\u3002\u52A0 --yes \u786E\u8BA4\u8FD9\u7B14\u5E03\u652F\u51FA`,
|
|
2070
|
+
hints: [`\u770B\u8FC7\u518D\u786E\u8BA4\uFF1Abuke drama status ${orderId}`]
|
|
2071
|
+
});
|
|
2072
|
+
}
|
|
2073
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2074
|
+
const confirmed = await confirmDramaOrder(baseUrl, apiKey, orderId, quoteHash, idempotencyKey, io);
|
|
2075
|
+
out.result(
|
|
2076
|
+
[
|
|
2077
|
+
...orderLines2(confirmed.view),
|
|
2078
|
+
confirmed.productionStarted ? quoted === null ? "\u5DF2\u786E\u8BA4\uFF1A\u6309\u539F\u6765\u6536\u4E0B\u7684\u62A5\u4EF7\u8865\u62CD\u7F3A\u7684\u955C\u5934" : `\u5DF2\u786E\u8BA4\uFF1A\u8FD9\u7B14\u6700\u591A ${quoted.view.totalCredits} \u5E03` : "\u5DF2\u786E\u8BA4\uFF1A\u8FD9\u6B21\u6CA1\u6709\u5F00\u65B0\u4EFB\u52A1\uFF08\u5B83\u53EF\u80FD\u5DF2\u7ECF\u5728\u62CD\uFF0C\u6216\u5DF2\u7ECF\u62CD\u597D\u7B49\u62FC\u63A5\uFF09",
|
|
2079
|
+
...guidanceLines(confirmed.view),
|
|
2080
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`
|
|
2081
|
+
],
|
|
2082
|
+
{
|
|
2083
|
+
order: confirmed.raw.order,
|
|
2084
|
+
productionStarted: confirmed.productionStarted,
|
|
2085
|
+
// 计价的那一份:可报价时是刚取回的报价;续拍按原签字走,没有当前报价。
|
|
2086
|
+
confirmed: { totalCredits: quoted === null ? null : quoted.view.totalCredits, quoteHash },
|
|
2087
|
+
idempotencyKey
|
|
2088
|
+
}
|
|
2089
|
+
);
|
|
2090
|
+
}
|
|
2091
|
+
async function cancel2(context, rawId) {
|
|
2092
|
+
const { io, out, values } = context;
|
|
2093
|
+
const orderId = orderIdOf2(rawId);
|
|
2094
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2095
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2096
|
+
const canceled = await cancelDramaOrder(baseUrl, apiKey, orderId, idempotencyKey, io);
|
|
2097
|
+
out.result(
|
|
2098
|
+
[
|
|
2099
|
+
...orderLines2(canceled.view),
|
|
2100
|
+
canceled.canceled ? "\u5DF2\u53D6\u6D88\uFF1A\u6CA1\u62CD\u7684\u955C\u5934\u9000\u56DE\u51BB\u7ED3\u989D\u5EA6\uFF0C\u5DF2\u7ECF\u62CD\u6210\u7684\u4FDD\u7559\u7167\u6263" : "\u8FD9\u5355\u4E4B\u524D\u5DF2\u7ECF\u53D6\u6D88\u8FC7\uFF0C\u6CA1\u6709\u518D\u53D6\u6D88\u4E00\u6B21",
|
|
2101
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`
|
|
2102
|
+
],
|
|
2103
|
+
{ order: canceled.raw.order, canceled: canceled.canceled, idempotencyKey }
|
|
2104
|
+
);
|
|
2105
|
+
}
|
|
2106
|
+
async function download2(context, rawId) {
|
|
2107
|
+
const { io, out, values } = context;
|
|
2108
|
+
const orderId = orderIdOf2(rawId);
|
|
2109
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2110
|
+
const result = await downloadDramaFilm(baseUrl, apiKey, orderId, io);
|
|
2111
|
+
const defaultName = result.filename ?? `drama-${orderId}.mp4`;
|
|
2112
|
+
const target = textOption(values, "out") ?? defaultName;
|
|
2113
|
+
const saved = await saveDownload(target, result.bytes);
|
|
2114
|
+
out.result(
|
|
2115
|
+
[`\u5DF2\u4E0B\u8F7D\uFF1A${saved.path}`, `\u5927\u5C0F\uFF1A${saved.bytes} \u5B57\u8282`, `\u6821\u9A8C\uFF1Asha256 ${saved.sha256}`],
|
|
2116
|
+
{ download: { ...saved, filename: defaultName } }
|
|
2117
|
+
);
|
|
2118
|
+
}
|
|
2119
|
+
|
|
868
2120
|
// src/output.ts
|
|
869
2121
|
function errorDocument(error) {
|
|
870
2122
|
const document = {
|
|
@@ -996,36 +2248,330 @@ async function logout({ io, out }) {
|
|
|
996
2248
|
}
|
|
997
2249
|
}
|
|
998
2250
|
|
|
999
|
-
// src/commands/
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
const
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
return { apiKey: fromEnv, baseUrl: explicit ?? DEFAULT_BASE_URL, source: "env" };
|
|
2251
|
+
// src/commands/products.ts
|
|
2252
|
+
var PRODUCT_ANGLES = ["front", "side", "back", "detail"];
|
|
2253
|
+
async function products(context) {
|
|
2254
|
+
const { args, values } = context;
|
|
2255
|
+
const [subcommand] = args;
|
|
2256
|
+
if (subcommand === void 0) {
|
|
2257
|
+
throw usageError("products \u8981\u8DDF\u4E00\u4E2A\u5B50\u547D\u4EE4\uFF1Acreate\u3001set-images \u6216 confirm-lock");
|
|
1007
2258
|
}
|
|
1008
|
-
|
|
1009
|
-
if (
|
|
2259
|
+
if (subcommand === "create") return create2(context, values);
|
|
2260
|
+
if (subcommand === "set-images") return setImages(context, values, args[1]);
|
|
2261
|
+
if (subcommand === "confirm-lock") return confirmLock(context, values, args[1]);
|
|
2262
|
+
throw usageError(`\u4E0D\u8BA4\u8BC6\u7684\u5B50\u547D\u4EE4 ${subcommand}\uFF1Aproducts \u7684\u5B50\u547D\u4EE4\u662F create\u3001set-images \u548C confirm-lock`);
|
|
2263
|
+
}
|
|
2264
|
+
function productIdOf(raw, what) {
|
|
2265
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
2266
|
+
throw usageError(`\u8981\u7ED9${what}`);
|
|
2267
|
+
}
|
|
2268
|
+
return raw.trim();
|
|
2269
|
+
}
|
|
2270
|
+
async function create2(context, values) {
|
|
2271
|
+
const { io, out } = context;
|
|
2272
|
+
const name2 = textOption(values, "name");
|
|
2273
|
+
if (name2 === void 0) {
|
|
2274
|
+
throw usageError("\u8981\u7ED9 --name <\u540D\u79F0>");
|
|
2275
|
+
}
|
|
2276
|
+
const category = textOption(values, "category");
|
|
2277
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2278
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2279
|
+
const { view, raw, replayed } = await createProduct(baseUrl, apiKey, name2, category, idempotencyKey, io);
|
|
2280
|
+
out.result(
|
|
2281
|
+
[
|
|
2282
|
+
replayed ? `\u4EA7\u54C1\u5DF2\u5B58\u5728\uFF1A${singleLine(view.id)}\uFF08\u540C\u952E\u91CD\u653E\uFF09` : `\u5DF2\u521B\u5EFA\u4EA7\u54C1\uFF1A${singleLine(view.id)}`,
|
|
2283
|
+
`\u540D\u79F0\uFF1A${singleLine(view.name)}`,
|
|
2284
|
+
`\u7C7B\u76EE\uFF1A${singleLine(view.category)}`,
|
|
2285
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`
|
|
2286
|
+
],
|
|
2287
|
+
{ product: raw.product, replayed, idempotencyKey }
|
|
2288
|
+
);
|
|
2289
|
+
}
|
|
2290
|
+
async function setImages(context, values, rawId) {
|
|
2291
|
+
const { io, out } = context;
|
|
2292
|
+
const productId = productIdOf(rawId, "\u4EA7\u54C1 id\uFF08buke products create \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
2293
|
+
const planned = [];
|
|
2294
|
+
for (const angle of PRODUCT_ANGLES) {
|
|
2295
|
+
const path = textOption(values, angle);
|
|
2296
|
+
if (path !== void 0) planned.push({ angle, path });
|
|
2297
|
+
}
|
|
2298
|
+
if (planned.length === 0) {
|
|
2299
|
+
throw usageError("\u81F3\u5C11\u7ED9\u4E00\u4E2A\u89D2\u5EA6\u7684\u56FE\uFF1A--front\u3001--side\u3001--back \u6216 --detail");
|
|
2300
|
+
}
|
|
2301
|
+
const images = await Promise.all(planned.map(async ({ angle, path }) => ({ angle, ...await readImageFile(path) })));
|
|
2302
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2303
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2304
|
+
let latest;
|
|
2305
|
+
const uploaded = [];
|
|
2306
|
+
for (const image of images) {
|
|
2307
|
+
const result = await putProductImage(
|
|
2308
|
+
baseUrl,
|
|
2309
|
+
apiKey,
|
|
2310
|
+
productId,
|
|
2311
|
+
image.angle,
|
|
2312
|
+
image.bytes,
|
|
2313
|
+
image.contentType,
|
|
2314
|
+
idempotencyKey,
|
|
2315
|
+
io
|
|
2316
|
+
);
|
|
2317
|
+
latest = result;
|
|
2318
|
+
uploaded.push({ angle: image.angle, replayed: result.replayed });
|
|
2319
|
+
}
|
|
2320
|
+
out.result(
|
|
2321
|
+
[
|
|
2322
|
+
...uploaded.map(
|
|
2323
|
+
({ angle, replayed }) => replayed ? `${angle}\uFF1A\u8FD9\u5F20\u5DF2\u7ECF\u4F20\u8FC7\u4E86\uFF08\u540C\u5B57\u8282\u91CD\u653E\uFF09` : `${angle}\uFF1A\u5DF2\u4E0A\u4F20`
|
|
2324
|
+
),
|
|
2325
|
+
`\u4EA7\u54C1\uFF1A${singleLine(latest?.view.id ?? productId)}\uFF08\u73B0\u5728 ${latest?.view.images.length ?? 0} \u5F20\u56FE\uFF09`,
|
|
2326
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`
|
|
2327
|
+
],
|
|
2328
|
+
{ product: latest?.raw.product, uploaded, idempotencyKey }
|
|
2329
|
+
);
|
|
2330
|
+
}
|
|
2331
|
+
async function confirmLock(context, values, rawId) {
|
|
2332
|
+
const { io, out } = context;
|
|
2333
|
+
const productId = productIdOf(rawId, "\u4EA7\u54C1 id\uFF08buke products create \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
2334
|
+
const colorName = textOption(values, "color");
|
|
2335
|
+
const silhouette = textOption(values, "silhouette");
|
|
2336
|
+
const material = textOption(values, "material");
|
|
2337
|
+
for (const [option, value] of [
|
|
2338
|
+
["--color", colorName],
|
|
2339
|
+
["--silhouette", silhouette],
|
|
2340
|
+
["--material", material]
|
|
2341
|
+
]) {
|
|
2342
|
+
if (value === void 0) {
|
|
2343
|
+
throw usageError(`\u5916\u89C2\u9501\u8981\u7ED9\u5168\uFF1A\u7F3A ${option}`);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2347
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2348
|
+
const { view, raw } = await confirmProductLock(
|
|
2349
|
+
baseUrl,
|
|
2350
|
+
apiKey,
|
|
2351
|
+
productId,
|
|
2352
|
+
{ colorName, silhouette, material },
|
|
2353
|
+
idempotencyKey,
|
|
2354
|
+
io
|
|
2355
|
+
);
|
|
2356
|
+
out.result(
|
|
2357
|
+
[
|
|
2358
|
+
`\u5916\u89C2\u9501\u5DF2\u786E\u8BA4\uFF1A\u4EA7\u54C1 ${singleLine(view.product.id)}`,
|
|
2359
|
+
`\u989C\u8272\uFF1A${singleLine(view.productLock.colorName)}`,
|
|
2360
|
+
`\u5ED3\u5F62\uFF1A${singleLine(view.productLock.silhouette)}`,
|
|
2361
|
+
`\u6750\u8D28\uFF1A${singleLine(view.productLock.material)}`,
|
|
2362
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`
|
|
2363
|
+
],
|
|
2364
|
+
{ productLock: raw.productLock, product: raw.product, idempotencyKey }
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
// src/commands/videos.ts
|
|
2369
|
+
var SUBCOMMANDS3 = "create\u3001status\u3001message\u3001confirm \u548C download";
|
|
2370
|
+
async function videos(context) {
|
|
2371
|
+
const { args } = context;
|
|
2372
|
+
const [subcommand] = args;
|
|
2373
|
+
if (subcommand === void 0) {
|
|
2374
|
+
throw usageError(`videos \u8981\u8DDF\u4E00\u4E2A\u5B50\u547D\u4EE4\uFF1A${SUBCOMMANDS3}`);
|
|
2375
|
+
}
|
|
2376
|
+
if (subcommand === "create") return create3(context);
|
|
2377
|
+
if (subcommand === "status") return status3(context, args[1]);
|
|
2378
|
+
if (subcommand === "message") return message(context, args[1]);
|
|
2379
|
+
if (subcommand === "confirm") return confirm2(context, args[1]);
|
|
2380
|
+
if (subcommand === "download") return download3(context, args[1]);
|
|
2381
|
+
throw usageError(`\u4E0D\u8BA4\u8BC6\u7684\u5B50\u547D\u4EE4 ${subcommand}\uFF1Avideos \u7684\u5B50\u547D\u4EE4\u662F ${SUBCOMMANDS3}`);
|
|
2382
|
+
}
|
|
2383
|
+
function runIdOf(raw) {
|
|
2384
|
+
if (raw === void 0 || raw.trim() === "") {
|
|
2385
|
+
throw usageError("\u8981\u7ED9\u89C6\u9891\u4EFB\u52A1 id\uFF08videos create \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
2386
|
+
}
|
|
2387
|
+
return raw.trim();
|
|
2388
|
+
}
|
|
2389
|
+
function waitControls3(io, values) {
|
|
2390
|
+
return {
|
|
2391
|
+
timeoutMs: timeoutSecondsOf(values, DEFAULT_WAIT_TIMEOUT_MS / 1e3) * 1e3,
|
|
2392
|
+
now: io.now ?? (() => /* @__PURE__ */ new Date()),
|
|
2393
|
+
sleep: io.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)))
|
|
2394
|
+
};
|
|
2395
|
+
}
|
|
2396
|
+
function settleRun(outcome) {
|
|
2397
|
+
const run2 = outcome.value.view;
|
|
2398
|
+
if (outcome.timedOut) {
|
|
1010
2399
|
throw new CliError({
|
|
1011
|
-
code: "
|
|
1012
|
-
exitCode: EXIT.
|
|
1013
|
-
message:
|
|
2400
|
+
code: "CLI_WAIT_TIMEOUT",
|
|
2401
|
+
exitCode: EXIT.WAIT_TIMEOUT,
|
|
2402
|
+
message: `\u7B49\u4E86\u8FD9\u4E48\u4E45\u8FD8\u5728 ${run2.status}\uFF08${run2.stage}\uFF09\uFF1A\u518D\u67E5\u7528 buke videos status ${run2.rootRunId}\uFF0C\u6216\u52A0 --timeout \u5EF6\u957F\u7B49\u5F85`
|
|
1014
2403
|
});
|
|
1015
2404
|
}
|
|
1016
|
-
|
|
1017
|
-
if (explicit !== null && explicit !== stored.baseUrl) {
|
|
2405
|
+
if (run2.status === "failed" || run2.status === "canceled") {
|
|
1018
2406
|
throw new CliError({
|
|
1019
|
-
code: "
|
|
2407
|
+
code: "CLI_TASK_FAILED",
|
|
2408
|
+
exitCode: EXIT.TASK_FAILED,
|
|
2409
|
+
message: run2.failure === null ? `\u8FD9\u6761\u89C6\u9891${run2.status === "canceled" ? "\u5DF2\u53D6\u6D88" : "\u6CA1\u6709\u505A\u6210"}` : singleLine(run2.failure.title) + (run2.failure.detail === "" ? "" : `\uFF1A${singleLine(run2.failure.detail)}`)
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
return outcome.value;
|
|
2413
|
+
}
|
|
2414
|
+
function runLines(run2) {
|
|
2415
|
+
return [
|
|
2416
|
+
`\u89C6\u9891\u4EFB\u52A1\uFF1A${singleLine(run2.rootRunId)}`,
|
|
2417
|
+
`\u72B6\u6001\uFF1A${singleLine(run2.status)}\uFF08${singleLine(run2.stage)}\uFF09`,
|
|
2418
|
+
`\u4EA7\u54C1\uFF1A${singleLine(run2.product.name)}`,
|
|
2419
|
+
`\u66F4\u65B0\u65F6\u95F4\uFF1A${singleLine(run2.updatedAt)}`
|
|
2420
|
+
];
|
|
2421
|
+
}
|
|
2422
|
+
function waitingLines(run2) {
|
|
2423
|
+
if (run2.status === "awaiting_confirmation") return [`\u7B49\u4F60\u786E\u8BA4\uFF1Abuke videos confirm ${run2.rootRunId}`];
|
|
2424
|
+
if (run2.status === "awaiting_reply" || run2.status === "needs_input") {
|
|
2425
|
+
return [`\u7B49\u4F60\u56DE\u7B54\uFF1Abuke videos message ${run2.rootRunId} --text <\u5185\u5BB9>`];
|
|
2426
|
+
}
|
|
2427
|
+
return [];
|
|
2428
|
+
}
|
|
2429
|
+
async function create3(context) {
|
|
2430
|
+
const { io, out, values } = context;
|
|
2431
|
+
const productId = textOption(values, "product");
|
|
2432
|
+
if (productId === void 0) {
|
|
2433
|
+
throw usageError("\u8981\u7ED9 --product <\u4EA7\u54C1id>\uFF08buke products create \u56DE\u7684\u90A3\u4E2A\uFF09");
|
|
2434
|
+
}
|
|
2435
|
+
const intent = textOption(values, "intent");
|
|
2436
|
+
const durationRaw = textOption(values, "duration");
|
|
2437
|
+
let durationSeconds;
|
|
2438
|
+
if (durationRaw !== void 0) {
|
|
2439
|
+
const parsed = Number(durationRaw);
|
|
2440
|
+
if (!Number.isInteger(parsed) || parsed <= 0) {
|
|
2441
|
+
throw usageError(`--duration \u8981\u662F\u6B63\u6574\u6570\u79D2\u6570\uFF0C\u5199\u7684\u662F ${durationRaw}`);
|
|
2442
|
+
}
|
|
2443
|
+
durationSeconds = parsed;
|
|
2444
|
+
}
|
|
2445
|
+
const preferences = {};
|
|
2446
|
+
if (durationSeconds !== void 0) preferences.durationSeconds = durationSeconds;
|
|
2447
|
+
for (const [option, field] of [
|
|
2448
|
+
["resolution", "resolution"],
|
|
2449
|
+
["speed", "speed"],
|
|
2450
|
+
["aspect-ratio", "aspectRatio"],
|
|
2451
|
+
["style-preset", "stylePreset"]
|
|
2452
|
+
]) {
|
|
2453
|
+
const value = textOption(values, option);
|
|
2454
|
+
if (value !== void 0) preferences[field] = value;
|
|
2455
|
+
}
|
|
2456
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2457
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2458
|
+
const { view, raw } = await createVideoRun(
|
|
2459
|
+
baseUrl,
|
|
2460
|
+
apiKey,
|
|
2461
|
+
{
|
|
2462
|
+
productId,
|
|
2463
|
+
...intent === void 0 ? {} : { intent },
|
|
2464
|
+
...Object.keys(preferences).length > 0 ? { preferences } : {}
|
|
2465
|
+
},
|
|
2466
|
+
idempotencyKey,
|
|
2467
|
+
io
|
|
2468
|
+
);
|
|
2469
|
+
out.result(
|
|
2470
|
+
[
|
|
2471
|
+
...runLines(view),
|
|
2472
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`,
|
|
2473
|
+
`\u67E5\u8FDB\u5EA6\uFF1Abuke videos status ${view.rootRunId}`
|
|
2474
|
+
],
|
|
2475
|
+
// --json 按文档回服务端那份完整的 run 视图。
|
|
2476
|
+
{ run: raw.run, idempotencyKey }
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
async function status3(context, rawId) {
|
|
2480
|
+
const { io, out, values } = context;
|
|
2481
|
+
const runId = runIdOf(rawId);
|
|
2482
|
+
const shouldWait = values.wait === true;
|
|
2483
|
+
const controls = shouldWait ? waitControls3(io, values) : void 0;
|
|
2484
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2485
|
+
const current = await getVideoRun(baseUrl, apiKey, runId, io);
|
|
2486
|
+
const final = shouldWait ? settleRun(await awaitVideoRun(baseUrl, apiKey, current, io, controls)) : current;
|
|
2487
|
+
const lastDirectorLine = [...final.view.messages].reverse().find((message2) => message2.role === "assistant" && message2.text.trim() !== "");
|
|
2488
|
+
out.result(
|
|
2489
|
+
[
|
|
2490
|
+
...runLines(final.view),
|
|
2491
|
+
...lastDirectorLine === void 0 ? [] : [`\u5BFC\u6F14\u8BF4\uFF1A${singleLine(lastDirectorLine.text)}`],
|
|
2492
|
+
...waitingLines(final.view),
|
|
2493
|
+
...final.view.status === "succeeded" ? [`\u4E0B\u8F7D\uFF1Abuke videos download ${final.view.rootRunId}`] : []
|
|
2494
|
+
],
|
|
2495
|
+
{ run: final.raw.run, ...shouldWait ? { waited: true } : {} }
|
|
2496
|
+
);
|
|
2497
|
+
}
|
|
2498
|
+
async function message(context, rawId) {
|
|
2499
|
+
const { io, out, values } = context;
|
|
2500
|
+
const runId = runIdOf(rawId);
|
|
2501
|
+
const text = textOption(values, "text");
|
|
2502
|
+
if (text === void 0) {
|
|
2503
|
+
throw usageError("\u8981\u7ED9 --text <\u5185\u5BB9>\uFF1A\u60F3\u5BF9\u5BFC\u6F14\u8BF4\u7684\u90A3\u53E5\u8BDD");
|
|
2504
|
+
}
|
|
2505
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2506
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2507
|
+
const { view, raw } = await postVideoMessage(baseUrl, apiKey, runId, text, idempotencyKey, io);
|
|
2508
|
+
const lastDirectorLine = [...view.messages].reverse().find((entry) => entry.role === "assistant" && entry.text.trim() !== "");
|
|
2509
|
+
out.result(
|
|
2510
|
+
[
|
|
2511
|
+
...runLines(view),
|
|
2512
|
+
...lastDirectorLine === void 0 ? [] : [`\u5BFC\u6F14\u8BF4\uFF1A${singleLine(lastDirectorLine.text)}`],
|
|
2513
|
+
...waitingLines(view),
|
|
2514
|
+
`\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`
|
|
2515
|
+
],
|
|
2516
|
+
{ run: raw.run, idempotencyKey }
|
|
2517
|
+
);
|
|
2518
|
+
}
|
|
2519
|
+
async function confirm2(context, rawId) {
|
|
2520
|
+
const { io, out, values } = context;
|
|
2521
|
+
const runId = runIdOf(rawId);
|
|
2522
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2523
|
+
const fetched = await getVideoRun(baseUrl, apiKey, runId, io);
|
|
2524
|
+
const run2 = fetched.view;
|
|
2525
|
+
const card = run2.nextActions.find((action) => action.type === "confirm_production");
|
|
2526
|
+
if (card === void 0) {
|
|
2527
|
+
throw new CliError({
|
|
2528
|
+
code: "CLI_USAGE",
|
|
1020
2529
|
exitCode: EXIT.USAGE,
|
|
1021
|
-
message: `\
|
|
2530
|
+
message: `\u73B0\u5728\u6CA1\u6709\u7B49\u7740\u786E\u8BA4\u7684\u5361\uFF08\u5F53\u524D\u72B6\u6001\uFF1A${run2.status}\uFF09\u3002\u5BFC\u6F14\u505C\u4E0B\u6765\u8981\u786E\u8BA4\u65F6\u518D\u8FD0\u884C\u8FD9\u6761\u547D\u4EE4`
|
|
1022
2531
|
});
|
|
1023
2532
|
}
|
|
1024
|
-
|
|
2533
|
+
if (card.confirmation === void 0) {
|
|
2534
|
+
throw new CliError({
|
|
2535
|
+
code: "CLI_USAGE",
|
|
2536
|
+
exitCode: EXIT.USAGE,
|
|
2537
|
+
message: "\u670D\u52A1\u7AEF\u6302\u51FA\u7684\u8FD9\u5F20\u5361\u4E0D\u5E26\u786E\u8BA4\u8EAB\u4EFD\uFF0C\u786E\u8BA4\u4E0D\u4E86\uFF1B\u7A0D\u540E\u91CD\u65B0\u8FD0\u884C buke videos status \u770B\u6700\u65B0\u72B6\u6001"
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
const credits = card.credits ?? 0;
|
|
2541
|
+
const kind = card.confirmKind === void 0 ? "\u786E\u8BA4" : `\u786E\u8BA4\uFF08${card.confirmKind}\uFF09`;
|
|
2542
|
+
if (values.yes !== true) {
|
|
2543
|
+
throw new CliError({
|
|
2544
|
+
code: "CLI_USAGE",
|
|
2545
|
+
exitCode: EXIT.USAGE,
|
|
2546
|
+
message: `\u8FD9\u5F20\u5361\u8981\u82B1 ${credits} \u5E03\u3002\u52A0 --yes \u786E\u8BA4\u8FD9\u7B14\u5E03\u652F\u51FA`,
|
|
2547
|
+
hints: [`${kind}\uFF1A${singleLine(run2.label)}`, `\u770B\u8FC7\u518D\u786E\u8BA4\uFF1Abuke videos status ${run2.rootRunId}`]
|
|
2548
|
+
});
|
|
2549
|
+
}
|
|
2550
|
+
const idempotencyKey = idempotencyKeyOf(values);
|
|
2551
|
+
const outcome = await confirmVideoProduction(baseUrl, apiKey, runId, run2.version, card.confirmation, idempotencyKey, io);
|
|
2552
|
+
out.result(
|
|
2553
|
+
[...runLines(outcome.view), `\u5DF2\u786E\u8BA4\uFF1A\u8FD9\u7B14\u6700\u591A ${credits} \u5E03`, ...waitingLines(outcome.view), `\u5E42\u7B49\u952E\uFF1A${idempotencyKey}`],
|
|
2554
|
+
{ run: outcome.raw.run, confirmed: { credits, confirmKind: card.confirmKind ?? null }, idempotencyKey }
|
|
2555
|
+
);
|
|
1025
2556
|
}
|
|
2557
|
+
async function download3(context, rawId) {
|
|
2558
|
+
const { io, out, values } = context;
|
|
2559
|
+
const runId = runIdOf(rawId);
|
|
2560
|
+
const { apiKey, baseUrl } = await resolveApiKey(context);
|
|
2561
|
+
const result = await downloadVideo(baseUrl, apiKey, runId, io);
|
|
2562
|
+
const defaultName = result.filename ?? `video-${runId}.mp4`;
|
|
2563
|
+
const target = textOption(values, "out") ?? defaultName;
|
|
2564
|
+
const saved = await saveDownload(target, result.bytes);
|
|
2565
|
+
out.result(
|
|
2566
|
+
[`\u5DF2\u4E0B\u8F7D\uFF1A${saved.path}`, `\u5927\u5C0F\uFF1A${saved.bytes} \u5B57\u8282`, `\u6821\u9A8C\uFF1Asha256 ${saved.sha256}`],
|
|
2567
|
+
{ download: { ...saved, filename: defaultName } }
|
|
2568
|
+
);
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
// src/commands/whoami.ts
|
|
1026
2572
|
async function whoami(context) {
|
|
1027
2573
|
const { io, out } = context;
|
|
1028
|
-
const resolved = await
|
|
2574
|
+
const resolved = await resolveApiKey(context);
|
|
1029
2575
|
const { apiKey, baseUrl } = resolved;
|
|
1030
2576
|
let me;
|
|
1031
2577
|
try {
|
|
@@ -1041,11 +2587,7 @@ async function whoami(context) {
|
|
|
1041
2587
|
const displayPrefix = displayPrefixOf(apiKey, me.key.id);
|
|
1042
2588
|
const identity = identityDocument(baseUrl, me, displayPrefix);
|
|
1043
2589
|
out.result(
|
|
1044
|
-
[
|
|
1045
|
-
`\u5F53\u524D\u767B\u5F55 ${baseUrl}`,
|
|
1046
|
-
...identityLines(me, displayPrefix),
|
|
1047
|
-
resolved.source === "env" ? "\u5BC6\u94A5\u6765\u81EA\uFF1A\u73AF\u5883\u53D8\u91CF BUKE_API_KEY" : `\u5BC6\u94A5\u6765\u81EA\uFF1A${resolved.credentialsPath}`
|
|
1048
|
-
],
|
|
2590
|
+
[`\u5F53\u524D\u767B\u5F55 ${baseUrl}`, ...identityLines(me, displayPrefix), keySourceLine(resolved)],
|
|
1049
2591
|
resolved.source === "env" ? { ...identity, source: resolved.source } : { ...identity, source: resolved.source, credentialsPath: resolved.credentialsPath },
|
|
1050
2592
|
[displayPrefix]
|
|
1051
2593
|
);
|
|
@@ -1062,6 +2604,8 @@ var COMMANDS = {
|
|
|
1062
2604
|
login: {
|
|
1063
2605
|
run: login,
|
|
1064
2606
|
acceptsBaseUrl: true,
|
|
2607
|
+
options: [],
|
|
2608
|
+
positionals: [],
|
|
1065
2609
|
help: [
|
|
1066
2610
|
"\u7528\u6CD5\uFF1Abuke login [--base-url <\u5730\u5740>] [--json]",
|
|
1067
2611
|
"",
|
|
@@ -1078,6 +2622,8 @@ var COMMANDS = {
|
|
|
1078
2622
|
whoami: {
|
|
1079
2623
|
run: whoami,
|
|
1080
2624
|
acceptsBaseUrl: true,
|
|
2625
|
+
options: [],
|
|
2626
|
+
positionals: [],
|
|
1081
2627
|
help: [
|
|
1082
2628
|
"\u7528\u6CD5\uFF1Abuke whoami [--base-url <\u5730\u5740>] [--json]",
|
|
1083
2629
|
"",
|
|
@@ -1093,6 +2639,8 @@ var COMMANDS = {
|
|
|
1093
2639
|
logout: {
|
|
1094
2640
|
run: logout,
|
|
1095
2641
|
acceptsBaseUrl: false,
|
|
2642
|
+
options: [],
|
|
2643
|
+
positionals: [],
|
|
1096
2644
|
help: [
|
|
1097
2645
|
"\u7528\u6CD5\uFF1Abuke logout [--json]",
|
|
1098
2646
|
"",
|
|
@@ -1101,15 +2649,189 @@ var COMMANDS = {
|
|
|
1101
2649
|
"\u9009\u9879\uFF1A",
|
|
1102
2650
|
" --json \u53EA\u5728\u6807\u51C6\u8F93\u51FA\u6253\u5370\u4E00\u4E2A JSON \u6587\u6863\uFF0C\u65B9\u4FBF\u811A\u672C\u8BFB\u53D6"
|
|
1103
2651
|
].join("\n")
|
|
2652
|
+
},
|
|
2653
|
+
balance: {
|
|
2654
|
+
run: balance,
|
|
2655
|
+
acceptsBaseUrl: true,
|
|
2656
|
+
options: [],
|
|
2657
|
+
positionals: [],
|
|
2658
|
+
help: [
|
|
2659
|
+
"\u7528\u6CD5\uFF1Abuke balance [--json]",
|
|
2660
|
+
"",
|
|
2661
|
+
"\u67E5\u8BE2\u8FD9\u4E2A\u8D26\u53F7\u7684\u4F59\u989D\uFF1A\u53EF\u7528\u591A\u5C11\u3001\u51BB\u7740\u591A\u5C11\u3001\u5DF2\u7ECF\u82B1\u4E86\u591A\u5C11\u3002",
|
|
2662
|
+
"",
|
|
2663
|
+
"\u9009\u9879\uFF1A",
|
|
2664
|
+
" --base-url <\u5730\u5740> \u670D\u52A1\u5730\u5740\uFF1B\u4E0D\u7ED9\u65F6\u7528\u767B\u5F55\u65F6\u7684\u5730\u5740",
|
|
2665
|
+
" --json \u53EA\u5728\u6807\u51C6\u8F93\u51FA\u6253\u5370\u4E00\u4E2A JSON \u6587\u6863\uFF0C\u65B9\u4FBF\u811A\u672C\u8BFB\u53D6"
|
|
2666
|
+
].join("\n")
|
|
2667
|
+
},
|
|
2668
|
+
products: {
|
|
2669
|
+
run: products,
|
|
2670
|
+
acceptsBaseUrl: true,
|
|
2671
|
+
options: ["name", "category", "front", "side", "back", "detail", "color", "silhouette", "material", "idempotency-key"],
|
|
2672
|
+
positionals: ["\u5B50\u547D\u4EE4", "\u4EA7\u54C1id"],
|
|
2673
|
+
help: [
|
|
2674
|
+
"\u7528\u6CD5\uFF1A",
|
|
2675
|
+
" buke products create --name <\u540D\u79F0> [--category <\u7C7B\u76EE>] [--json]",
|
|
2676
|
+
" buke products set-images <\u4EA7\u54C1id> --front <\u56FE> [--side <\u56FE>] [--back <\u56FE>] [--detail <\u56FE>]",
|
|
2677
|
+
" buke products confirm-lock <\u4EA7\u54C1id> --color <\u8272> --silhouette <\u5ED3\u5F62> --material <\u6750\u8D28>",
|
|
2678
|
+
"",
|
|
2679
|
+
"\u4EA7\u54C1\u5EFA\u6863\uFF0C\u662F\u5546\u54C1\u89C6\u9891\u4E0B\u5355\u7684\u524D\u7F6E\uFF1A",
|
|
2680
|
+
" create \u5EFA\u4E00\u4EF6\u4EA7\u54C1\uFF08\u540D\u79F0\u5FC5\u586B\uFF1B\u7C7B\u76EE\u53EF\u7ED9\u53EF\u4E0D\u7ED9\uFF0C\u4E0D\u7ED9\u65F6\u7531\u670D\u52A1\u7AEF\u6309\u540D\u79F0\u8BC6\u522B\uFF09",
|
|
2681
|
+
" set-images \u4F20\u4EA7\u54C1\u56FE\uFF08JPEG/PNG/WebP \u7684\u6587\u4EF6\u8DEF\u5F84\uFF1B\u81F3\u5C11\u7ED9\u4E00\u4E2A\u89D2\u5EA6\uFF09",
|
|
2682
|
+
" confirm-lock \u786E\u8BA4\u5916\u89C2\u9501\uFF1A\u989C\u8272\u3001\u5ED3\u5F62\u3001\u6750\u8D28\u4E09\u6837\u90FD\u8981\u7ED9",
|
|
2683
|
+
"",
|
|
2684
|
+
"\u9009\u9879\uFF1A",
|
|
2685
|
+
" --name <\u540D\u79F0> \u4EA7\u54C1\u540D\u79F0",
|
|
2686
|
+
" --category <\u7C7B\u76EE> \u7C7B\u76EE\uFF1B\u4E0D\u7ED9\u65F6\u670D\u52A1\u7AEF\u6309\u540D\u79F0\u548C\u4ECB\u7ECD\u8BC6\u522B",
|
|
2687
|
+
" --front/--side/--back/--detail <\u56FE> \u4EA7\u54C1\u56FE\u7684\u89D2\u5EA6\u4E0E\u6587\u4EF6\u8DEF\u5F84",
|
|
2688
|
+
" --color <\u8272> \u5916\u89C2\u9501\uFF1A\u989C\u8272",
|
|
2689
|
+
" --silhouette <\u5ED3\u5F62> \u5916\u89C2\u9501\uFF1A\u5ED3\u5F62",
|
|
2690
|
+
" --material <\u6750\u8D28> \u5916\u89C2\u9501\uFF1A\u6750\u8D28",
|
|
2691
|
+
" --idempotency-key <\u952E> \u5E42\u7B49\u952E\uFF1B\u4E0D\u7ED9\u65F6\u81EA\u52A8\u751F\u6210\u5E76\u5728\u8F93\u51FA\u91CC\u56DE\u663E\uFF0C\u91CD\u8BD5\u540C\u4E00\u6B21\u8BF7\u6C42\u65F6\u539F\u6837\u590D\u7528",
|
|
2692
|
+
" --base-url <\u5730\u5740> \u670D\u52A1\u5730\u5740\uFF1B\u4E0D\u7ED9\u65F6\u7528\u767B\u5F55\u65F6\u7684\u5730\u5740",
|
|
2693
|
+
" --json \u53EA\u5728\u6807\u51C6\u8F93\u51FA\u6253\u5370\u4E00\u4E2A JSON \u6587\u6863\uFF0C\u65B9\u4FBF\u811A\u672C\u8BFB\u53D6"
|
|
2694
|
+
].join("\n")
|
|
2695
|
+
},
|
|
2696
|
+
shorts: {
|
|
2697
|
+
run: shorts,
|
|
2698
|
+
acceptsBaseUrl: true,
|
|
2699
|
+
options: ["template", "props", "quote-hash", "wait", "timeout", "out", "idempotency-key"],
|
|
2700
|
+
positionals: ["\u5B50\u547D\u4EE4", "\u8BA2\u5355id"],
|
|
2701
|
+
help: [
|
|
2702
|
+
"\u7528\u6CD5\uFF1A",
|
|
2703
|
+
" buke shorts catalog [--json]",
|
|
2704
|
+
" buke shorts upload <\u56FE\u7247\u6587\u4EF6>",
|
|
2705
|
+
" buke shorts quote --template <\u6A21\u677Fid> --props <props.json|->",
|
|
2706
|
+
" buke shorts order --template <\u6A21\u677Fid> --props <props.json|-> [--quote-hash <hash>] [--wait] [--timeout <\u79D2>]",
|
|
2707
|
+
" buke shorts status <\u8BA2\u5355id> [--wait] [--timeout <\u79D2>]",
|
|
2708
|
+
" buke shorts download <\u8BA2\u5355id> [--out <\u8DEF\u5F84>]",
|
|
2709
|
+
" buke shorts cancel <\u8BA2\u5355id>",
|
|
2710
|
+
"",
|
|
2711
|
+
"\u6E32\u67D3\u77ED\u7247\uFF08\u6A21\u677F\u76F4\u51FA\u7684\u7AD6\u5C4F\u5546\u54C1\u77ED\u7247\uFF09\uFF1A",
|
|
2712
|
+
" catalog \u5217\u51FA\u5168\u90E8\u6A21\u677F\uFF08id\u3001\u65F6\u957F\u3001\u8981\u54EA\u4E9B\u7D20\u6750\uFF09",
|
|
2713
|
+
" upload \u6258\u7BA1\u4E00\u5F20\u7D20\u6750\u56FE\uFF0C\u6362\u56DE\u53EF\u4EE5\u76F4\u63A5\u586B\u8FDB\u6A21\u677F\u56FE\u7247\u69FD\u7684\u5730\u5740",
|
|
2714
|
+
" quote \u53EA\u8BFB\u62A5\u4EF7\uFF1B\u6536\u8D39\u7684\u6A21\u677F\u4E0B\u5355\u524D\u5FC5\u987B\u5148\u62FF quoteHash",
|
|
2715
|
+
" order \u4E0B\u5355\uFF1B\u540C\u952E\u540C\u5185\u5BB9\u91CD\u8BD5\u56DE\u540C\u4E00\u5F20\u5355",
|
|
2716
|
+
" status \u67E5\u8FDB\u5EA6\uFF1B--wait \u4E00\u76F4\u7B49\u5230\u51FA\u7ED3\u679C",
|
|
2717
|
+
" download \u4E0B\u8F7D\u6E32\u67D3\u597D\u7684\u6210\u7247\uFF08mp4\uFF09",
|
|
2718
|
+
" cancel \u53D6\u6D88\u8FD8\u6CA1\u5F00\u59CB\u7684\u8BA2\u5355",
|
|
2719
|
+
"",
|
|
2720
|
+
"\u9009\u9879\uFF1A",
|
|
2721
|
+
" --template <\u6A21\u677Fid> \u6A21\u677F id\uFF08catalog \u91CC\u5217\u51FA\u7684\uFF09",
|
|
2722
|
+
" --props <props.json|-> \u6A21\u677F\u53C2\u6570\uFF1A\u4E00\u4E2A JSON \u6587\u4EF6\uFF0C\u6216 - \u8868\u793A\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB",
|
|
2723
|
+
" --quote-hash <hash> \u62A5\u4EF7\u54C8\u5E0C\uFF08quote \u547D\u4EE4\u56DE\u7684\uFF09",
|
|
2724
|
+
" --wait \u4E00\u76F4\u7B49\u5230\u7EC8\u6001\uFF1A\u6210\u529F\u9000\u51FA 0\uFF0C\u4EFB\u52A1\u5931\u8D25\u9000\u51FA 9\uFF0C\u5230\u65F6\u9650\u9000\u51FA 8",
|
|
2725
|
+
" --timeout <\u79D2> --wait \u7684\u65F6\u9650\uFF0C\u9ED8\u8BA4 600",
|
|
2726
|
+
" --out <\u8DEF\u5F84> \u4E0B\u8F7D\u4FDD\u5B58\u7684\u4F4D\u7F6E\uFF1B\u4E0D\u7ED9\u65F6\u5B58\u5230\u5F53\u524D\u76EE\u5F55",
|
|
2727
|
+
" --idempotency-key <\u952E> \u5E42\u7B49\u952E\uFF1B\u4E0D\u7ED9\u65F6\u81EA\u52A8\u751F\u6210\u5E76\u5728\u8F93\u51FA\u91CC\u56DE\u663E\uFF0C\u91CD\u8BD5\u540C\u4E00\u6B21\u8BF7\u6C42\u65F6\u539F\u6837\u590D\u7528",
|
|
2728
|
+
" --base-url <\u5730\u5740> \u670D\u52A1\u5730\u5740\uFF1B\u4E0D\u7ED9\u65F6\u7528\u767B\u5F55\u65F6\u7684\u5730\u5740",
|
|
2729
|
+
" --json \u53EA\u5728\u6807\u51C6\u8F93\u51FA\u6253\u5370\u4E00\u4E2A JSON \u6587\u6863\uFF0C\u65B9\u4FBF\u811A\u672C\u8BFB\u53D6"
|
|
2730
|
+
].join("\n")
|
|
2731
|
+
},
|
|
2732
|
+
videos: {
|
|
2733
|
+
run: videos,
|
|
2734
|
+
acceptsBaseUrl: true,
|
|
2735
|
+
options: [
|
|
2736
|
+
"product",
|
|
2737
|
+
"intent",
|
|
2738
|
+
"duration",
|
|
2739
|
+
"resolution",
|
|
2740
|
+
"speed",
|
|
2741
|
+
"aspect-ratio",
|
|
2742
|
+
"style-preset",
|
|
2743
|
+
"text",
|
|
2744
|
+
"yes",
|
|
2745
|
+
"wait",
|
|
2746
|
+
"timeout",
|
|
2747
|
+
"out",
|
|
2748
|
+
"idempotency-key"
|
|
2749
|
+
],
|
|
2750
|
+
positionals: ["\u5B50\u547D\u4EE4", "\u89C6\u9891id"],
|
|
2751
|
+
help: [
|
|
2752
|
+
"\u7528\u6CD5\uFF1A",
|
|
2753
|
+
" buke videos create --product <\u4EA7\u54C1id> [--intent <\u4E00\u53E5\u8BDD>] [--duration <\u79D2>] [--resolution <r>]",
|
|
2754
|
+
" [--speed <\u6863>] [--aspect-ratio <a>] [--style-preset <p>] [--json]",
|
|
2755
|
+
" buke videos status <\u89C6\u9891id> [--wait] [--timeout <\u79D2>]",
|
|
2756
|
+
" buke videos message <\u89C6\u9891id> --text <\u5185\u5BB9>",
|
|
2757
|
+
" buke videos confirm <\u89C6\u9891id> [--yes]",
|
|
2758
|
+
" buke videos download <\u89C6\u9891id> [--out <\u8DEF\u5F84>]",
|
|
2759
|
+
"",
|
|
2760
|
+
"\u5546\u54C1\u89C6\u9891\uFF08\u5BFC\u6F14\u5168\u7A0B\u7F16\u6392\u7684\u90A3\u6761\u4EA7\u7EBF\uFF09\uFF1A",
|
|
2761
|
+
" create \u4E0B\u5355\uFF1B\u4EA7\u54C1\u5148\u7528 buke products \u5EFA\u597D\u3002\u53D7\u7406\u540E\u8F6E\u8BE2 status \u53D6\u8FDB\u5EA6",
|
|
2762
|
+
" status \u67E5\u8FDB\u5EA6\uFF1B--wait \u4E00\u76F4\u7B49\u5230\u7EC8\u6001",
|
|
2763
|
+
" message \u7ED9\u5BFC\u6F14\u56DE\u4E00\u53E5\u8BDD\uFF08\u8865\u610F\u56FE\u3001\u56DE\u7B54\u63D0\u95EE\uFF09",
|
|
2764
|
+
" confirm \u786E\u8BA4\u5F00\u62CD\uFF1A\u628A\u670D\u52A1\u7AEF\u6302\u51FA\u7684\u90A3\u5F20\u5361\u539F\u6837\u56DE\u4F20\uFF0C\u94B1\u5728\u505C\u70B9\u5F53\u9762\u8981\u6388\u6743",
|
|
2765
|
+
" download \u4E0B\u8F7D\u6210\u7247\uFF08mp4\uFF09",
|
|
2766
|
+
"",
|
|
2767
|
+
"\u9009\u9879\uFF1A",
|
|
2768
|
+
" --product <\u4EA7\u54C1id> \u4EA7\u54C1 id\uFF08buke products create \u56DE\u7684\uFF09",
|
|
2769
|
+
" --intent <\u4E00\u53E5\u8BDD> \u8FD9\u6761\u7247\u5B50\u60F3\u8BB2\u4EC0\u4E48\uFF1B\u4E0D\u7ED9\u65F6\u7531\u5BFC\u6F14\u6309\u4EA7\u54C1\u81EA\u5DF1\u60F3",
|
|
2770
|
+
" --duration <\u79D2> \u671F\u671B\u65F6\u957F",
|
|
2771
|
+
" --resolution <r> \u5206\u8FA8\u7387\u6863\u4F4D",
|
|
2772
|
+
" --speed <\u6863> \u751F\u6210\u901F\u5EA6\u6863\u4F4D",
|
|
2773
|
+
" --aspect-ratio <a> \u753B\u5E45\uFF08\u5982 9:16\uFF09",
|
|
2774
|
+
" --style-preset <p> \u753B\u9762\u98CE\u683C",
|
|
2775
|
+
" --text <\u5185\u5BB9> \u8981\u5E26\u7ED9\u5BFC\u6F14\u7684\u90A3\u53E5\u8BDD",
|
|
2776
|
+
" --yes confirm \u65F6\u771F\u7684\u63D0\u4EA4\uFF1B\u4E0D\u7ED9\u65F6\u53EA\u663E\u793A\u90A3\u5F20\u5361",
|
|
2777
|
+
" --wait \u4E00\u76F4\u7B49\u5230\u7EC8\u6001\uFF1A\u6210\u529F\u9000\u51FA 0\uFF0C\u4EFB\u52A1\u5931\u8D25\u9000\u51FA 9\uFF0C\u5230\u65F6\u9650\u9000\u51FA 8",
|
|
2778
|
+
" --timeout <\u79D2> --wait \u7684\u65F6\u9650\uFF0C\u9ED8\u8BA4 600",
|
|
2779
|
+
" --out <\u8DEF\u5F84> \u4E0B\u8F7D\u4FDD\u5B58\u7684\u4F4D\u7F6E\uFF1B\u4E0D\u7ED9\u65F6\u5B58\u5230\u5F53\u524D\u76EE\u5F55",
|
|
2780
|
+
" --idempotency-key <\u952E> \u5E42\u7B49\u952E\uFF1B\u4E0D\u7ED9\u65F6\u81EA\u52A8\u751F\u6210\u5E76\u5728\u8F93\u51FA\u91CC\u56DE\u663E\uFF0C\u91CD\u8BD5\u540C\u4E00\u6B21\u8BF7\u6C42\u65F6\u539F\u6837\u590D\u7528",
|
|
2781
|
+
" --base-url <\u5730\u5740> \u670D\u52A1\u5730\u5740\uFF1B\u4E0D\u7ED9\u65F6\u7528\u767B\u5F55\u65F6\u7684\u5730\u5740",
|
|
2782
|
+
" --json \u53EA\u5728\u6807\u51C6\u8F93\u51FA\u6253\u5370\u4E00\u4E2A JSON \u6587\u6863\uFF0C\u65B9\u4FBF\u811A\u672C\u8BFB\u53D6"
|
|
2783
|
+
].join("\n")
|
|
2784
|
+
},
|
|
2785
|
+
drama: {
|
|
2786
|
+
run: drama,
|
|
2787
|
+
acceptsBaseUrl: true,
|
|
2788
|
+
options: ["product", "genre", "duration", "brief", "quote-hash", "yes", "wait", "timeout", "out", "idempotency-key"],
|
|
2789
|
+
positionals: ["\u5B50\u547D\u4EE4", "\u8BA2\u5355id"],
|
|
2790
|
+
help: [
|
|
2791
|
+
"\u7528\u6CD5\uFF1A",
|
|
2792
|
+
" buke drama create --product <\u4EA7\u54C1id> [--genre <\u9898\u6750id>] [--duration 30s|60s|90s] [--brief <JSON \u6587\u4EF6|->] [--json]",
|
|
2793
|
+
" buke drama status <\u8BA2\u5355id> [--wait] [--timeout <\u79D2>]",
|
|
2794
|
+
" buke drama quote <\u8BA2\u5355id>",
|
|
2795
|
+
" buke drama confirm <\u8BA2\u5355id> --quote-hash <\u62A5\u4EF7\u54C8\u5E0C> [--yes]",
|
|
2796
|
+
" buke drama cancel <\u8BA2\u5355id>",
|
|
2797
|
+
" buke drama download <\u8BA2\u5355id> [--out <\u8DEF\u5F84>]",
|
|
2798
|
+
"",
|
|
2799
|
+
"\u77ED\u5267\uFF08\u65E0\u4EBA\u503C\u5B88\u7F16\u6392\u5668\uFF09\uFF1A\u5E73\u53F0\u5148\u8DD1\u5199\u7A3F\u3001\u7ED1\u4EBA\u4E0E\u6392\u7248\u5206\u955C\uFF0C\u5230\u53EF\u62A5\u4EF7\u505C\u4E0B\u7B49\u4F60\u786E\u8BA4\uFF1B\u786E\u8BA4\u5F00\u62CD\u662F\u552F\u4E00\u6263\u8D39\u5165\u53E3\u3002",
|
|
2800
|
+
" create \u4E0B\u5355\uFF1B\u4EA7\u54C1\u5148\u7528 buke products \u5EFA\u597D\u3002\u53D7\u7406\u540E\u8F6E\u8BE2 status \u53D6\u8FDB\u5EA6",
|
|
2801
|
+
" status \u67E5\u8FDB\u5EA6\uFF08\u67E5\u8BE2\u672C\u8EAB\u4F1A\u63A8\u8FDB\u6392\u7248\uFF09\uFF1B--wait \u4E00\u76F4\u7B49\u5230\u7EC8\u6001\u6216\u505C\u9760",
|
|
2802
|
+
" quote \u53EA\u8BFB\u62A5\u4EF7\uFF1A\u62A5\u4EF7\u8981\u7D20\u4E0E\u62A5\u4EF7\u54C8\u5E0C\uFF0C\u786E\u8BA4\u5F00\u62CD\u65F6\u539F\u6837\u5E26\u56DE",
|
|
2803
|
+
" confirm \u786E\u8BA4\u5F00\u62CD\uFF1A\u5148\u53D6\u4E00\u6B21\u5F53\u524D\u62A5\u4EF7\u7ED9\u4EBA\u770B\uFF0C\u52A0 --yes \u624D\u63D0\u4EA4\u8FD9\u7B14\u5E03\u652F\u51FA",
|
|
2804
|
+
" cancel \u53D6\u6D88\uFF1A\u6CA1\u62CD\u7684\u955C\u5934\u9000\u56DE\u51BB\u7ED3\u989D\u5EA6\uFF0C\u5DF2\u7ECF\u62CD\u6210\u7684\u4FDD\u7559\u7167\u6263",
|
|
2805
|
+
" download \u4E0B\u8F7D\u76F4\u62FC\u597D\u7684\u6210\u7247\uFF08mp4\uFF09",
|
|
2806
|
+
"",
|
|
2807
|
+
"\u9009\u9879\uFF1A",
|
|
2808
|
+
" --product <\u4EA7\u54C1id> \u4EA7\u54C1 id\uFF08buke products create \u56DE\u7684\uFF09",
|
|
2809
|
+
" --genre <\u9898\u6750id> \u9898\u6750 id\uFF08\u5982 counterattack\u3001urban-ceo\u3001family\uFF09",
|
|
2810
|
+
" --duration <\u4F53\u91CF> \u6210\u7247\u4F53\u91CF\uFF1A30s\u300160s \u6216 90s\uFF1B\u4E0D\u7ED9\u65F6 30s",
|
|
2811
|
+
" --brief <JSON \u6587\u4EF6|-> \u6545\u4E8B\u8BBE\u5B9A\uFF1Adescription\u3001forbidden\u3001storyTone \u4E09\u9879\uFF0C\u4E00\u4E2A JSON \u6587\u4EF6\u6216 - \u8868\u793A\u4ECE\u6807\u51C6\u8F93\u5165\u8BFB",
|
|
2812
|
+
" --quote-hash <\u54C8\u5E0C> \u62A5\u4EF7\u54C8\u5E0C\uFF08buke drama quote \u56DE\u7684\uFF09\uFF0C\u786E\u8BA4\u5F00\u62CD\u65F6\u539F\u6837\u5E26\u56DE",
|
|
2813
|
+
" --yes confirm \u65F6\u771F\u7684\u63D0\u4EA4\u5E76\u5F00\u62CD\uFF1B\u4E0D\u7ED9\u65F6\u53EA\u770B\u5F53\u524D\u62A5\u4EF7",
|
|
2814
|
+
" --wait \u4E00\u76F4\u7B49\u5230\u7EC8\u6001\u6216\u505C\u9760\uFF1A\u6210\u529F\u9000\u51FA 0\uFF0C\u5931\u8D25\u6216\u53D6\u6D88\u9000\u51FA 9\uFF0C\u5230\u65F6\u9650\u9000\u51FA 8",
|
|
2815
|
+
" --timeout <\u79D2> --wait \u7684\u65F6\u9650\uFF0C\u9ED8\u8BA4 600",
|
|
2816
|
+
" --out <\u8DEF\u5F84> \u4E0B\u8F7D\u4FDD\u5B58\u7684\u4F4D\u7F6E\uFF1B\u4E0D\u7ED9\u65F6\u5B58\u5230\u5F53\u524D\u76EE\u5F55",
|
|
2817
|
+
" --idempotency-key <\u952E> \u5E42\u7B49\u952E\uFF1B\u4E0D\u7ED9\u65F6\u81EA\u52A8\u751F\u6210\u5E76\u5728\u8F93\u51FA\u91CC\u56DE\u663E\uFF0C\u91CD\u8BD5\u540C\u4E00\u6B21\u8BF7\u6C42\u65F6\u539F\u6837\u590D\u7528",
|
|
2818
|
+
" --base-url <\u5730\u5740> \u670D\u52A1\u5730\u5740\uFF1B\u4E0D\u7ED9\u65F6\u7528\u767B\u5F55\u65F6\u7684\u5730\u5740",
|
|
2819
|
+
" --json \u53EA\u5728\u6807\u51C6\u8F93\u51FA\u6253\u5370\u4E00\u4E2A JSON \u6587\u6863\uFF0C\u65B9\u4FBF\u811A\u672C\u8BFB\u53D6"
|
|
2820
|
+
].join("\n")
|
|
1104
2821
|
}
|
|
1105
2822
|
};
|
|
1106
2823
|
var GENERAL_HELP = [
|
|
1107
2824
|
"buke\uFF1A\u300A\u4E0D\u53EF\u601D\u8BAE\u300B\u7684\u547D\u4EE4\u884C\u5DE5\u5177",
|
|
1108
2825
|
"",
|
|
1109
2826
|
"\u7528\u6CD5\uFF1A",
|
|
1110
|
-
" buke login
|
|
1111
|
-
" buke whoami
|
|
1112
|
-
" buke logout
|
|
2827
|
+
" buke login [--base-url <\u5730\u5740>] [--json] \u7528\u4E00\u628A API \u5BC6\u94A5\u767B\u5F55\uFF0C\u5E76\u628A\u5B83\u4FDD\u5B58\u5728\u672C\u673A",
|
|
2828
|
+
" buke whoami [--base-url <\u5730\u5740>] [--json] \u67E5\u770B\u5F53\u524D\u7528\u7684\u662F\u54EA\u628A\u5BC6\u94A5\u3001\u5C5E\u4E8E\u54EA\u4E2A\u56E2\u961F",
|
|
2829
|
+
" buke logout [--json] \u9000\u51FA\u767B\u5F55\uFF0C\u5220\u9664\u672C\u673A\u4FDD\u5B58\u7684\u5BC6\u94A5",
|
|
2830
|
+
" buke balance [--json] \u67E5\u8BE2\u8D26\u6237\u4F59\u989D",
|
|
2831
|
+
" buke products <\u5B50\u547D\u4EE4> [\u53C2\u6570] \u4EA7\u54C1\u5EFA\u6863\uFF1Acreate\u3001set-images\u3001confirm-lock",
|
|
2832
|
+
" buke shorts <\u5B50\u547D\u4EE4> [\u53C2\u6570] \u6E32\u67D3\u77ED\u7247\uFF1Acatalog\u3001upload\u3001quote\u3001order\u3001status\u3001download\u3001cancel",
|
|
2833
|
+
" buke videos <\u5B50\u547D\u4EE4> [\u53C2\u6570] \u5546\u54C1\u89C6\u9891\uFF1Acreate\u3001status\u3001message\u3001confirm\u3001download",
|
|
2834
|
+
" buke drama <\u5B50\u547D\u4EE4> [\u53C2\u6570] \u77ED\u5267\uFF1Acreate\u3001status\u3001quote\u3001confirm\u3001cancel\u3001download",
|
|
1113
2835
|
" buke --help | -h \u663E\u793A\u8FD9\u4EFD\u8BF4\u660E\uFF1Bbuke <\u547D\u4EE4> --help \u770B\u5355\u6761\u547D\u4EE4",
|
|
1114
2836
|
" buke --version | -v \u663E\u793A\u7248\u672C\u53F7",
|
|
1115
2837
|
"",
|
|
@@ -1122,7 +2844,7 @@ var GENERAL_HELP = [
|
|
|
1122
2844
|
...KEY_HOWTO,
|
|
1123
2845
|
"",
|
|
1124
2846
|
"\u73AF\u5883\u53D8\u91CF\uFF1A",
|
|
1125
|
-
" BUKE_API_KEY API \u5BC6\u94A5\uFF1B\u8BBE\u4E86\u5B83\uFF0Clogin \u548C
|
|
2847
|
+
" BUKE_API_KEY API \u5BC6\u94A5\uFF1B\u8BBE\u4E86\u5B83\uFF0Clogin \u548C\u522B\u7684\u547D\u4EE4\u90FD\u76F4\u63A5\u7528\u5B83",
|
|
1126
2848
|
" BUKE_BASE_URL \u670D\u52A1\u5730\u5740\uFF0C\u4F5C\u7528\u540C --base-url",
|
|
1127
2849
|
" BUKE_CONFIG_DIR \u4FDD\u5B58\u51ED\u636E\u7684\u76EE\u5F55\uFF0C\u8981\u5199\u7EDD\u5BF9\u8DEF\u5F84\u3002\u4E0D\u8BBE\u65F6\u662F $XDG_CONFIG_HOME/buke\uFF1B",
|
|
1128
2850
|
" \u8FD9\u4E2A\u4E5F\u6CA1\u8BBE\u5C31\u662F ~/.config/buke\uFF08Windows \u4E0A\u662F %APPDATA%\\buke\uFF09",
|
|
@@ -1134,34 +2856,63 @@ var GENERAL_HELP = [
|
|
|
1134
2856
|
" 4 \u4F59\u989D\u4E0D\u8DB3",
|
|
1135
2857
|
" 5 \u670D\u52A1\u7AEF\u6216\u7F51\u7EDC\u51FA\u9519\uFF1B\u672C\u673A\u7684\u51ED\u636E\u6587\u4EF6\u8BFB\u4E0D\u4E86\u3001\u5199\u4E0D\u4E86\u4E5F\u662F\u8FD9\u4E2A\u7801",
|
|
1136
2858
|
" 6 \u62A5\u4EF7\u53D8\u4E86",
|
|
1137
|
-
" 7 \u8BF7\u6C42\u592A\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5",
|
|
2859
|
+
" 7 \u8BF7\u6C42\u592A\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\uFF1B\u6216\u8FD9\u4E00\u6B65\u8FD8\u6CA1\u5230\u65F6\u5019\uFF0C\u7A0D\u540E\u518D\u6765",
|
|
1138
2860
|
" 8 \u7B49\u5F85\u8D85\u65F6",
|
|
1139
2861
|
" 9 \u4EFB\u52A1\u5931\u8D25",
|
|
1140
2862
|
" 10 \u8981\u627E\u7684\u4E1C\u897F\u4E0D\u5B58\u5728",
|
|
1141
2863
|
" 130 \u88AB Ctrl-C \u6253\u65AD",
|
|
1142
2864
|
"",
|
|
1143
|
-
"\
|
|
2865
|
+
"\u8FD9\u4E00\u7248\u80FD\u4E0B\u5355\u3001\u67E5\u8FDB\u5EA6\u3001\u4E0B\u8F7D\u6210\u7247\uFF08\u6E32\u67D3\u77ED\u7247\u3001\u5546\u54C1\u89C6\u9891\u4E0E\u77ED\u5267\u4E09\u6761\u7EBF\uFF09\u3002"
|
|
1144
2866
|
].join("\n");
|
|
1145
2867
|
var MAX_ECHO_LENGTH = 40;
|
|
1146
2868
|
function echo(item) {
|
|
1147
2869
|
return item.length > MAX_ECHO_LENGTH ? `${item.slice(0, MAX_ECHO_LENGTH)}\u2026` : item;
|
|
1148
2870
|
}
|
|
2871
|
+
var GLOBAL_OPTIONS = /* @__PURE__ */ new Set(["help", "version", "json", "base-url"]);
|
|
2872
|
+
var STRING_OPTIONS = /* @__PURE__ */ new Set([
|
|
2873
|
+
"base-url",
|
|
2874
|
+
"idempotency-key",
|
|
2875
|
+
"name",
|
|
2876
|
+
"category",
|
|
2877
|
+
"front",
|
|
2878
|
+
"side",
|
|
2879
|
+
"back",
|
|
2880
|
+
"detail",
|
|
2881
|
+
"color",
|
|
2882
|
+
"silhouette",
|
|
2883
|
+
"material",
|
|
2884
|
+
"template",
|
|
2885
|
+
"props",
|
|
2886
|
+
"quote-hash",
|
|
2887
|
+
"timeout",
|
|
2888
|
+
"out",
|
|
2889
|
+
"product",
|
|
2890
|
+
"intent",
|
|
2891
|
+
"duration",
|
|
2892
|
+
"resolution",
|
|
2893
|
+
"speed",
|
|
2894
|
+
"aspect-ratio",
|
|
2895
|
+
"style-preset",
|
|
2896
|
+
"text",
|
|
2897
|
+
"genre",
|
|
2898
|
+
"brief"
|
|
2899
|
+
]);
|
|
2900
|
+
var BOOLEAN_OPTIONS = /* @__PURE__ */ new Set(["help", "version", "json", "wait", "yes"]);
|
|
1149
2901
|
function parse(argv) {
|
|
1150
2902
|
try {
|
|
2903
|
+
const options = {};
|
|
2904
|
+
for (const name2 of STRING_OPTIONS) options[name2] = { type: "string" };
|
|
2905
|
+
for (const name2 of BOOLEAN_OPTIONS) options[name2] = { type: "boolean", ...name2 === "help" ? { short: "h" } : name2 === "version" ? { short: "v" } : {} };
|
|
1151
2906
|
const { values, positionals } = parseArgs({
|
|
1152
2907
|
args: argv,
|
|
1153
|
-
options
|
|
1154
|
-
help: { type: "boolean", short: "h" },
|
|
1155
|
-
version: { type: "boolean", short: "v" },
|
|
1156
|
-
json: { type: "boolean" },
|
|
1157
|
-
"base-url": { type: "string" }
|
|
1158
|
-
},
|
|
2908
|
+
options,
|
|
1159
2909
|
strict: true,
|
|
1160
2910
|
allowPositionals: true
|
|
1161
2911
|
});
|
|
1162
2912
|
return {
|
|
1163
2913
|
command: positionals[0],
|
|
1164
|
-
|
|
2914
|
+
positionals,
|
|
2915
|
+
values,
|
|
1165
2916
|
help: values.help === true,
|
|
1166
2917
|
version: values.version === true,
|
|
1167
2918
|
baseUrl: values["base-url"]
|
|
@@ -1193,9 +2944,21 @@ async function dispatch(argv, io, out) {
|
|
|
1193
2944
|
const parsed = parse(argv);
|
|
1194
2945
|
const command = parsed.command !== void 0 && Object.hasOwn(COMMANDS, parsed.command) ? COMMANDS[parsed.command] : void 0;
|
|
1195
2946
|
if (parsed.command !== void 0 && !command) throw usageError(`\u4E0D\u8BA4\u8BC6\u7684\u547D\u4EE4 ${echo(parsed.command)}`);
|
|
1196
|
-
|
|
1197
|
-
if (command
|
|
1198
|
-
|
|
2947
|
+
const args = parsed.positionals.slice(1);
|
|
2948
|
+
if (command) {
|
|
2949
|
+
if (command.positionals.length === 0 && args.length > 0) {
|
|
2950
|
+
throw usageError(`${parsed.command} \u540E\u9762\u4E0D\u63A5\u522B\u7684\u53C2\u6570`);
|
|
2951
|
+
}
|
|
2952
|
+
if (args.length > command.positionals.length) {
|
|
2953
|
+
throw usageError(`${parsed.command} \u540E\u9762\u7684\u53C2\u6570\u591A\u4E86\uFF08${echo(args[command.positionals.length])}\uFF09`);
|
|
2954
|
+
}
|
|
2955
|
+
if (!command.acceptsBaseUrl && parsed.baseUrl !== void 0) {
|
|
2956
|
+
throw usageError(`${parsed.command} \u4E0D\u8BA4\u8BC6\u9009\u9879 --base-url`);
|
|
2957
|
+
}
|
|
2958
|
+
for (const [name2, value] of Object.entries(parsed.values)) {
|
|
2959
|
+
if (value === void 0 || GLOBAL_OPTIONS.has(name2)) continue;
|
|
2960
|
+
if (!command.options.includes(name2)) throw usageError(`${parsed.command} \u4E0D\u8BA4\u8BC6\u9009\u9879 --${name2}`);
|
|
2961
|
+
}
|
|
1199
2962
|
}
|
|
1200
2963
|
if (parsed.help || !command && !parsed.version) {
|
|
1201
2964
|
const text = command ? command.help : GENERAL_HELP;
|
|
@@ -1206,7 +2969,7 @@ async function dispatch(argv, io, out) {
|
|
|
1206
2969
|
out.result([`${PACKAGE_NAME}/${VERSION}`], { name: PACKAGE_NAME, version: VERSION });
|
|
1207
2970
|
return;
|
|
1208
2971
|
}
|
|
1209
|
-
if (command) await command.run({ io, out, baseUrl: parsed.baseUrl });
|
|
2972
|
+
if (command) await command.run({ io, out, baseUrl: parsed.baseUrl, args, values: parsed.values });
|
|
1210
2973
|
}
|
|
1211
2974
|
async function run(argv, io) {
|
|
1212
2975
|
let out;
|