@kolmopdf/mcp-server 1.2.1 → 1.2.2
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 +3 -1
- package/dist/index.cjs +91 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +77 -35
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,13 +16,15 @@ MCP server for [KolmoPDF](https://www.kolmopdf.com) — high-fidelity PDF→Mark
|
|
|
16
16
|
}
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
On macOS GUI clients, `npx` may not be on the app's PATH even when it works in Terminal. Run `command -v npx` and use that absolute path as `command`. Put `KOLMOPDF_API_KEY` in the client's private MCP `env`, then fully restart the app.
|
|
20
|
+
|
|
19
21
|
## Environment variables
|
|
20
22
|
|
|
21
23
|
| Variable | Required | Default | Description |
|
|
22
24
|
| --- | --- | --- | --- |
|
|
23
25
|
| `KOLMOPDF_API_KEY` | yes | — | API key from https://www.kolmopdf.com/api-keys |
|
|
24
26
|
| `KOLMOPDF_BASE_URL` | no | `https://www.kolmopdf.com` | Override for enterprise/debug |
|
|
25
|
-
| `KOLMOPDF_OUTPUT_DIR` | no |
|
|
27
|
+
| `KOLMOPDF_OUTPUT_DIR` | no | `~/kolmopdf-output` | Absolute or cwd-relative extraction root |
|
|
26
28
|
| `KOLMOPDF_POLL_INTERVAL_MS` | no | `2000` | Status poll interval |
|
|
27
29
|
| `KOLMOPDF_MAX_POLL_MINUTES` | no | `30` | Max client-side wait |
|
|
28
30
|
| `KOLMOPDF_HTTP_TIMEOUT_MS` | no | `60000` | Per-call HTTP timeout |
|
package/dist/index.cjs
CHANGED
|
@@ -38,19 +38,19 @@ var ERROR_SPECS = {
|
|
|
38
38
|
// --- API codes ---
|
|
39
39
|
invalid_api_key: {
|
|
40
40
|
message: "API key is missing or invalid.",
|
|
41
|
-
remediation: "Create a key at https://www.kolmopdf.com/api-keys
|
|
41
|
+
remediation: "Create a key at https://www.kolmopdf.com/api-keys. Every account, including PAYG, can create one API key.",
|
|
42
42
|
httpStatus: 401,
|
|
43
43
|
source: "api"
|
|
44
44
|
},
|
|
45
45
|
insufficient_points: {
|
|
46
46
|
message: "Not enough credits.",
|
|
47
|
-
remediation: "
|
|
47
|
+
remediation: "Buy one-time credits at https://www.kolmopdf.com/credits \u2014 no subscription required. Credits are shared with the web account. Check the API key spending limit separately. Never start a purchase without the user's confirmation.",
|
|
48
48
|
httpStatus: 402,
|
|
49
49
|
source: "api"
|
|
50
50
|
},
|
|
51
51
|
points_deduction_failed: {
|
|
52
52
|
message: "Credit deduction failed.",
|
|
53
|
-
remediation: "
|
|
53
|
+
remediation: "Check your balance and API key limit. Buy one-time credits at https://www.kolmopdf.com/credits; do not retry a paid operation or purchase automatically.",
|
|
54
54
|
httpStatus: 402,
|
|
55
55
|
source: "api"
|
|
56
56
|
},
|
|
@@ -474,9 +474,11 @@ var KolmoPdfClient = class {
|
|
|
474
474
|
};
|
|
475
475
|
|
|
476
476
|
// src/config.ts
|
|
477
|
+
var import_node_os = require("os");
|
|
478
|
+
var import_node_path = require("path");
|
|
477
479
|
var DEFAULTS = {
|
|
478
480
|
baseUrl: "https://www.kolmopdf.com",
|
|
479
|
-
outputDir: "
|
|
481
|
+
outputDir: (0, import_node_path.resolve)((0, import_node_os.homedir)(), "kolmopdf-output"),
|
|
480
482
|
pollIntervalMs: 2e3,
|
|
481
483
|
maxPollMinutes: 30,
|
|
482
484
|
httpTimeoutMs: 6e4,
|
|
@@ -490,12 +492,16 @@ function intFromEnv(value, fallback) {
|
|
|
490
492
|
function trimTrailingSlash(url) {
|
|
491
493
|
return url.replace(/\/+$/, "");
|
|
492
494
|
}
|
|
495
|
+
function normalizeApiKey(value) {
|
|
496
|
+
const trimmed = value?.trim();
|
|
497
|
+
if (!trimmed || /^\$\{KOLMOPDF_API_KEY(?::-[^}]*)?\}$/.test(trimmed)) return void 0;
|
|
498
|
+
return trimmed;
|
|
499
|
+
}
|
|
493
500
|
function loadConfig(env = process.env) {
|
|
494
|
-
const apiKeyRaw = env.KOLMOPDF_API_KEY?.trim();
|
|
495
501
|
return {
|
|
496
|
-
apiKey:
|
|
502
|
+
apiKey: normalizeApiKey(env.KOLMOPDF_API_KEY),
|
|
497
503
|
baseUrl: trimTrailingSlash(env.KOLMOPDF_BASE_URL?.trim() || DEFAULTS.baseUrl),
|
|
498
|
-
outputDir: env.KOLMOPDF_OUTPUT_DIR?.trim() || DEFAULTS.outputDir,
|
|
504
|
+
outputDir: (0, import_node_path.resolve)(env.KOLMOPDF_OUTPUT_DIR?.trim() || DEFAULTS.outputDir),
|
|
499
505
|
pollIntervalMs: intFromEnv(env.KOLMOPDF_POLL_INTERVAL_MS, DEFAULTS.pollIntervalMs),
|
|
500
506
|
maxPollMinutes: intFromEnv(env.KOLMOPDF_MAX_POLL_MINUTES, DEFAULTS.maxPollMinutes),
|
|
501
507
|
httpTimeoutMs: intFromEnv(env.KOLMOPDF_HTTP_TIMEOUT_MS, DEFAULTS.httpTimeoutMs),
|
|
@@ -533,9 +539,23 @@ async function checkBalanceHandler(_args, ctx) {
|
|
|
533
539
|
// src/tools/convert.ts
|
|
534
540
|
var import_node_fs = require("fs");
|
|
535
541
|
var import_promises4 = require("fs/promises");
|
|
536
|
-
var
|
|
542
|
+
var import_node_path4 = require("path");
|
|
537
543
|
var import_zod2 = require("zod");
|
|
538
544
|
|
|
545
|
+
// src/output.ts
|
|
546
|
+
var import_node_path2 = require("path");
|
|
547
|
+
function resolveOutputRoot(baseDir, subdir) {
|
|
548
|
+
const root = (0, import_node_path2.resolve)(baseDir);
|
|
549
|
+
const candidate = (0, import_node_path2.resolve)(root, subdir);
|
|
550
|
+
const rel = (0, import_node_path2.relative)(root, candidate);
|
|
551
|
+
if (rel.startsWith("..") || (0, import_node_path2.isAbsolute)(rel)) {
|
|
552
|
+
throw new KolmoPdfError("client_local_validation", {
|
|
553
|
+
message: "output_subdir must stay inside KOLMOPDF_OUTPUT_DIR."
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
return candidate;
|
|
557
|
+
}
|
|
558
|
+
|
|
539
559
|
// src/pages.ts
|
|
540
560
|
var import_promises2 = require("fs/promises");
|
|
541
561
|
var import_pdf_lib = require("pdf-lib");
|
|
@@ -577,7 +597,7 @@ function isRetryable(err) {
|
|
|
577
597
|
return false;
|
|
578
598
|
}
|
|
579
599
|
function sleep(ms) {
|
|
580
|
-
return new Promise((
|
|
600
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
581
601
|
}
|
|
582
602
|
async function fetchStatusWithRetry(client, taskId) {
|
|
583
603
|
for (let attempt = 1; attempt <= RETRY_POLICY.maxAttempts; attempt++) {
|
|
@@ -716,7 +736,7 @@ async function pollUntilComplete(ctx) {
|
|
|
716
736
|
|
|
717
737
|
// src/sniff.ts
|
|
718
738
|
var import_promises3 = require("fs/promises");
|
|
719
|
-
var
|
|
739
|
+
var import_node_path3 = require("path");
|
|
720
740
|
var EXT = {
|
|
721
741
|
zip: ".zip",
|
|
722
742
|
pdf: ".pdf",
|
|
@@ -780,10 +800,13 @@ function normalizeFormat(targetFormat) {
|
|
|
780
800
|
return targetFormat;
|
|
781
801
|
}
|
|
782
802
|
}
|
|
803
|
+
function resolveConvertKind(sniffedKind, targetFormat) {
|
|
804
|
+
return normalizeFormat(targetFormat) === "docx" && sniffedKind === "zip" ? "docx" : sniffedKind;
|
|
805
|
+
}
|
|
783
806
|
async function convertHandler(args, ctx) {
|
|
784
807
|
const client = ctx.getClient();
|
|
785
|
-
const filePath = (0,
|
|
786
|
-
const filename = (0,
|
|
808
|
+
const filePath = (0, import_node_path4.resolve)(args.file_path);
|
|
809
|
+
const filename = (0, import_node_path4.basename)(filePath);
|
|
787
810
|
const fileSize = await readFileSize(filePath);
|
|
788
811
|
if (fileSize > MAX_FILE_BYTES) {
|
|
789
812
|
throw new KolmoPdfError("convert_file_too_large");
|
|
@@ -814,13 +837,14 @@ async function convertHandler(args, ctx) {
|
|
|
814
837
|
});
|
|
815
838
|
await ctx.progress?.report("[downloading] Fetching converted file...");
|
|
816
839
|
const subdir = args.output_subdir || taskId;
|
|
817
|
-
const outputRoot = (
|
|
840
|
+
const outputRoot = resolveOutputRoot(ctx.config.outputDir, subdir);
|
|
818
841
|
(0, import_node_fs.mkdirSync)(outputRoot, { recursive: true });
|
|
819
|
-
const tempPath = (0,
|
|
842
|
+
const tempPath = (0, import_node_path4.join)(outputRoot, "download.bin");
|
|
820
843
|
const ws = (0, import_node_fs.createWriteStream)(tempPath);
|
|
821
844
|
await client.download(taskId, ws, { destPath: tempPath });
|
|
822
|
-
const
|
|
823
|
-
const
|
|
845
|
+
const sniffedKind = await sniffFile(tempPath);
|
|
846
|
+
const kind = resolveConvertKind(sniffedKind, args.target_format);
|
|
847
|
+
const outputPath = (0, import_node_path4.join)(outputRoot, `result${extensionForKind(kind)}`);
|
|
824
848
|
await (0, import_promises4.rename)(tempPath, outputPath);
|
|
825
849
|
const output = {
|
|
826
850
|
task_id: taskId,
|
|
@@ -836,7 +860,7 @@ async function convertHandler(args, ctx) {
|
|
|
836
860
|
}
|
|
837
861
|
|
|
838
862
|
// src/tools/estimate-cost.ts
|
|
839
|
-
var
|
|
863
|
+
var import_node_path5 = require("path");
|
|
840
864
|
var import_zod3 = require("zod");
|
|
841
865
|
var estimateCostName = "kolmopdf_estimate_cost";
|
|
842
866
|
var estimateCostDescription = "Estimate the credit cost of a KolmoPDF operation before running it. Reads page count locally and checks the current balance. Does not spend credits.";
|
|
@@ -866,7 +890,7 @@ async function estimateCostHandler(args, ctx) {
|
|
|
866
890
|
const client = ctx.getClient();
|
|
867
891
|
let pages = null;
|
|
868
892
|
if (args.operation !== "convert") {
|
|
869
|
-
const filePath = (0,
|
|
893
|
+
const filePath = (0, import_node_path5.resolve)(args.file_path);
|
|
870
894
|
pages = await readPageCount(filePath);
|
|
871
895
|
}
|
|
872
896
|
const estimatedCredits = estimateCredits(args.operation, pages ?? 1);
|
|
@@ -900,12 +924,12 @@ async function getTaskStatusHandler(args, ctx) {
|
|
|
900
924
|
// src/tools/parse-pdf.ts
|
|
901
925
|
var import_node_fs3 = require("fs");
|
|
902
926
|
var import_promises6 = require("fs/promises");
|
|
903
|
-
var
|
|
927
|
+
var import_node_path7 = require("path");
|
|
904
928
|
var import_zod5 = require("zod");
|
|
905
929
|
|
|
906
930
|
// src/extract.ts
|
|
907
931
|
var import_node_fs2 = require("fs");
|
|
908
|
-
var
|
|
932
|
+
var import_node_path6 = require("path");
|
|
909
933
|
var import_promises5 = require("stream/promises");
|
|
910
934
|
var import_yauzl = require("yauzl");
|
|
911
935
|
function pickPrimaryMarkdownPath(candidates) {
|
|
@@ -925,6 +949,24 @@ function pickPrimaryMarkdownPath(candidates) {
|
|
|
925
949
|
scored.sort((a, b) => b.score - a.score);
|
|
926
950
|
return scored[0]?.path ?? null;
|
|
927
951
|
}
|
|
952
|
+
function safeZipEntryPath(destDir, entryName) {
|
|
953
|
+
const normalized = entryName.replace(/\\/g, "/");
|
|
954
|
+
const segments = normalized.split("/").filter((segment) => segment && segment !== ".");
|
|
955
|
+
if (normalized.includes("\0") || normalized.startsWith("/") || /^[A-Za-z]:/.test(normalized) || segments.includes("..")) {
|
|
956
|
+
throw new KolmoPdfError("client_extract_failed", {
|
|
957
|
+
message: `Unsafe ZIP entry path: ${entryName}`
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
const root = (0, import_node_path6.resolve)(destDir);
|
|
961
|
+
const entryPath = (0, import_node_path6.resolve)(root, ...segments);
|
|
962
|
+
const rel = (0, import_node_path6.relative)(root, entryPath);
|
|
963
|
+
if (rel.startsWith("..") || (0, import_node_path6.isAbsolute)(rel)) {
|
|
964
|
+
throw new KolmoPdfError("client_extract_failed", {
|
|
965
|
+
message: `Unsafe ZIP entry path: ${entryName}`
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
return entryPath;
|
|
969
|
+
}
|
|
928
970
|
async function extractZip(zipPath, destDir) {
|
|
929
971
|
(0, import_node_fs2.mkdirSync)(destDir, { recursive: true });
|
|
930
972
|
const zipFile = await openZip(zipPath);
|
|
@@ -932,7 +974,7 @@ async function extractZip(zipPath, destDir) {
|
|
|
932
974
|
const mdCandidates = [];
|
|
933
975
|
let imagesDir = null;
|
|
934
976
|
for await (const entry of iterEntries(zipFile)) {
|
|
935
|
-
const entryPath = (
|
|
977
|
+
const entryPath = safeZipEntryPath(destDir, entry.fileName);
|
|
936
978
|
if (entry.fileName.endsWith("/")) {
|
|
937
979
|
(0, import_node_fs2.mkdirSync)(entryPath, { recursive: true });
|
|
938
980
|
if (entry.fileName.includes("images")) {
|
|
@@ -940,7 +982,7 @@ async function extractZip(zipPath, destDir) {
|
|
|
940
982
|
}
|
|
941
983
|
continue;
|
|
942
984
|
}
|
|
943
|
-
(0, import_node_fs2.mkdirSync)((0,
|
|
985
|
+
(0, import_node_fs2.mkdirSync)((0, import_node_path6.dirname)(entryPath), { recursive: true });
|
|
944
986
|
const readStream = await openReadStream(zipFile, entry);
|
|
945
987
|
const writeStream = (0, import_node_fs2.createWriteStream)(entryPath);
|
|
946
988
|
await (0, import_promises5.pipeline)(readStream, writeStream);
|
|
@@ -955,36 +997,36 @@ async function extractZip(zipPath, destDir) {
|
|
|
955
997
|
}
|
|
956
998
|
if (!imagesDir && /images\//i.test(entry.fileName)) {
|
|
957
999
|
const prefix = entry.fileName.split("images/")[0] ?? "";
|
|
958
|
-
imagesDir = (0,
|
|
1000
|
+
imagesDir = (0, import_node_path6.join)(destDir, prefix, "images");
|
|
959
1001
|
}
|
|
960
1002
|
}
|
|
961
1003
|
const markdownPath = pickPrimaryMarkdownPath(mdCandidates);
|
|
962
1004
|
return { markdownPath, imagesDir, outputRoot: destDir, files };
|
|
963
1005
|
}
|
|
964
1006
|
function openZip(path) {
|
|
965
|
-
return new Promise((
|
|
1007
|
+
return new Promise((resolve8, reject) => {
|
|
966
1008
|
(0, import_yauzl.open)(path, { lazyEntries: true }, (err, zf) => {
|
|
967
1009
|
if (err || !zf) return reject(err ?? new Error("Failed to open zip"));
|
|
968
|
-
|
|
1010
|
+
resolve8(zf);
|
|
969
1011
|
});
|
|
970
1012
|
});
|
|
971
1013
|
}
|
|
972
1014
|
async function* iterEntries(zipFile) {
|
|
973
|
-
let
|
|
1015
|
+
let resolve8 = null;
|
|
974
1016
|
const queue = [];
|
|
975
1017
|
zipFile.on("entry", (entry) => {
|
|
976
|
-
if (
|
|
977
|
-
const r =
|
|
978
|
-
|
|
1018
|
+
if (resolve8) {
|
|
1019
|
+
const r = resolve8;
|
|
1020
|
+
resolve8 = null;
|
|
979
1021
|
r(entry);
|
|
980
1022
|
} else {
|
|
981
1023
|
queue.push(entry);
|
|
982
1024
|
}
|
|
983
1025
|
});
|
|
984
1026
|
zipFile.on("end", () => {
|
|
985
|
-
if (
|
|
986
|
-
const r =
|
|
987
|
-
|
|
1027
|
+
if (resolve8) {
|
|
1028
|
+
const r = resolve8;
|
|
1029
|
+
resolve8 = null;
|
|
988
1030
|
r(null);
|
|
989
1031
|
} else {
|
|
990
1032
|
queue.push(null);
|
|
@@ -993,7 +1035,7 @@ async function* iterEntries(zipFile) {
|
|
|
993
1035
|
zipFile.readEntry();
|
|
994
1036
|
while (true) {
|
|
995
1037
|
const entry = queue.length > 0 ? queue.shift() : await new Promise((r) => {
|
|
996
|
-
|
|
1038
|
+
resolve8 = r;
|
|
997
1039
|
});
|
|
998
1040
|
if (entry === null) break;
|
|
999
1041
|
yield entry;
|
|
@@ -1001,10 +1043,10 @@ async function* iterEntries(zipFile) {
|
|
|
1001
1043
|
}
|
|
1002
1044
|
}
|
|
1003
1045
|
function openReadStream(zipFile, entry) {
|
|
1004
|
-
return new Promise((
|
|
1046
|
+
return new Promise((resolve8, reject) => {
|
|
1005
1047
|
zipFile.openReadStream(entry, (err, stream) => {
|
|
1006
1048
|
if (err || !stream) return reject(err ?? new Error("Failed to open entry stream"));
|
|
1007
|
-
|
|
1049
|
+
resolve8(stream);
|
|
1008
1050
|
});
|
|
1009
1051
|
});
|
|
1010
1052
|
}
|
|
@@ -1029,8 +1071,8 @@ var parsePdfInputSchema = import_zod5.z.object({
|
|
|
1029
1071
|
});
|
|
1030
1072
|
async function parsePdfHandler(args, ctx) {
|
|
1031
1073
|
const client = ctx.getClient();
|
|
1032
|
-
const filePath = (0,
|
|
1033
|
-
const filename = (0,
|
|
1074
|
+
const filePath = (0, import_node_path7.resolve)(args.file_path);
|
|
1075
|
+
const filename = (0, import_node_path7.basename)(filePath);
|
|
1034
1076
|
const fileSize = await readFileSize(filePath);
|
|
1035
1077
|
if (fileSize > MAX_FILE_BYTES) {
|
|
1036
1078
|
throw new KolmoPdfError("parse_file_too_large");
|
|
@@ -1069,9 +1111,9 @@ async function parsePdfHandler(args, ctx) {
|
|
|
1069
1111
|
});
|
|
1070
1112
|
await ctx.progress?.report("[downloading] Fetching result...");
|
|
1071
1113
|
const subdir = args.output_subdir || taskId;
|
|
1072
|
-
const outputRoot = (
|
|
1114
|
+
const outputRoot = resolveOutputRoot(ctx.config.outputDir, subdir);
|
|
1073
1115
|
(0, import_node_fs3.mkdirSync)(outputRoot, { recursive: true });
|
|
1074
|
-
const downloadPath = (0,
|
|
1116
|
+
const downloadPath = (0, import_node_path7.join)(outputRoot, "download.bin");
|
|
1075
1117
|
const ws = (0, import_node_fs3.createWriteStream)(downloadPath);
|
|
1076
1118
|
await client.download(taskId, ws, { destPath: downloadPath });
|
|
1077
1119
|
let markdownPath;
|
|
@@ -1079,14 +1121,14 @@ async function parsePdfHandler(args, ctx) {
|
|
|
1079
1121
|
let outputType;
|
|
1080
1122
|
const kind = await sniffFile(downloadPath);
|
|
1081
1123
|
if (kind === "zip") {
|
|
1082
|
-
const zipPath = (0,
|
|
1124
|
+
const zipPath = (0, import_node_path7.join)(outputRoot, "result.zip");
|
|
1083
1125
|
await (0, import_promises6.rename)(downloadPath, zipPath);
|
|
1084
1126
|
const extracted = await extractZip(zipPath, outputRoot);
|
|
1085
|
-
markdownPath = extracted.markdownPath || (0,
|
|
1127
|
+
markdownPath = extracted.markdownPath || (0, import_node_path7.join)(outputRoot, "result.md");
|
|
1086
1128
|
imagesDir = extracted.imagesDir;
|
|
1087
1129
|
outputType = "zip_extracted";
|
|
1088
1130
|
} else {
|
|
1089
|
-
markdownPath = (0,
|
|
1131
|
+
markdownPath = (0, import_node_path7.join)(outputRoot, "result.md");
|
|
1090
1132
|
await (0, import_promises6.rename)(downloadPath, markdownPath);
|
|
1091
1133
|
outputType = "markdown_file";
|
|
1092
1134
|
}
|
|
@@ -1113,7 +1155,7 @@ async function parsePdfHandler(args, ctx) {
|
|
|
1113
1155
|
// src/tools/translate-pdf.ts
|
|
1114
1156
|
var import_node_fs4 = require("fs");
|
|
1115
1157
|
var import_promises7 = require("fs/promises");
|
|
1116
|
-
var
|
|
1158
|
+
var import_node_path8 = require("path");
|
|
1117
1159
|
var import_zod6 = require("zod");
|
|
1118
1160
|
var translatePdfName = "kolmopdf_translate_pdf";
|
|
1119
1161
|
var translatePdfDescription = "Translate a PDF while preserving its original layout via KolmoPDF. Produces a translated PDF, or a ZIP of PDFs when multiple layout modes are requested.";
|
|
@@ -1128,8 +1170,8 @@ var translatePdfInputSchema = import_zod6.z.object({
|
|
|
1128
1170
|
});
|
|
1129
1171
|
async function translatePdfHandler(args, ctx) {
|
|
1130
1172
|
const client = ctx.getClient();
|
|
1131
|
-
const filePath = (0,
|
|
1132
|
-
const filename = (0,
|
|
1173
|
+
const filePath = (0, import_node_path8.resolve)(args.file_path);
|
|
1174
|
+
const filename = (0, import_node_path8.basename)(filePath);
|
|
1133
1175
|
const fileSize = await readFileSize(filePath);
|
|
1134
1176
|
if (fileSize > MAX_FILE_BYTES) {
|
|
1135
1177
|
throw new KolmoPdfError("translate_pdf_file_too_large");
|
|
@@ -1164,13 +1206,13 @@ async function translatePdfHandler(args, ctx) {
|
|
|
1164
1206
|
});
|
|
1165
1207
|
await ctx.progress?.report("[downloading] Fetching translated result...");
|
|
1166
1208
|
const subdir = args.output_subdir || taskId;
|
|
1167
|
-
const outputRoot = (
|
|
1209
|
+
const outputRoot = resolveOutputRoot(ctx.config.outputDir, subdir);
|
|
1168
1210
|
(0, import_node_fs4.mkdirSync)(outputRoot, { recursive: true });
|
|
1169
|
-
const tempPath = (0,
|
|
1211
|
+
const tempPath = (0, import_node_path8.join)(outputRoot, "download.bin");
|
|
1170
1212
|
const ws = (0, import_node_fs4.createWriteStream)(tempPath);
|
|
1171
1213
|
await client.download(taskId, ws, { destPath: tempPath });
|
|
1172
1214
|
const kind = await sniffFile(tempPath);
|
|
1173
|
-
let translatedPdfPath = (0,
|
|
1215
|
+
let translatedPdfPath = (0, import_node_path8.join)(outputRoot, `translated${extensionForKind(kind)}`);
|
|
1174
1216
|
let archivePath;
|
|
1175
1217
|
await (0, import_promises7.rename)(tempPath, translatedPdfPath);
|
|
1176
1218
|
if (kind === "zip") {
|
|
@@ -1195,7 +1237,7 @@ async function translatePdfHandler(args, ctx) {
|
|
|
1195
1237
|
}
|
|
1196
1238
|
|
|
1197
1239
|
// src/index.ts
|
|
1198
|
-
var VERSION = "1.
|
|
1240
|
+
var VERSION = "1.2.2";
|
|
1199
1241
|
function buildContext() {
|
|
1200
1242
|
const config = loadConfig();
|
|
1201
1243
|
return {
|