bailian-cli-core 1.0.3 → 1.1.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/LICENSE +12 -11
- package/dist/index.d.mts +11 -5
- package/dist/index.mjs +58 -19
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
Apache License
|
|
2
3
|
Version 2.0, January 2004
|
|
3
4
|
http://www.apache.org/licenses/
|
|
@@ -137,8 +138,8 @@
|
|
|
137
138
|
|
|
138
139
|
6. Trademarks. This License does not grant permission to use the trade
|
|
139
140
|
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
-
except as required for
|
|
141
|
-
reproducing the content of the NOTICE file.
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
143
|
|
|
143
144
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
145
|
agreed to in writing, Licensor provides the Work (and each
|
|
@@ -163,15 +164,15 @@
|
|
|
163
164
|
has been advised of the possibility of such damages.
|
|
164
165
|
|
|
165
166
|
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
-
the Work or Derivative Works thereof, You may
|
|
167
|
-
fee for, acceptance of support, warranty, indemnity,
|
|
168
|
-
liability obligations and/or rights consistent with this
|
|
169
|
-
However, in accepting such obligations, You may act only
|
|
170
|
-
own behalf and on
|
|
171
|
-
and only if You agree to indemnify,
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
additional liability.
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
175
176
|
|
|
176
177
|
END OF TERMS AND CONDITIONS
|
|
177
178
|
|
package/dist/index.d.mts
CHANGED
|
@@ -711,6 +711,7 @@ interface RequestOpts {
|
|
|
711
711
|
stream?: boolean;
|
|
712
712
|
noAuth?: boolean;
|
|
713
713
|
async?: boolean;
|
|
714
|
+
signal?: AbortSignal;
|
|
714
715
|
}
|
|
715
716
|
declare function request(config: Config, opts: RequestOpts): Promise<Response>;
|
|
716
717
|
declare function requestJson<T>(config: Config, opts: RequestOpts): Promise<T>;
|
|
@@ -772,9 +773,11 @@ interface ConsoleGatewayRequest {
|
|
|
772
773
|
}
|
|
773
774
|
/**
|
|
774
775
|
* Invoke a Bailian **console** OpenAPI via the CLI gateway (`/cli/api.json`).
|
|
775
|
-
*
|
|
776
|
+
* `token` is the console `access_token` (from `bl auth login --console`); when
|
|
777
|
+
* omitted the request is sent without an Authorization header, which works for
|
|
778
|
+
* public console APIs that don't require a login session.
|
|
776
779
|
*/
|
|
777
|
-
declare function callConsoleGateway(config: Config, token: string, {
|
|
780
|
+
declare function callConsoleGateway(config: Config, token: string | undefined, {
|
|
778
781
|
api,
|
|
779
782
|
data,
|
|
780
783
|
region
|
|
@@ -825,6 +828,7 @@ interface UploadOptions {
|
|
|
825
828
|
apiKey: string;
|
|
826
829
|
model: string;
|
|
827
830
|
filePath: string;
|
|
831
|
+
signal?: AbortSignal;
|
|
828
832
|
}
|
|
829
833
|
/**
|
|
830
834
|
* Upload a local file to DashScope temporary storage and return the oss:// URL.
|
|
@@ -839,7 +843,9 @@ declare function isLocalFile(input: string): boolean;
|
|
|
839
843
|
* Resolve a file argument: if it's a local path, upload it and return the oss:// URL.
|
|
840
844
|
* If it's already a URL, return as-is.
|
|
841
845
|
*/
|
|
842
|
-
declare function resolveFileUrl(input: string, apiKey: string, model: string
|
|
846
|
+
declare function resolveFileUrl(input: string, apiKey: string, model: string, opts?: {
|
|
847
|
+
signal?: AbortSignal;
|
|
848
|
+
}): Promise<string>;
|
|
843
849
|
//#endregion
|
|
844
850
|
//#region src/types/command.d.ts
|
|
845
851
|
interface OptionDef {
|
|
@@ -855,7 +861,7 @@ interface Command {
|
|
|
855
861
|
options?: OptionDef[];
|
|
856
862
|
examples?: string[];
|
|
857
863
|
apiDocs?: string;
|
|
858
|
-
execute(config: Config, flags: GlobalFlags)
|
|
864
|
+
execute: (config: Config, flags: GlobalFlags) => Promise<void>;
|
|
859
865
|
}
|
|
860
866
|
interface CommandSpec {
|
|
861
867
|
name: string;
|
|
@@ -864,7 +870,7 @@ interface CommandSpec {
|
|
|
864
870
|
options?: OptionDef[];
|
|
865
871
|
examples?: string[];
|
|
866
872
|
apiDocs?: string;
|
|
867
|
-
run(config: Config, flags: GlobalFlags)
|
|
873
|
+
run: (config: Config, flags: GlobalFlags) => Promise<void>;
|
|
868
874
|
}
|
|
869
875
|
declare function defineCommand(spec: CommandSpec): Command;
|
|
870
876
|
/** Global flags shared by all commands — drives the parser's type resolution. */
|
package/dist/index.mjs
CHANGED
|
@@ -486,13 +486,13 @@ async function request(config, opts) {
|
|
|
486
486
|
console.error(`> x-dashscope-source-config: ${SOURCE_CONFIG}`);
|
|
487
487
|
}
|
|
488
488
|
}
|
|
489
|
-
const
|
|
489
|
+
const requestSignal = createRequestSignal((opts.timeout ?? config.timeout) * 1e3, opts.signal);
|
|
490
490
|
const res = await fetch(opts.url, {
|
|
491
491
|
method: opts.method ?? "GET",
|
|
492
492
|
headers,
|
|
493
493
|
body: opts.body ? isFormData ? opts.body : JSON.stringify(opts.body) : void 0,
|
|
494
|
-
signal:
|
|
495
|
-
});
|
|
494
|
+
signal: requestSignal.signal
|
|
495
|
+
}).finally(requestSignal.cleanup);
|
|
496
496
|
if (config.verbose) {
|
|
497
497
|
console.error(`< ${res.status} ${res.statusText}`);
|
|
498
498
|
const reqId = res.headers.get("x-request-id");
|
|
@@ -507,6 +507,22 @@ async function request(config, opts) {
|
|
|
507
507
|
}
|
|
508
508
|
return res;
|
|
509
509
|
}
|
|
510
|
+
function createRequestSignal(timeoutMs, parentSignal) {
|
|
511
|
+
const controller = new AbortController();
|
|
512
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
513
|
+
const abortFromParent = () => controller.abort(parentSignal?.reason);
|
|
514
|
+
const cleanup = () => {
|
|
515
|
+
clearTimeout(timeout);
|
|
516
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
517
|
+
};
|
|
518
|
+
if (parentSignal?.aborted) abortFromParent();
|
|
519
|
+
else parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
520
|
+
controller.signal.addEventListener("abort", cleanup, { once: true });
|
|
521
|
+
return {
|
|
522
|
+
signal: controller.signal,
|
|
523
|
+
cleanup
|
|
524
|
+
};
|
|
525
|
+
}
|
|
510
526
|
async function requestJson(config, opts) {
|
|
511
527
|
const res = await request(config, opts);
|
|
512
528
|
let data;
|
|
@@ -694,7 +710,9 @@ function buildGatewayParams(api, data) {
|
|
|
694
710
|
}
|
|
695
711
|
/**
|
|
696
712
|
* Invoke a Bailian **console** OpenAPI via the CLI gateway (`/cli/api.json`).
|
|
697
|
-
*
|
|
713
|
+
* `token` is the console `access_token` (from `bl auth login --console`); when
|
|
714
|
+
* omitted the request is sent without an Authorization header, which works for
|
|
715
|
+
* public console APIs that don't require a login session.
|
|
698
716
|
*/
|
|
699
717
|
async function callConsoleGateway(config, token, { api, data, region = "cn-beijing" }) {
|
|
700
718
|
const params = buildGatewayParams(api, data);
|
|
@@ -704,13 +722,14 @@ async function callConsoleGateway(config, token, { api, data, region = "cn-beiji
|
|
|
704
722
|
});
|
|
705
723
|
const timeoutMs = config.timeout * 1e3;
|
|
706
724
|
const gatewayBase = config.consoleGatewayUrl;
|
|
725
|
+
const headers = {
|
|
726
|
+
Accept: "*/*",
|
|
727
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
728
|
+
};
|
|
729
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
707
730
|
const res = await fetch(`${gatewayBase}/cli/api.json?action=${GATEWAY_ACTION}&product=${GATEWAY_PRODUCT}&api=${encodeURIComponent(api)}`, {
|
|
708
731
|
method: "POST",
|
|
709
|
-
headers
|
|
710
|
-
Accept: "*/*",
|
|
711
|
-
Authorization: `Bearer ${token}`,
|
|
712
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
713
|
-
},
|
|
732
|
+
headers,
|
|
714
733
|
body: body.toString(),
|
|
715
734
|
signal: AbortSignal.timeout(timeoutMs)
|
|
716
735
|
});
|
|
@@ -733,16 +752,17 @@ const UPLOAD_API = `${REGIONS.cn}/api/v1/uploads`;
|
|
|
733
752
|
/**
|
|
734
753
|
* Step 1: Fetch the upload policy (presigned credentials) from DashScope.
|
|
735
754
|
*/
|
|
736
|
-
async function getUploadPolicy(apiKey, model) {
|
|
755
|
+
async function getUploadPolicy(apiKey, model, signal) {
|
|
737
756
|
const url = `${UPLOAD_API}?action=getPolicy&model=${encodeURIComponent(model)}`;
|
|
757
|
+
const policySignal = combineWithTimeout(15e3, signal);
|
|
738
758
|
const res = await fetch(url, {
|
|
739
759
|
headers: {
|
|
740
760
|
Authorization: `Bearer ${apiKey}`,
|
|
741
761
|
"Content-Type": "application/json",
|
|
742
762
|
...trackingHeaders()
|
|
743
763
|
},
|
|
744
|
-
signal:
|
|
745
|
-
});
|
|
764
|
+
signal: policySignal.signal
|
|
765
|
+
}).finally(policySignal.cleanup);
|
|
746
766
|
if (!res.ok) {
|
|
747
767
|
const text = await res.text().catch(() => "");
|
|
748
768
|
throw new BailianError(`Failed to get upload policy (HTTP ${res.status}): ${text}`, ExitCode.GENERAL);
|
|
@@ -752,7 +772,7 @@ async function getUploadPolicy(apiKey, model) {
|
|
|
752
772
|
/**
|
|
753
773
|
* Step 2: Upload the file to OSS using the policy.
|
|
754
774
|
*/
|
|
755
|
-
async function uploadToOSS(policy, filePath) {
|
|
775
|
+
async function uploadToOSS(policy, filePath, signal) {
|
|
756
776
|
const fileName = basename(filePath);
|
|
757
777
|
const key = `${policy.upload_dir}/${fileName}`;
|
|
758
778
|
const fileData = readFileSync(filePath);
|
|
@@ -765,12 +785,13 @@ async function uploadToOSS(policy, filePath) {
|
|
|
765
785
|
form.append("key", key);
|
|
766
786
|
form.append("success_action_status", "200");
|
|
767
787
|
form.append("file", new Blob([fileData]), fileName);
|
|
788
|
+
const uploadSignal = combineWithTimeout(12e4, signal);
|
|
768
789
|
const res = await fetch(policy.upload_host, {
|
|
769
790
|
method: "POST",
|
|
770
791
|
headers: { ...trackingHeaders() },
|
|
771
792
|
body: form,
|
|
772
|
-
signal:
|
|
773
|
-
});
|
|
793
|
+
signal: uploadSignal.signal
|
|
794
|
+
}).finally(uploadSignal.cleanup);
|
|
774
795
|
if (!res.ok) {
|
|
775
796
|
const text = await res.text().catch(() => "");
|
|
776
797
|
throw new BailianError(`Failed to upload file to OSS (HTTP ${res.status}): ${text}`, ExitCode.GENERAL);
|
|
@@ -782,10 +803,10 @@ async function uploadToOSS(policy, filePath) {
|
|
|
782
803
|
* The URL is valid for 48 hours.
|
|
783
804
|
*/
|
|
784
805
|
async function uploadFile(opts) {
|
|
785
|
-
const { apiKey, model, filePath } = opts;
|
|
806
|
+
const { apiKey, model, filePath, signal } = opts;
|
|
786
807
|
if (!existsSync(filePath)) throw new BailianError(`File not found: ${filePath}`, ExitCode.USAGE);
|
|
787
808
|
if (!statSync(filePath).isFile()) throw new BailianError(`Not a file: ${filePath}`, ExitCode.USAGE);
|
|
788
|
-
return uploadToOSS(await getUploadPolicy(apiKey, model), filePath);
|
|
809
|
+
return uploadToOSS(await getUploadPolicy(apiKey, model, signal), filePath, signal);
|
|
789
810
|
}
|
|
790
811
|
/**
|
|
791
812
|
* Check if a string looks like a local file path (not a URL).
|
|
@@ -800,14 +821,31 @@ function isLocalFile(input) {
|
|
|
800
821
|
* Resolve a file argument: if it's a local path, upload it and return the oss:// URL.
|
|
801
822
|
* If it's already a URL, return as-is.
|
|
802
823
|
*/
|
|
803
|
-
async function resolveFileUrl(input, apiKey, model) {
|
|
824
|
+
async function resolveFileUrl(input, apiKey, model, opts = {}) {
|
|
804
825
|
if (!isLocalFile(input)) return input;
|
|
805
826
|
return uploadFile({
|
|
806
827
|
apiKey,
|
|
807
828
|
model,
|
|
808
|
-
filePath: input
|
|
829
|
+
filePath: input,
|
|
830
|
+
signal: opts.signal
|
|
809
831
|
});
|
|
810
832
|
}
|
|
833
|
+
function combineWithTimeout(timeoutMs, parentSignal) {
|
|
834
|
+
const controller = new AbortController();
|
|
835
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
836
|
+
const abortFromParent = () => controller.abort(parentSignal?.reason);
|
|
837
|
+
const cleanup = () => {
|
|
838
|
+
clearTimeout(timeout);
|
|
839
|
+
parentSignal?.removeEventListener("abort", abortFromParent);
|
|
840
|
+
};
|
|
841
|
+
if (parentSignal?.aborted) abortFromParent();
|
|
842
|
+
else parentSignal?.addEventListener("abort", abortFromParent, { once: true });
|
|
843
|
+
controller.signal.addEventListener("abort", cleanup, { once: true });
|
|
844
|
+
return {
|
|
845
|
+
signal: controller.signal,
|
|
846
|
+
cleanup
|
|
847
|
+
};
|
|
848
|
+
}
|
|
811
849
|
//#endregion
|
|
812
850
|
//#region src/types/command.ts
|
|
813
851
|
function defineCommand(spec) {
|
|
@@ -1969,6 +2007,7 @@ const PARAM_ALLOWLIST = new Set([
|
|
|
1969
2007
|
"pitch",
|
|
1970
2008
|
"rate",
|
|
1971
2009
|
"volume",
|
|
2010
|
+
"api",
|
|
1972
2011
|
"mode",
|
|
1973
2012
|
"download",
|
|
1974
2013
|
"noWait",
|
package/package.json
CHANGED