@verbatra/sdk 0.5.0 → 0.6.1
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/dist/index.cjs +416 -154
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +89 -14
- package/dist/index.d.ts +89 -14
- package/dist/index.js +416 -154
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -329,77 +329,76 @@ function checkPlaceholders(source, translated) {
|
|
|
329
329
|
reordered
|
|
330
330
|
};
|
|
331
331
|
}
|
|
332
|
-
var
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
var
|
|
337
|
-
var
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
var AUTH_FAILED_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
344
|
-
"AuthenticationError",
|
|
345
|
-
"PermissionDeniedError",
|
|
346
|
-
"AuthorizationError"
|
|
347
|
-
]);
|
|
348
|
-
var TIMEOUT_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
349
|
-
"APIConnectionTimeoutError",
|
|
350
|
-
"ConnectionError"
|
|
351
|
-
]);
|
|
352
|
-
var ABORT_ERROR_CLASS_NAMES = /* @__PURE__ */ new Set(["APIUserAbortError"]);
|
|
353
|
-
function getErrorStatus(error) {
|
|
354
|
-
if (typeof error !== "object" || error === null || !("status" in error)) {
|
|
355
|
-
return void 0;
|
|
332
|
+
var MIN_SOURCE_LENGTH = 8;
|
|
333
|
+
var MAX_LENGTH_MULTIPLE = 12;
|
|
334
|
+
var MAX_REPEAT_UNIT_LENGTH = 16;
|
|
335
|
+
var MIN_CONSECUTIVE_REPEATS = 8;
|
|
336
|
+
var REPEAT_COVERAGE_FRACTION = 0.5;
|
|
337
|
+
var MAX_SCAN_LENGTH = 8192;
|
|
338
|
+
function matchesUnit(text, a, b, unit) {
|
|
339
|
+
for (let i = 0; i < unit; i++) {
|
|
340
|
+
if (text[a + i] !== text[b + i]) {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
356
343
|
}
|
|
357
|
-
|
|
358
|
-
return typeof status === "number" ? status : void 0;
|
|
344
|
+
return true;
|
|
359
345
|
}
|
|
360
|
-
function
|
|
361
|
-
|
|
362
|
-
|
|
346
|
+
function countConsecutiveCopies(text, start, unit, scanLength) {
|
|
347
|
+
let copies = 1;
|
|
348
|
+
let next = start + unit;
|
|
349
|
+
while (next + unit <= scanLength && matchesUnit(text, start, next, unit)) {
|
|
350
|
+
copies++;
|
|
351
|
+
next += unit;
|
|
352
|
+
}
|
|
353
|
+
return copies;
|
|
354
|
+
}
|
|
355
|
+
function hasDominantRun(text, scanLength, unit, coverage) {
|
|
356
|
+
const limit = scanLength - unit;
|
|
357
|
+
let start = 0;
|
|
358
|
+
while (start <= limit) {
|
|
359
|
+
const copies = countConsecutiveCopies(text, start, unit, scanLength);
|
|
360
|
+
if (copies >= MIN_CONSECUTIVE_REPEATS && copies * unit >= coverage) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
start += copies * unit;
|
|
363
364
|
}
|
|
364
|
-
return
|
|
365
|
+
return false;
|
|
365
366
|
}
|
|
366
|
-
function
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
const className = readClassName(error);
|
|
378
|
-
if (className !== void 0) {
|
|
379
|
-
if (RATE_LIMITED_CLASS_NAMES.has(className)) {
|
|
380
|
-
return "RATE_LIMITED";
|
|
381
|
-
}
|
|
382
|
-
if (AUTH_FAILED_CLASS_NAMES.has(className)) {
|
|
383
|
-
return "AUTH_FAILED";
|
|
384
|
-
}
|
|
385
|
-
if (TIMEOUT_CLASS_NAMES.has(className)) {
|
|
386
|
-
return "TIMEOUT";
|
|
367
|
+
function hasRunawayRepetition(text) {
|
|
368
|
+
const scanLength = Math.min(text.length, MAX_SCAN_LENGTH);
|
|
369
|
+
const coverage = scanLength * REPEAT_COVERAGE_FRACTION;
|
|
370
|
+
const maxUnit = Math.min(
|
|
371
|
+
MAX_REPEAT_UNIT_LENGTH,
|
|
372
|
+
Math.floor(scanLength / MIN_CONSECUTIVE_REPEATS)
|
|
373
|
+
);
|
|
374
|
+
for (let unit = 1; unit <= maxUnit; unit++) {
|
|
375
|
+
if (hasDominantRun(text, scanLength, unit, coverage)) {
|
|
376
|
+
return true;
|
|
387
377
|
}
|
|
388
378
|
}
|
|
389
|
-
return
|
|
379
|
+
return false;
|
|
390
380
|
}
|
|
391
|
-
function
|
|
392
|
-
|
|
393
|
-
|
|
381
|
+
function assessValueDegeneracy(sourceValue, candidateValue) {
|
|
382
|
+
const source = sourceValue.trim();
|
|
383
|
+
const candidate = candidateValue.trim();
|
|
384
|
+
if (source.length >= MIN_SOURCE_LENGTH && candidate.length >= source.length * MAX_LENGTH_MULTIPLE) {
|
|
385
|
+
return { degenerate: true };
|
|
394
386
|
}
|
|
395
|
-
|
|
396
|
-
return className !== void 0 && ABORT_ERROR_CLASS_NAMES.has(className);
|
|
387
|
+
return { degenerate: hasRunawayRepetition(candidate) };
|
|
397
388
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
389
|
+
var LOCALE_TOKEN = "{locale}";
|
|
390
|
+
function localeFilePath(cwd, pattern, locale) {
|
|
391
|
+
return resolve(cwd, pattern.replaceAll(LOCALE_TOKEN, locale));
|
|
392
|
+
}
|
|
393
|
+
function checkBatchIntegrity(inputs, extract, compare) {
|
|
394
|
+
const integrity = /* @__PURE__ */ new Map();
|
|
395
|
+
for (const { key, sourceValue, translatedValue } of inputs) {
|
|
396
|
+
integrity.set(
|
|
397
|
+
key,
|
|
398
|
+
compare !== void 0 ? compare(sourceValue, translatedValue) : checkPlaceholders(extract(sourceValue), extract(translatedValue))
|
|
399
|
+
);
|
|
401
400
|
}
|
|
402
|
-
return
|
|
401
|
+
return integrity;
|
|
403
402
|
}
|
|
404
403
|
var REDACTED = "[REDACTED]";
|
|
405
404
|
var KEY_PATTERNS = [
|
|
@@ -437,38 +436,6 @@ var ProviderError = class extends Error {
|
|
|
437
436
|
this.code = code;
|
|
438
437
|
}
|
|
439
438
|
};
|
|
440
|
-
var PROVIDER_CALL_FAILED_MESSAGE = "The translation provider request failed.";
|
|
441
|
-
var RATE_LIMITED_MESSAGE = "The translation provider rate-limited this request.";
|
|
442
|
-
var TIMEOUT_MESSAGE = "The translation provider request timed out.";
|
|
443
|
-
var AUTH_FAILED_MESSAGE = "The translation provider rejected the request credentials.";
|
|
444
|
-
var MESSAGE_BY_CODE = {
|
|
445
|
-
RATE_LIMITED: RATE_LIMITED_MESSAGE,
|
|
446
|
-
TIMEOUT: TIMEOUT_MESSAGE,
|
|
447
|
-
AUTH_FAILED: AUTH_FAILED_MESSAGE,
|
|
448
|
-
PROVIDER_ERROR: PROVIDER_CALL_FAILED_MESSAGE
|
|
449
|
-
};
|
|
450
|
-
async function guardProviderCall(call, signal) {
|
|
451
|
-
signal?.throwIfAborted();
|
|
452
|
-
try {
|
|
453
|
-
return await call();
|
|
454
|
-
} catch (error) {
|
|
455
|
-
if (isAbortError(error, signal)) {
|
|
456
|
-
throw error;
|
|
457
|
-
}
|
|
458
|
-
const code = classifyProviderError(error);
|
|
459
|
-
throw new ProviderError(code, MESSAGE_BY_CODE[code]);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
function checkBatchIntegrity(inputs, extract, compare) {
|
|
463
|
-
const integrity = /* @__PURE__ */ new Map();
|
|
464
|
-
for (const { key, sourceValue, translatedValue } of inputs) {
|
|
465
|
-
integrity.set(
|
|
466
|
-
key,
|
|
467
|
-
compare !== void 0 ? compare(sourceValue, translatedValue) : checkPlaceholders(extract(sourceValue), extract(translatedValue))
|
|
468
|
-
);
|
|
469
|
-
}
|
|
470
|
-
return integrity;
|
|
471
|
-
}
|
|
472
439
|
var requestDataSchema = z.object({
|
|
473
440
|
sourceLocale: z.string().min(1),
|
|
474
441
|
targetLocale: z.string().min(1),
|
|
@@ -711,6 +678,121 @@ function assertNotTruncated(truncated) {
|
|
|
711
678
|
throw new ProviderError("OUTPUT_TRUNCATED", OUTPUT_TRUNCATED_MESSAGE);
|
|
712
679
|
}
|
|
713
680
|
}
|
|
681
|
+
var RATE_LIMITED_STATUS = 429;
|
|
682
|
+
var TIMEOUT_STATUS = 408;
|
|
683
|
+
var AUTH_FAILED_STATUSES = /* @__PURE__ */ new Set([401, 403]);
|
|
684
|
+
var RATE_LIMITED_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
685
|
+
"RateLimitError",
|
|
686
|
+
"TooManyRequestsError"
|
|
687
|
+
]);
|
|
688
|
+
var AUTH_FAILED_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
689
|
+
"AuthenticationError",
|
|
690
|
+
"PermissionDeniedError",
|
|
691
|
+
"AuthorizationError"
|
|
692
|
+
]);
|
|
693
|
+
var TIMEOUT_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
694
|
+
"APIConnectionTimeoutError",
|
|
695
|
+
"ConnectionError"
|
|
696
|
+
]);
|
|
697
|
+
var ABORT_ERROR_CLASS_NAMES = /* @__PURE__ */ new Set(["APIUserAbortError"]);
|
|
698
|
+
function getErrorStatus(error) {
|
|
699
|
+
if (typeof error !== "object" || error === null || !("status" in error)) {
|
|
700
|
+
return void 0;
|
|
701
|
+
}
|
|
702
|
+
const status = error.status;
|
|
703
|
+
return typeof status === "number" ? status : void 0;
|
|
704
|
+
}
|
|
705
|
+
function readClassName(error) {
|
|
706
|
+
if (typeof error !== "object" || error === null) {
|
|
707
|
+
return void 0;
|
|
708
|
+
}
|
|
709
|
+
return error.constructor?.name;
|
|
710
|
+
}
|
|
711
|
+
function classifyProviderError(error) {
|
|
712
|
+
const status = getErrorStatus(error);
|
|
713
|
+
if (status === RATE_LIMITED_STATUS) {
|
|
714
|
+
return "RATE_LIMITED";
|
|
715
|
+
}
|
|
716
|
+
if (status !== void 0 && AUTH_FAILED_STATUSES.has(status)) {
|
|
717
|
+
return "AUTH_FAILED";
|
|
718
|
+
}
|
|
719
|
+
if (status === TIMEOUT_STATUS) {
|
|
720
|
+
return "TIMEOUT";
|
|
721
|
+
}
|
|
722
|
+
const className = readClassName(error);
|
|
723
|
+
if (className !== void 0) {
|
|
724
|
+
if (RATE_LIMITED_CLASS_NAMES.has(className)) {
|
|
725
|
+
return "RATE_LIMITED";
|
|
726
|
+
}
|
|
727
|
+
if (AUTH_FAILED_CLASS_NAMES.has(className)) {
|
|
728
|
+
return "AUTH_FAILED";
|
|
729
|
+
}
|
|
730
|
+
if (TIMEOUT_CLASS_NAMES.has(className)) {
|
|
731
|
+
return "TIMEOUT";
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return "PROVIDER_ERROR";
|
|
735
|
+
}
|
|
736
|
+
function isAbortShapedError(error) {
|
|
737
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
738
|
+
return true;
|
|
739
|
+
}
|
|
740
|
+
const className = readClassName(error);
|
|
741
|
+
return className !== void 0 && ABORT_ERROR_CLASS_NAMES.has(className);
|
|
742
|
+
}
|
|
743
|
+
function isAbortError(error, signal) {
|
|
744
|
+
if (signal !== void 0) {
|
|
745
|
+
return signal.aborted === true && isAbortShapedError(error);
|
|
746
|
+
}
|
|
747
|
+
return isAbortShapedError(error);
|
|
748
|
+
}
|
|
749
|
+
var PROVIDER_CALL_FAILED_MESSAGE = "The translation provider request failed.";
|
|
750
|
+
var RATE_LIMITED_MESSAGE = "The translation provider rate-limited this request.";
|
|
751
|
+
var TIMEOUT_MESSAGE = "The translation provider request timed out.";
|
|
752
|
+
var AUTH_FAILED_MESSAGE = "The translation provider rejected the request credentials.";
|
|
753
|
+
var MESSAGE_BY_CODE = {
|
|
754
|
+
RATE_LIMITED: RATE_LIMITED_MESSAGE,
|
|
755
|
+
TIMEOUT: TIMEOUT_MESSAGE,
|
|
756
|
+
AUTH_FAILED: AUTH_FAILED_MESSAGE,
|
|
757
|
+
PROVIDER_ERROR: PROVIDER_CALL_FAILED_MESSAGE
|
|
758
|
+
};
|
|
759
|
+
async function guardProviderCall(call, signal) {
|
|
760
|
+
signal?.throwIfAborted();
|
|
761
|
+
try {
|
|
762
|
+
return await call();
|
|
763
|
+
} catch (error) {
|
|
764
|
+
if (isAbortError(error, signal)) {
|
|
765
|
+
throw error;
|
|
766
|
+
}
|
|
767
|
+
const code = classifyProviderError(error);
|
|
768
|
+
throw new ProviderError(code, MESSAGE_BY_CODE[code]);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
|
|
772
|
+
function requestTimedOutMessage(timeoutMs) {
|
|
773
|
+
return `The translation provider request exceeded the ${timeoutMs} ms request timeout.`;
|
|
774
|
+
}
|
|
775
|
+
function combineSignals(caller, timeout) {
|
|
776
|
+
return caller === void 0 ? timeout : AbortSignal.any([caller, timeout]);
|
|
777
|
+
}
|
|
778
|
+
async function withRequestTimeout(timeoutMs, callerSignal, call) {
|
|
779
|
+
const timeoutController = new AbortController();
|
|
780
|
+
const signal = combineSignals(callerSignal, timeoutController.signal);
|
|
781
|
+
let timer;
|
|
782
|
+
const timedOut = new Promise((_, reject) => {
|
|
783
|
+
timer = setTimeout(() => {
|
|
784
|
+
timeoutController.abort();
|
|
785
|
+
reject(new ProviderError("TIMEOUT", requestTimedOutMessage(timeoutMs)));
|
|
786
|
+
}, timeoutMs);
|
|
787
|
+
});
|
|
788
|
+
try {
|
|
789
|
+
return await Promise.race([guardProviderCall(() => call(signal), signal), timedOut]);
|
|
790
|
+
} finally {
|
|
791
|
+
if (timer !== void 0) {
|
|
792
|
+
clearTimeout(timer);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
714
796
|
var PROVIDER_ENV = {
|
|
715
797
|
anthropic: "ANTHROPIC_API_KEY",
|
|
716
798
|
openai: "OPENAI_API_KEY",
|
|
@@ -765,7 +847,13 @@ function createDefaultClient() {
|
|
|
765
847
|
}
|
|
766
848
|
var anthropicConfigSchema = z.object({
|
|
767
849
|
model: z.string().min(1),
|
|
768
|
-
maxTokens: z.number().int().positive()
|
|
850
|
+
maxTokens: z.number().int().positive(),
|
|
851
|
+
/**
|
|
852
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
853
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
854
|
+
* server cannot hold a locale's write lock open forever.
|
|
855
|
+
*/
|
|
856
|
+
requestTimeoutMs: z.number().int().positive().optional()
|
|
769
857
|
});
|
|
770
858
|
var SUBMIT_TOOL_NAME = "submit_translations";
|
|
771
859
|
var SYSTEM_RULES = [
|
|
@@ -825,10 +913,11 @@ function createAnthropicProvider(config, deps = {}) {
|
|
|
825
913
|
};
|
|
826
914
|
}
|
|
827
915
|
function createMechanism(client, config) {
|
|
916
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
828
917
|
return {
|
|
829
918
|
translate: async ({ payloadJson, signal }) => {
|
|
830
919
|
const body = buildRequest(config, payloadJson);
|
|
831
|
-
const message = await callClient(client, body, signal);
|
|
920
|
+
const message = await callClient(client, body, timeoutMs, signal);
|
|
832
921
|
assertNotTruncated(message.stop_reason === "max_tokens");
|
|
833
922
|
const raw = requireToolInput(message.content);
|
|
834
923
|
const usage = toUsage(message.usage);
|
|
@@ -836,10 +925,11 @@ function createMechanism(client, config) {
|
|
|
836
925
|
}
|
|
837
926
|
};
|
|
838
927
|
}
|
|
839
|
-
function callClient(client, body, signal) {
|
|
840
|
-
return
|
|
841
|
-
|
|
842
|
-
signal
|
|
928
|
+
function callClient(client, body, timeoutMs, signal) {
|
|
929
|
+
return withRequestTimeout(
|
|
930
|
+
timeoutMs,
|
|
931
|
+
signal,
|
|
932
|
+
(requestSignal) => client.messages.create(body, { signal: requestSignal })
|
|
843
933
|
);
|
|
844
934
|
}
|
|
845
935
|
function toUsage(usage) {
|
|
@@ -853,7 +943,14 @@ function toUsage(usage) {
|
|
|
853
943
|
return { inputTokens: input_tokens, outputTokens: output_tokens };
|
|
854
944
|
}
|
|
855
945
|
var deepLConfigSchema = z.object({
|
|
856
|
-
glossaryId: z.string().min(1).optional()
|
|
946
|
+
glossaryId: z.string().min(1).optional(),
|
|
947
|
+
/**
|
|
948
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
949
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
950
|
+
* server cannot hold a locale's write lock open forever. deepl-node cannot cancel an in-flight
|
|
951
|
+
* request, so on timeout verbatra's await is released but the underlying request is left to settle.
|
|
952
|
+
*/
|
|
953
|
+
requestTimeoutMs: z.number().int().positive().optional()
|
|
857
954
|
});
|
|
858
955
|
var DEEPL_LOGGER = "deepl";
|
|
859
956
|
function resolveDeeplLoglevel(requireFn = createRequire(import.meta.url)) {
|
|
@@ -1024,6 +1121,7 @@ async function translate(bundle, config, request) {
|
|
|
1024
1121
|
options,
|
|
1025
1122
|
request.extractPlaceholders,
|
|
1026
1123
|
request.comparePlaceholders,
|
|
1124
|
+
config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
1027
1125
|
request.signal
|
|
1028
1126
|
);
|
|
1029
1127
|
if (unprotectable.length > 0) {
|
|
@@ -1058,7 +1156,7 @@ function buildReviewFlags2(protectable, data, values, integrity, glossary) {
|
|
|
1058
1156
|
}
|
|
1059
1157
|
return reviewFlags;
|
|
1060
1158
|
}
|
|
1061
|
-
async function translateProtectable(client, data, protectable, options, extract, compare, signal) {
|
|
1159
|
+
async function translateProtectable(client, data, protectable, options, extract, compare, timeoutMs, signal) {
|
|
1062
1160
|
if (protectable.length === 0) {
|
|
1063
1161
|
return { values: /* @__PURE__ */ new Map(), integrity: /* @__PURE__ */ new Map() };
|
|
1064
1162
|
}
|
|
@@ -1069,29 +1167,45 @@ async function translateProtectable(client, data, protectable, options, extract,
|
|
|
1069
1167
|
data.sourceLocale,
|
|
1070
1168
|
data.targetLocale,
|
|
1071
1169
|
options,
|
|
1170
|
+
timeoutMs,
|
|
1072
1171
|
signal
|
|
1073
1172
|
);
|
|
1074
1173
|
const { values, integrityInputs } = zipResults(protectable, results);
|
|
1075
1174
|
const integrity = checkBatchIntegrity(integrityInputs, extract, compare);
|
|
1076
1175
|
return { values, integrity };
|
|
1077
1176
|
}
|
|
1078
|
-
function callClient2(client, texts, sourceLang, targetLang, options, signal) {
|
|
1079
|
-
return
|
|
1080
|
-
|
|
1081
|
-
signal
|
|
1177
|
+
function callClient2(client, texts, sourceLang, targetLang, options, timeoutMs, signal) {
|
|
1178
|
+
return withRequestTimeout(
|
|
1179
|
+
timeoutMs,
|
|
1180
|
+
signal,
|
|
1181
|
+
() => client.translateText(texts, sourceLang, targetLang, options)
|
|
1082
1182
|
);
|
|
1083
1183
|
}
|
|
1084
|
-
async function callClientChunked(client, texts, sourceLang, targetLang, options, signal) {
|
|
1184
|
+
async function callClientChunked(client, texts, sourceLang, targetLang, options, timeoutMs, signal) {
|
|
1085
1185
|
const results = [];
|
|
1086
1186
|
for (const chunk2 of chunkTextsForDeepL(texts)) {
|
|
1087
|
-
const chunkResults = await callClient2(
|
|
1187
|
+
const chunkResults = await callClient2(
|
|
1188
|
+
client,
|
|
1189
|
+
chunk2,
|
|
1190
|
+
sourceLang,
|
|
1191
|
+
targetLang,
|
|
1192
|
+
options,
|
|
1193
|
+
timeoutMs,
|
|
1194
|
+
signal
|
|
1195
|
+
);
|
|
1088
1196
|
results.push(...chunkResults);
|
|
1089
1197
|
}
|
|
1090
1198
|
return results;
|
|
1091
1199
|
}
|
|
1092
1200
|
var geminiConfigSchema = z.object({
|
|
1093
1201
|
model: z.string().min(1),
|
|
1094
|
-
maxOutputTokens: z.number().int().positive()
|
|
1202
|
+
maxOutputTokens: z.number().int().positive(),
|
|
1203
|
+
/**
|
|
1204
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
1205
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
1206
|
+
* server cannot hold a locale's write lock open forever.
|
|
1207
|
+
*/
|
|
1208
|
+
requestTimeoutMs: z.number().int().positive().optional()
|
|
1095
1209
|
});
|
|
1096
1210
|
var DEFAULT_GEMINI_RETRY = { attempts: 3, baseDelayMs: 250 };
|
|
1097
1211
|
function isRetryableStatus(error) {
|
|
@@ -1281,20 +1395,27 @@ function createGeminiProvider(config, deps = {}) {
|
|
|
1281
1395
|
};
|
|
1282
1396
|
}
|
|
1283
1397
|
function createMechanism2(client, config) {
|
|
1398
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
1284
1399
|
return {
|
|
1285
1400
|
translate: async ({ payloadJson, signal }) => {
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1401
|
+
const response = await withRequestTimeout(
|
|
1402
|
+
timeoutMs,
|
|
1403
|
+
signal,
|
|
1404
|
+
(requestSignal) => client.models.generateContent(buildGeminiRequest(config, payloadJson, requestSignal))
|
|
1405
|
+
);
|
|
1288
1406
|
return extractGeminiResult(response);
|
|
1289
1407
|
}
|
|
1290
1408
|
};
|
|
1291
1409
|
}
|
|
1292
|
-
function callClient3(client, request, signal) {
|
|
1293
|
-
return guardProviderCall(() => client.models.generateContent(request), signal);
|
|
1294
|
-
}
|
|
1295
1410
|
var openAiConfigSchema = z.object({
|
|
1296
1411
|
model: z.string().min(1),
|
|
1297
|
-
maxOutputTokens: z.number().int().positive()
|
|
1412
|
+
maxOutputTokens: z.number().int().positive(),
|
|
1413
|
+
/**
|
|
1414
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
1415
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
1416
|
+
* server cannot hold a locale's write lock open forever.
|
|
1417
|
+
*/
|
|
1418
|
+
requestTimeoutMs: z.number().int().positive().optional()
|
|
1298
1419
|
});
|
|
1299
1420
|
function createDefaultClient4() {
|
|
1300
1421
|
const sdk = new OpenAI({ apiKey: requireOpenAiKey(), logLevel: "off" });
|
|
@@ -1449,18 +1570,20 @@ function createOpenAiProvider(config, deps = {}) {
|
|
|
1449
1570
|
};
|
|
1450
1571
|
}
|
|
1451
1572
|
function createMechanism3(client, config) {
|
|
1573
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
1452
1574
|
return {
|
|
1453
1575
|
translate: async ({ payloadJson, signal }) => {
|
|
1454
1576
|
const body = buildOpenAiRequest(config, payloadJson);
|
|
1455
|
-
const completion = await
|
|
1577
|
+
const completion = await callClient3(client, body, timeoutMs, signal);
|
|
1456
1578
|
return extractOpenAiResult(completion);
|
|
1457
1579
|
}
|
|
1458
1580
|
};
|
|
1459
1581
|
}
|
|
1460
|
-
function
|
|
1461
|
-
return
|
|
1462
|
-
|
|
1463
|
-
signal
|
|
1582
|
+
function callClient3(client, body, timeoutMs, signal) {
|
|
1583
|
+
return withRequestTimeout(
|
|
1584
|
+
timeoutMs,
|
|
1585
|
+
signal,
|
|
1586
|
+
(requestSignal) => client.chat.completions.create(body, { signal: requestSignal })
|
|
1464
1587
|
);
|
|
1465
1588
|
}
|
|
1466
1589
|
var HOSTED_PROVIDER_ENV_VARS = new Set(
|
|
@@ -1483,7 +1606,13 @@ var openAiCompatibleConfigSchema = z.object({
|
|
|
1483
1606
|
maxOutputTokens: z.number().int().positive(),
|
|
1484
1607
|
apiKeyEnvVar: z.string().min(1).refine(isNotHostedProviderEnvVar, {
|
|
1485
1608
|
message: "apiKeyEnvVar must not name a hosted provider's environment variable."
|
|
1486
|
-
}).optional()
|
|
1609
|
+
}).optional(),
|
|
1610
|
+
/**
|
|
1611
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
1612
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive local
|
|
1613
|
+
* server (the reported stuck-LM-Studio case) cannot hold a locale's write lock open forever.
|
|
1614
|
+
*/
|
|
1615
|
+
requestTimeoutMs: z.number().int().positive().optional()
|
|
1487
1616
|
});
|
|
1488
1617
|
function createDefaultClient5(config) {
|
|
1489
1618
|
const sdk = new OpenAI({
|
|
@@ -1515,18 +1644,20 @@ function createOpenAiCompatibleProvider(config, deps = {}) {
|
|
|
1515
1644
|
};
|
|
1516
1645
|
}
|
|
1517
1646
|
function createMechanism4(client, config) {
|
|
1647
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
1518
1648
|
return {
|
|
1519
1649
|
translate: async ({ payloadJson, signal }) => {
|
|
1520
1650
|
const body = buildOpenAiRequest(config, payloadJson, "strict-schema", "max_tokens");
|
|
1521
|
-
const completion = await
|
|
1651
|
+
const completion = await callClient4(client, body, timeoutMs, signal);
|
|
1522
1652
|
return extractOpenAiResult(completion, true);
|
|
1523
1653
|
}
|
|
1524
1654
|
};
|
|
1525
1655
|
}
|
|
1526
|
-
function
|
|
1527
|
-
return
|
|
1528
|
-
|
|
1529
|
-
signal
|
|
1656
|
+
function callClient4(client, body, timeoutMs, signal) {
|
|
1657
|
+
return withRequestTimeout(
|
|
1658
|
+
timeoutMs,
|
|
1659
|
+
signal,
|
|
1660
|
+
(requestSignal) => client.chat.completions.create(body, { signal: requestSignal })
|
|
1530
1661
|
);
|
|
1531
1662
|
}
|
|
1532
1663
|
var SCAFFOLD_MODELS = {
|
|
@@ -1736,6 +1867,8 @@ var LOCAL_DIR_NAME = ".verbatra-local";
|
|
|
1736
1867
|
var LOCK_FILE_GUARD_STEM = "_lockfile";
|
|
1737
1868
|
var DEFAULT_POLL_INTERVAL_MS = 100;
|
|
1738
1869
|
var DEFAULT_ACQUIRE_TIMEOUT_MS = 10 * 6e4;
|
|
1870
|
+
var WAIT_NOTICE_INTERVAL_MS = 1e3;
|
|
1871
|
+
var MAX_LOCK_PAYLOAD_BYTES = 64 * 1024;
|
|
1739
1872
|
function lockPath(cwd, stem) {
|
|
1740
1873
|
return resolve(cwd, LOCAL_DIR_NAME, "locks", `${stem}.lock`);
|
|
1741
1874
|
}
|
|
@@ -1753,7 +1886,47 @@ function sleep(ms) {
|
|
|
1753
1886
|
function lockPayload() {
|
|
1754
1887
|
return JSON.stringify({ pid: process.pid, acquiredAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1755
1888
|
}
|
|
1756
|
-
|
|
1889
|
+
function parseHolder(read) {
|
|
1890
|
+
if (read.kind !== "ok") {
|
|
1891
|
+
return void 0;
|
|
1892
|
+
}
|
|
1893
|
+
let parsed;
|
|
1894
|
+
try {
|
|
1895
|
+
parsed = JSON.parse(read.content);
|
|
1896
|
+
} catch {
|
|
1897
|
+
return void 0;
|
|
1898
|
+
}
|
|
1899
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
1900
|
+
return void 0;
|
|
1901
|
+
}
|
|
1902
|
+
const record = parsed;
|
|
1903
|
+
const holder = {};
|
|
1904
|
+
if (typeof record.pid === "number") {
|
|
1905
|
+
holder.pid = record.pid;
|
|
1906
|
+
}
|
|
1907
|
+
if (typeof record.acquiredAt === "string") {
|
|
1908
|
+
holder.acquiredAt = record.acquiredAt;
|
|
1909
|
+
}
|
|
1910
|
+
return holder;
|
|
1911
|
+
}
|
|
1912
|
+
function makeWaitNotifier(path, fs, onWait, start) {
|
|
1913
|
+
let holder;
|
|
1914
|
+
let holderRead = false;
|
|
1915
|
+
let lastEmit;
|
|
1916
|
+
return async () => {
|
|
1917
|
+
if (!holderRead) {
|
|
1918
|
+
holderRead = true;
|
|
1919
|
+
holder = parseHolder(await fs.readFileBounded(path, MAX_LOCK_PAYLOAD_BYTES));
|
|
1920
|
+
}
|
|
1921
|
+
const elapsedMs = Date.now() - start;
|
|
1922
|
+
if (lastEmit !== void 0 && elapsedMs - lastEmit < WAIT_NOTICE_INTERVAL_MS) {
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
lastEmit = elapsedMs;
|
|
1926
|
+
onWait({ lockPath: path, elapsedMs, ...holder !== void 0 ? { holder } : {} });
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
async function acquireLock(path, fs, pollIntervalMs, deadline, notify) {
|
|
1757
1930
|
for (; ; ) {
|
|
1758
1931
|
if (await fs.createExclusive(path, lockPayload())) {
|
|
1759
1932
|
return;
|
|
@@ -1764,6 +1937,9 @@ async function acquireLock(path, fs, pollIntervalMs, deadline) {
|
|
|
1764
1937
|
`Could not acquire the write lock at ${path}: another process may be holding it. If no verbatra process is currently running, this lock file was likely left behind by one that was killed; delete it and retry.`
|
|
1765
1938
|
);
|
|
1766
1939
|
}
|
|
1940
|
+
if (notify !== void 0) {
|
|
1941
|
+
await notify();
|
|
1942
|
+
}
|
|
1767
1943
|
const jitter = Math.random() * pollIntervalMs;
|
|
1768
1944
|
await sleep(pollIntervalMs + jitter);
|
|
1769
1945
|
}
|
|
@@ -1771,7 +1947,9 @@ async function acquireLock(path, fs, pollIntervalMs, deadline) {
|
|
|
1771
1947
|
async function withFileLock(path, fs, fn, options) {
|
|
1772
1948
|
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
1773
1949
|
const acquireTimeoutMs = options.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS;
|
|
1774
|
-
|
|
1950
|
+
const start = Date.now();
|
|
1951
|
+
const notify = options.onWait !== void 0 ? makeWaitNotifier(path, fs, options.onWait, start) : void 0;
|
|
1952
|
+
await acquireLock(path, fs, pollIntervalMs, start + acquireTimeoutMs, notify);
|
|
1775
1953
|
try {
|
|
1776
1954
|
return await fn();
|
|
1777
1955
|
} finally {
|
|
@@ -3456,6 +3634,9 @@ function gateCandidateValue(sourceEntry, candidateValue, adapter) {
|
|
|
3456
3634
|
if (!adapter.validateMessage(candidateValue)) {
|
|
3457
3635
|
return { accepted: false, reason: "icu" };
|
|
3458
3636
|
}
|
|
3637
|
+
if (assessValueDegeneracy(sourceEntry.value, candidateValue).degenerate) {
|
|
3638
|
+
return { accepted: false, reason: "degenerate" };
|
|
3639
|
+
}
|
|
3459
3640
|
return { accepted: true };
|
|
3460
3641
|
}
|
|
3461
3642
|
|
|
@@ -3743,7 +3924,7 @@ var runBudgetSchema = z.object({
|
|
|
3743
3924
|
});
|
|
3744
3925
|
var runStatusLocaleSchema = z.object({
|
|
3745
3926
|
locale: z.string(),
|
|
3746
|
-
status: z.enum(["succeeded", "failed"]),
|
|
3927
|
+
status: z.enum(["succeeded", "partial", "failed"]),
|
|
3747
3928
|
needsReview: z.array(needsReviewEntrySchema),
|
|
3748
3929
|
usage: usageSummarySchema.optional()
|
|
3749
3930
|
});
|
|
@@ -3888,10 +4069,21 @@ function failureSummary(locale, error) {
|
|
|
3888
4069
|
error: describeError(error)
|
|
3889
4070
|
};
|
|
3890
4071
|
}
|
|
4072
|
+
function deriveLocaleStatus(parts) {
|
|
4073
|
+
const withheld = parts.integrityMismatches.length > 0 || parts.providerFailures.length > 0 || parts.budgetWithheld.length > 0;
|
|
4074
|
+
if (!withheld) {
|
|
4075
|
+
return "succeeded";
|
|
4076
|
+
}
|
|
4077
|
+
const accepted = parts.translated.length > 0 || parts.generated.length > 0;
|
|
4078
|
+
return accepted ? "partial" : "failed";
|
|
4079
|
+
}
|
|
3891
4080
|
function partition(locales) {
|
|
3892
|
-
const
|
|
3893
|
-
|
|
3894
|
-
|
|
4081
|
+
const namesWith = (status) => locales.filter((s) => s.status === status).map((s) => s.locale);
|
|
4082
|
+
return {
|
|
4083
|
+
succeeded: namesWith("succeeded"),
|
|
4084
|
+
partial: namesWith("partial"),
|
|
4085
|
+
failed: namesWith("failed")
|
|
4086
|
+
};
|
|
3895
4087
|
}
|
|
3896
4088
|
|
|
3897
4089
|
// src/flow/batching.ts
|
|
@@ -4372,7 +4564,7 @@ function pluralNoticeFor(params, merged) {
|
|
|
4372
4564
|
function baseSummary(parts) {
|
|
4373
4565
|
return {
|
|
4374
4566
|
locale: parts.locale,
|
|
4375
|
-
status:
|
|
4567
|
+
status: deriveLocaleStatus(parts),
|
|
4376
4568
|
translated: parts.translated,
|
|
4377
4569
|
unchanged: parts.unchanged,
|
|
4378
4570
|
orphaned: parts.orphaned,
|
|
@@ -4431,10 +4623,16 @@ async function runSubBatch(provider, params, batch, accepted, integrityMismatche
|
|
|
4431
4623
|
try {
|
|
4432
4624
|
result = await provider.translateBatch(buildRequest3(params, batch));
|
|
4433
4625
|
} catch (error) {
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4626
|
+
return handleSubBatchFailure(
|
|
4627
|
+
error,
|
|
4628
|
+
provider,
|
|
4629
|
+
params,
|
|
4630
|
+
batch,
|
|
4631
|
+
accepted,
|
|
4632
|
+
integrityMismatches,
|
|
4633
|
+
providerFailures,
|
|
4634
|
+
reviewFlags
|
|
4635
|
+
);
|
|
4438
4636
|
}
|
|
4439
4637
|
for (const entry of batch) {
|
|
4440
4638
|
foldEntryResult(entry, result, params.adapter, accepted, integrityMismatches, providerFailures);
|
|
@@ -4446,6 +4644,44 @@ async function runSubBatch(provider, params, batch, accepted, integrityMismatche
|
|
|
4446
4644
|
}
|
|
4447
4645
|
return { notices: readNotices(result), usage: result.usage };
|
|
4448
4646
|
}
|
|
4647
|
+
function isOutputTruncated(error) {
|
|
4648
|
+
return error instanceof ProviderError && error.code === "OUTPUT_TRUNCATED";
|
|
4649
|
+
}
|
|
4650
|
+
async function handleSubBatchFailure(error, provider, params, batch, accepted, integrityMismatches, providerFailures, reviewFlags) {
|
|
4651
|
+
if (isOutputTruncated(error) && batch.length > 1) {
|
|
4652
|
+
return retryTruncatedSplit(
|
|
4653
|
+
provider,
|
|
4654
|
+
params,
|
|
4655
|
+
batch,
|
|
4656
|
+
accepted,
|
|
4657
|
+
integrityMismatches,
|
|
4658
|
+
providerFailures,
|
|
4659
|
+
reviewFlags
|
|
4660
|
+
);
|
|
4661
|
+
}
|
|
4662
|
+
for (const entry of batch) {
|
|
4663
|
+
providerFailures.push(entry.key);
|
|
4664
|
+
}
|
|
4665
|
+
return { notices: [subBatchFailedNotice(batch.length, error)], usage: void 0 };
|
|
4666
|
+
}
|
|
4667
|
+
async function retryTruncatedSplit(provider, params, batch, accepted, integrityMismatches, providerFailures, reviewFlags) {
|
|
4668
|
+
const notices = [];
|
|
4669
|
+
let usage;
|
|
4670
|
+
for (const half of chunk(batch, Math.ceil(batch.length / 2))) {
|
|
4671
|
+
const sub = await runSubBatch(
|
|
4672
|
+
provider,
|
|
4673
|
+
params,
|
|
4674
|
+
half,
|
|
4675
|
+
accepted,
|
|
4676
|
+
integrityMismatches,
|
|
4677
|
+
providerFailures,
|
|
4678
|
+
reviewFlags
|
|
4679
|
+
);
|
|
4680
|
+
notices.push(...sub.notices);
|
|
4681
|
+
usage = combineUsage(usage, sub.usage);
|
|
4682
|
+
}
|
|
4683
|
+
return { notices, usage };
|
|
4684
|
+
}
|
|
4449
4685
|
function foldEntryResult(entry, result, adapter, accepted, integrityMismatches, providerFailures) {
|
|
4450
4686
|
const value = result.values.get(entry.key);
|
|
4451
4687
|
if (value === void 0) {
|
|
@@ -4529,16 +4765,26 @@ async function runDryLocale(context, targetLocale, lock) {
|
|
|
4529
4765
|
return (await runLocale(params)).summary;
|
|
4530
4766
|
}
|
|
4531
4767
|
async function runLiveLocale(context, targetLocale) {
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4768
|
+
const lockOptions = {
|
|
4769
|
+
...context.onLockWait !== void 0 ? { onWait: context.onLockWait } : {},
|
|
4770
|
+
...context.lockAcquireTimeoutMs !== void 0 ? { acquireTimeoutMs: context.lockAcquireTimeoutMs } : {}
|
|
4771
|
+
};
|
|
4772
|
+
return withLocaleWriteLock(
|
|
4773
|
+
context.cwd,
|
|
4774
|
+
targetLocale,
|
|
4775
|
+
context.fs,
|
|
4776
|
+
async () => {
|
|
4777
|
+
const lock = await readLockFile(lockFilePath(context.cwd), context.fs);
|
|
4778
|
+
const params = buildLocaleRunParams(context, targetLocale, baselineFor(lock, targetLocale));
|
|
4779
|
+
const result = await runLocale(params);
|
|
4780
|
+
await updateLockFileLocale(context.cwd, context.fs, targetLocale, {
|
|
4781
|
+
mode: "replace",
|
|
4782
|
+
entries: result.lockEntries
|
|
4783
|
+
});
|
|
4784
|
+
return result.summary;
|
|
4785
|
+
},
|
|
4786
|
+
lockOptions
|
|
4787
|
+
);
|
|
4542
4788
|
}
|
|
4543
4789
|
async function runOneLocale(targetLocale, run) {
|
|
4544
4790
|
try {
|
|
@@ -4592,10 +4838,12 @@ async function translate2(input, deps = {}) {
|
|
|
4592
4838
|
generatePlurals,
|
|
4593
4839
|
maxBatchSize,
|
|
4594
4840
|
fs,
|
|
4595
|
-
budget
|
|
4841
|
+
budget,
|
|
4842
|
+
...input.onLockWait !== void 0 ? { onLockWait: input.onLockWait } : {},
|
|
4843
|
+
...input.lockAcquireTimeoutMs !== void 0 ? { lockAcquireTimeoutMs: input.lockAcquireTimeoutMs } : {}
|
|
4596
4844
|
};
|
|
4597
4845
|
const summaries = dryRun ? await runAllLocalesDry(context, config.targetLocales) : await runAllLocalesLive(context, config.targetLocales);
|
|
4598
|
-
const { succeeded, failed } = partition(summaries);
|
|
4846
|
+
const { succeeded, partial, failed } = partition(summaries);
|
|
4599
4847
|
const usage = summaries.reduce(
|
|
4600
4848
|
(total, summary2) => combineUsage(total, summary2.usage),
|
|
4601
4849
|
void 0
|
|
@@ -4605,6 +4853,7 @@ async function translate2(input, deps = {}) {
|
|
|
4605
4853
|
dryRun,
|
|
4606
4854
|
locales: summaries,
|
|
4607
4855
|
succeeded,
|
|
4856
|
+
partial,
|
|
4608
4857
|
failed,
|
|
4609
4858
|
...usage !== void 0 ? { usage } : {},
|
|
4610
4859
|
...budgetSummary !== void 0 ? { budget: budgetSummary } : {}
|
|
@@ -5163,15 +5412,23 @@ function importLocale(params) {
|
|
|
5163
5412
|
classifyRows(params, buckets);
|
|
5164
5413
|
const rowKeys = new Set(params.sheet.rows.map((row) => row.key));
|
|
5165
5414
|
const invalidIcuSource = [...new Set(params.sourceInvalidIcuKeys)].filter((key) => rowKeys.has(key)).sort();
|
|
5415
|
+
const translated = [...buckets.accepted.keys()].sort();
|
|
5416
|
+
const integrityMismatches = [...buckets.mismatches].sort();
|
|
5166
5417
|
const summary = {
|
|
5167
5418
|
locale: params.sheet.locale,
|
|
5168
|
-
status:
|
|
5169
|
-
|
|
5419
|
+
status: deriveLocaleStatus({
|
|
5420
|
+
translated,
|
|
5421
|
+
generated: [],
|
|
5422
|
+
integrityMismatches,
|
|
5423
|
+
providerFailures: [],
|
|
5424
|
+
budgetWithheld: []
|
|
5425
|
+
}),
|
|
5426
|
+
translated,
|
|
5170
5427
|
unchanged: diff2.unchanged,
|
|
5171
5428
|
orphaned: diff2.orphaned,
|
|
5172
5429
|
pruned: [],
|
|
5173
5430
|
invalidIcuSource,
|
|
5174
|
-
integrityMismatches
|
|
5431
|
+
integrityMismatches,
|
|
5175
5432
|
providerFailures: [],
|
|
5176
5433
|
budgetWithheld: [],
|
|
5177
5434
|
generated: [],
|
|
@@ -5300,8 +5557,8 @@ async function importWorkbook(input, deps = {}) {
|
|
|
5300
5557
|
summaries.push(failureSummary(sheet.locale, error));
|
|
5301
5558
|
}
|
|
5302
5559
|
}
|
|
5303
|
-
const { succeeded, failed } = partition(summaries);
|
|
5304
|
-
return { dryRun, locales: summaries, succeeded, failed };
|
|
5560
|
+
const { succeeded, partial, failed } = partition(summaries);
|
|
5561
|
+
return { dryRun, locales: summaries, succeeded, partial, failed };
|
|
5305
5562
|
}
|
|
5306
5563
|
|
|
5307
5564
|
// src/lock/load-lock-file.ts
|
|
@@ -5359,7 +5616,12 @@ async function watch(input, deps = {}) {
|
|
|
5359
5616
|
);
|
|
5360
5617
|
}
|
|
5361
5618
|
const runTranslate = deps.runTranslate ?? defaultRunTranslate(deps);
|
|
5362
|
-
const runInput = {
|
|
5619
|
+
const runInput = {
|
|
5620
|
+
config: input.config,
|
|
5621
|
+
cwd,
|
|
5622
|
+
...input.onLockWait !== void 0 ? { onLockWait: input.onLockWait } : {},
|
|
5623
|
+
...input.lockAcquireTimeoutMs !== void 0 ? { lockAcquireTimeoutMs: input.lockAcquireTimeoutMs } : {}
|
|
5624
|
+
};
|
|
5363
5625
|
let state = "idle";
|
|
5364
5626
|
let pending = false;
|
|
5365
5627
|
let stopped = false;
|