@verbatra/sdk 0.6.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 +2 -2
package/dist/index.cjs
CHANGED
|
@@ -359,77 +359,76 @@ function checkPlaceholders(source, translated) {
|
|
|
359
359
|
reordered
|
|
360
360
|
};
|
|
361
361
|
}
|
|
362
|
-
var
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
var
|
|
367
|
-
var
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
var AUTH_FAILED_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
374
|
-
"AuthenticationError",
|
|
375
|
-
"PermissionDeniedError",
|
|
376
|
-
"AuthorizationError"
|
|
377
|
-
]);
|
|
378
|
-
var TIMEOUT_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
379
|
-
"APIConnectionTimeoutError",
|
|
380
|
-
"ConnectionError"
|
|
381
|
-
]);
|
|
382
|
-
var ABORT_ERROR_CLASS_NAMES = /* @__PURE__ */ new Set(["APIUserAbortError"]);
|
|
383
|
-
function getErrorStatus(error) {
|
|
384
|
-
if (typeof error !== "object" || error === null || !("status" in error)) {
|
|
385
|
-
return void 0;
|
|
362
|
+
var MIN_SOURCE_LENGTH = 8;
|
|
363
|
+
var MAX_LENGTH_MULTIPLE = 12;
|
|
364
|
+
var MAX_REPEAT_UNIT_LENGTH = 16;
|
|
365
|
+
var MIN_CONSECUTIVE_REPEATS = 8;
|
|
366
|
+
var REPEAT_COVERAGE_FRACTION = 0.5;
|
|
367
|
+
var MAX_SCAN_LENGTH = 8192;
|
|
368
|
+
function matchesUnit(text, a, b, unit) {
|
|
369
|
+
for (let i = 0; i < unit; i++) {
|
|
370
|
+
if (text[a + i] !== text[b + i]) {
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
386
373
|
}
|
|
387
|
-
|
|
388
|
-
return typeof status === "number" ? status : void 0;
|
|
374
|
+
return true;
|
|
389
375
|
}
|
|
390
|
-
function
|
|
391
|
-
|
|
392
|
-
|
|
376
|
+
function countConsecutiveCopies(text, start, unit, scanLength) {
|
|
377
|
+
let copies = 1;
|
|
378
|
+
let next = start + unit;
|
|
379
|
+
while (next + unit <= scanLength && matchesUnit(text, start, next, unit)) {
|
|
380
|
+
copies++;
|
|
381
|
+
next += unit;
|
|
382
|
+
}
|
|
383
|
+
return copies;
|
|
384
|
+
}
|
|
385
|
+
function hasDominantRun(text, scanLength, unit, coverage) {
|
|
386
|
+
const limit = scanLength - unit;
|
|
387
|
+
let start = 0;
|
|
388
|
+
while (start <= limit) {
|
|
389
|
+
const copies = countConsecutiveCopies(text, start, unit, scanLength);
|
|
390
|
+
if (copies >= MIN_CONSECUTIVE_REPEATS && copies * unit >= coverage) {
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
start += copies * unit;
|
|
393
394
|
}
|
|
394
|
-
return
|
|
395
|
+
return false;
|
|
395
396
|
}
|
|
396
|
-
function
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
407
|
-
const className = readClassName(error);
|
|
408
|
-
if (className !== void 0) {
|
|
409
|
-
if (RATE_LIMITED_CLASS_NAMES.has(className)) {
|
|
410
|
-
return "RATE_LIMITED";
|
|
411
|
-
}
|
|
412
|
-
if (AUTH_FAILED_CLASS_NAMES.has(className)) {
|
|
413
|
-
return "AUTH_FAILED";
|
|
414
|
-
}
|
|
415
|
-
if (TIMEOUT_CLASS_NAMES.has(className)) {
|
|
416
|
-
return "TIMEOUT";
|
|
397
|
+
function hasRunawayRepetition(text) {
|
|
398
|
+
const scanLength = Math.min(text.length, MAX_SCAN_LENGTH);
|
|
399
|
+
const coverage = scanLength * REPEAT_COVERAGE_FRACTION;
|
|
400
|
+
const maxUnit = Math.min(
|
|
401
|
+
MAX_REPEAT_UNIT_LENGTH,
|
|
402
|
+
Math.floor(scanLength / MIN_CONSECUTIVE_REPEATS)
|
|
403
|
+
);
|
|
404
|
+
for (let unit = 1; unit <= maxUnit; unit++) {
|
|
405
|
+
if (hasDominantRun(text, scanLength, unit, coverage)) {
|
|
406
|
+
return true;
|
|
417
407
|
}
|
|
418
408
|
}
|
|
419
|
-
return
|
|
409
|
+
return false;
|
|
420
410
|
}
|
|
421
|
-
function
|
|
422
|
-
|
|
423
|
-
|
|
411
|
+
function assessValueDegeneracy(sourceValue, candidateValue) {
|
|
412
|
+
const source = sourceValue.trim();
|
|
413
|
+
const candidate = candidateValue.trim();
|
|
414
|
+
if (source.length >= MIN_SOURCE_LENGTH && candidate.length >= source.length * MAX_LENGTH_MULTIPLE) {
|
|
415
|
+
return { degenerate: true };
|
|
424
416
|
}
|
|
425
|
-
|
|
426
|
-
return className !== void 0 && ABORT_ERROR_CLASS_NAMES.has(className);
|
|
417
|
+
return { degenerate: hasRunawayRepetition(candidate) };
|
|
427
418
|
}
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
419
|
+
var LOCALE_TOKEN = "{locale}";
|
|
420
|
+
function localeFilePath(cwd, pattern, locale) {
|
|
421
|
+
return path.resolve(cwd, pattern.replaceAll(LOCALE_TOKEN, locale));
|
|
422
|
+
}
|
|
423
|
+
function checkBatchIntegrity(inputs, extract, compare) {
|
|
424
|
+
const integrity = /* @__PURE__ */ new Map();
|
|
425
|
+
for (const { key, sourceValue, translatedValue } of inputs) {
|
|
426
|
+
integrity.set(
|
|
427
|
+
key,
|
|
428
|
+
compare !== void 0 ? compare(sourceValue, translatedValue) : checkPlaceholders(extract(sourceValue), extract(translatedValue))
|
|
429
|
+
);
|
|
431
430
|
}
|
|
432
|
-
return
|
|
431
|
+
return integrity;
|
|
433
432
|
}
|
|
434
433
|
var REDACTED = "[REDACTED]";
|
|
435
434
|
var KEY_PATTERNS = [
|
|
@@ -467,38 +466,6 @@ var ProviderError = class extends Error {
|
|
|
467
466
|
this.code = code;
|
|
468
467
|
}
|
|
469
468
|
};
|
|
470
|
-
var PROVIDER_CALL_FAILED_MESSAGE = "The translation provider request failed.";
|
|
471
|
-
var RATE_LIMITED_MESSAGE = "The translation provider rate-limited this request.";
|
|
472
|
-
var TIMEOUT_MESSAGE = "The translation provider request timed out.";
|
|
473
|
-
var AUTH_FAILED_MESSAGE = "The translation provider rejected the request credentials.";
|
|
474
|
-
var MESSAGE_BY_CODE = {
|
|
475
|
-
RATE_LIMITED: RATE_LIMITED_MESSAGE,
|
|
476
|
-
TIMEOUT: TIMEOUT_MESSAGE,
|
|
477
|
-
AUTH_FAILED: AUTH_FAILED_MESSAGE,
|
|
478
|
-
PROVIDER_ERROR: PROVIDER_CALL_FAILED_MESSAGE
|
|
479
|
-
};
|
|
480
|
-
async function guardProviderCall(call, signal) {
|
|
481
|
-
signal?.throwIfAborted();
|
|
482
|
-
try {
|
|
483
|
-
return await call();
|
|
484
|
-
} catch (error) {
|
|
485
|
-
if (isAbortError(error, signal)) {
|
|
486
|
-
throw error;
|
|
487
|
-
}
|
|
488
|
-
const code = classifyProviderError(error);
|
|
489
|
-
throw new ProviderError(code, MESSAGE_BY_CODE[code]);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
function checkBatchIntegrity(inputs, extract, compare) {
|
|
493
|
-
const integrity = /* @__PURE__ */ new Map();
|
|
494
|
-
for (const { key, sourceValue, translatedValue } of inputs) {
|
|
495
|
-
integrity.set(
|
|
496
|
-
key,
|
|
497
|
-
compare !== void 0 ? compare(sourceValue, translatedValue) : checkPlaceholders(extract(sourceValue), extract(translatedValue))
|
|
498
|
-
);
|
|
499
|
-
}
|
|
500
|
-
return integrity;
|
|
501
|
-
}
|
|
502
469
|
var requestDataSchema = zod.z.object({
|
|
503
470
|
sourceLocale: zod.z.string().min(1),
|
|
504
471
|
targetLocale: zod.z.string().min(1),
|
|
@@ -741,6 +708,121 @@ function assertNotTruncated(truncated) {
|
|
|
741
708
|
throw new ProviderError("OUTPUT_TRUNCATED", OUTPUT_TRUNCATED_MESSAGE);
|
|
742
709
|
}
|
|
743
710
|
}
|
|
711
|
+
var RATE_LIMITED_STATUS = 429;
|
|
712
|
+
var TIMEOUT_STATUS = 408;
|
|
713
|
+
var AUTH_FAILED_STATUSES = /* @__PURE__ */ new Set([401, 403]);
|
|
714
|
+
var RATE_LIMITED_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
715
|
+
"RateLimitError",
|
|
716
|
+
"TooManyRequestsError"
|
|
717
|
+
]);
|
|
718
|
+
var AUTH_FAILED_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
719
|
+
"AuthenticationError",
|
|
720
|
+
"PermissionDeniedError",
|
|
721
|
+
"AuthorizationError"
|
|
722
|
+
]);
|
|
723
|
+
var TIMEOUT_CLASS_NAMES = /* @__PURE__ */ new Set([
|
|
724
|
+
"APIConnectionTimeoutError",
|
|
725
|
+
"ConnectionError"
|
|
726
|
+
]);
|
|
727
|
+
var ABORT_ERROR_CLASS_NAMES = /* @__PURE__ */ new Set(["APIUserAbortError"]);
|
|
728
|
+
function getErrorStatus(error) {
|
|
729
|
+
if (typeof error !== "object" || error === null || !("status" in error)) {
|
|
730
|
+
return void 0;
|
|
731
|
+
}
|
|
732
|
+
const status = error.status;
|
|
733
|
+
return typeof status === "number" ? status : void 0;
|
|
734
|
+
}
|
|
735
|
+
function readClassName(error) {
|
|
736
|
+
if (typeof error !== "object" || error === null) {
|
|
737
|
+
return void 0;
|
|
738
|
+
}
|
|
739
|
+
return error.constructor?.name;
|
|
740
|
+
}
|
|
741
|
+
function classifyProviderError(error) {
|
|
742
|
+
const status = getErrorStatus(error);
|
|
743
|
+
if (status === RATE_LIMITED_STATUS) {
|
|
744
|
+
return "RATE_LIMITED";
|
|
745
|
+
}
|
|
746
|
+
if (status !== void 0 && AUTH_FAILED_STATUSES.has(status)) {
|
|
747
|
+
return "AUTH_FAILED";
|
|
748
|
+
}
|
|
749
|
+
if (status === TIMEOUT_STATUS) {
|
|
750
|
+
return "TIMEOUT";
|
|
751
|
+
}
|
|
752
|
+
const className = readClassName(error);
|
|
753
|
+
if (className !== void 0) {
|
|
754
|
+
if (RATE_LIMITED_CLASS_NAMES.has(className)) {
|
|
755
|
+
return "RATE_LIMITED";
|
|
756
|
+
}
|
|
757
|
+
if (AUTH_FAILED_CLASS_NAMES.has(className)) {
|
|
758
|
+
return "AUTH_FAILED";
|
|
759
|
+
}
|
|
760
|
+
if (TIMEOUT_CLASS_NAMES.has(className)) {
|
|
761
|
+
return "TIMEOUT";
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return "PROVIDER_ERROR";
|
|
765
|
+
}
|
|
766
|
+
function isAbortShapedError(error) {
|
|
767
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
768
|
+
return true;
|
|
769
|
+
}
|
|
770
|
+
const className = readClassName(error);
|
|
771
|
+
return className !== void 0 && ABORT_ERROR_CLASS_NAMES.has(className);
|
|
772
|
+
}
|
|
773
|
+
function isAbortError(error, signal) {
|
|
774
|
+
if (signal !== void 0) {
|
|
775
|
+
return signal.aborted === true && isAbortShapedError(error);
|
|
776
|
+
}
|
|
777
|
+
return isAbortShapedError(error);
|
|
778
|
+
}
|
|
779
|
+
var PROVIDER_CALL_FAILED_MESSAGE = "The translation provider request failed.";
|
|
780
|
+
var RATE_LIMITED_MESSAGE = "The translation provider rate-limited this request.";
|
|
781
|
+
var TIMEOUT_MESSAGE = "The translation provider request timed out.";
|
|
782
|
+
var AUTH_FAILED_MESSAGE = "The translation provider rejected the request credentials.";
|
|
783
|
+
var MESSAGE_BY_CODE = {
|
|
784
|
+
RATE_LIMITED: RATE_LIMITED_MESSAGE,
|
|
785
|
+
TIMEOUT: TIMEOUT_MESSAGE,
|
|
786
|
+
AUTH_FAILED: AUTH_FAILED_MESSAGE,
|
|
787
|
+
PROVIDER_ERROR: PROVIDER_CALL_FAILED_MESSAGE
|
|
788
|
+
};
|
|
789
|
+
async function guardProviderCall(call, signal) {
|
|
790
|
+
signal?.throwIfAborted();
|
|
791
|
+
try {
|
|
792
|
+
return await call();
|
|
793
|
+
} catch (error) {
|
|
794
|
+
if (isAbortError(error, signal)) {
|
|
795
|
+
throw error;
|
|
796
|
+
}
|
|
797
|
+
const code = classifyProviderError(error);
|
|
798
|
+
throw new ProviderError(code, MESSAGE_BY_CODE[code]);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
|
|
802
|
+
function requestTimedOutMessage(timeoutMs) {
|
|
803
|
+
return `The translation provider request exceeded the ${timeoutMs} ms request timeout.`;
|
|
804
|
+
}
|
|
805
|
+
function combineSignals(caller, timeout) {
|
|
806
|
+
return caller === void 0 ? timeout : AbortSignal.any([caller, timeout]);
|
|
807
|
+
}
|
|
808
|
+
async function withRequestTimeout(timeoutMs, callerSignal, call) {
|
|
809
|
+
const timeoutController = new AbortController();
|
|
810
|
+
const signal = combineSignals(callerSignal, timeoutController.signal);
|
|
811
|
+
let timer;
|
|
812
|
+
const timedOut = new Promise((_, reject) => {
|
|
813
|
+
timer = setTimeout(() => {
|
|
814
|
+
timeoutController.abort();
|
|
815
|
+
reject(new ProviderError("TIMEOUT", requestTimedOutMessage(timeoutMs)));
|
|
816
|
+
}, timeoutMs);
|
|
817
|
+
});
|
|
818
|
+
try {
|
|
819
|
+
return await Promise.race([guardProviderCall(() => call(signal), signal), timedOut]);
|
|
820
|
+
} finally {
|
|
821
|
+
if (timer !== void 0) {
|
|
822
|
+
clearTimeout(timer);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}
|
|
744
826
|
var PROVIDER_ENV = {
|
|
745
827
|
anthropic: "ANTHROPIC_API_KEY",
|
|
746
828
|
openai: "OPENAI_API_KEY",
|
|
@@ -795,7 +877,13 @@ function createDefaultClient() {
|
|
|
795
877
|
}
|
|
796
878
|
var anthropicConfigSchema = zod.z.object({
|
|
797
879
|
model: zod.z.string().min(1),
|
|
798
|
-
maxTokens: zod.z.number().int().positive()
|
|
880
|
+
maxTokens: zod.z.number().int().positive(),
|
|
881
|
+
/**
|
|
882
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
883
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
884
|
+
* server cannot hold a locale's write lock open forever.
|
|
885
|
+
*/
|
|
886
|
+
requestTimeoutMs: zod.z.number().int().positive().optional()
|
|
799
887
|
});
|
|
800
888
|
var SUBMIT_TOOL_NAME = "submit_translations";
|
|
801
889
|
var SYSTEM_RULES = [
|
|
@@ -855,10 +943,11 @@ function createAnthropicProvider(config, deps = {}) {
|
|
|
855
943
|
};
|
|
856
944
|
}
|
|
857
945
|
function createMechanism(client, config) {
|
|
946
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
858
947
|
return {
|
|
859
948
|
translate: async ({ payloadJson, signal }) => {
|
|
860
949
|
const body = buildRequest(config, payloadJson);
|
|
861
|
-
const message = await callClient(client, body, signal);
|
|
950
|
+
const message = await callClient(client, body, timeoutMs, signal);
|
|
862
951
|
assertNotTruncated(message.stop_reason === "max_tokens");
|
|
863
952
|
const raw = requireToolInput(message.content);
|
|
864
953
|
const usage = toUsage(message.usage);
|
|
@@ -866,10 +955,11 @@ function createMechanism(client, config) {
|
|
|
866
955
|
}
|
|
867
956
|
};
|
|
868
957
|
}
|
|
869
|
-
function callClient(client, body, signal) {
|
|
870
|
-
return
|
|
871
|
-
|
|
872
|
-
signal
|
|
958
|
+
function callClient(client, body, timeoutMs, signal) {
|
|
959
|
+
return withRequestTimeout(
|
|
960
|
+
timeoutMs,
|
|
961
|
+
signal,
|
|
962
|
+
(requestSignal) => client.messages.create(body, { signal: requestSignal })
|
|
873
963
|
);
|
|
874
964
|
}
|
|
875
965
|
function toUsage(usage) {
|
|
@@ -883,7 +973,14 @@ function toUsage(usage) {
|
|
|
883
973
|
return { inputTokens: input_tokens, outputTokens: output_tokens };
|
|
884
974
|
}
|
|
885
975
|
var deepLConfigSchema = zod.z.object({
|
|
886
|
-
glossaryId: zod.z.string().min(1).optional()
|
|
976
|
+
glossaryId: zod.z.string().min(1).optional(),
|
|
977
|
+
/**
|
|
978
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
979
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
980
|
+
* server cannot hold a locale's write lock open forever. deepl-node cannot cancel an in-flight
|
|
981
|
+
* request, so on timeout verbatra's await is released but the underlying request is left to settle.
|
|
982
|
+
*/
|
|
983
|
+
requestTimeoutMs: zod.z.number().int().positive().optional()
|
|
887
984
|
});
|
|
888
985
|
var DEEPL_LOGGER = "deepl";
|
|
889
986
|
function resolveDeeplLoglevel(requireFn = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))) {
|
|
@@ -1054,6 +1151,7 @@ async function translate(bundle, config, request) {
|
|
|
1054
1151
|
options,
|
|
1055
1152
|
request.extractPlaceholders,
|
|
1056
1153
|
request.comparePlaceholders,
|
|
1154
|
+
config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
1057
1155
|
request.signal
|
|
1058
1156
|
);
|
|
1059
1157
|
if (unprotectable.length > 0) {
|
|
@@ -1088,7 +1186,7 @@ function buildReviewFlags2(protectable, data, values, integrity, glossary) {
|
|
|
1088
1186
|
}
|
|
1089
1187
|
return reviewFlags;
|
|
1090
1188
|
}
|
|
1091
|
-
async function translateProtectable(client, data, protectable, options, extract, compare, signal) {
|
|
1189
|
+
async function translateProtectable(client, data, protectable, options, extract, compare, timeoutMs, signal) {
|
|
1092
1190
|
if (protectable.length === 0) {
|
|
1093
1191
|
return { values: /* @__PURE__ */ new Map(), integrity: /* @__PURE__ */ new Map() };
|
|
1094
1192
|
}
|
|
@@ -1099,29 +1197,45 @@ async function translateProtectable(client, data, protectable, options, extract,
|
|
|
1099
1197
|
data.sourceLocale,
|
|
1100
1198
|
data.targetLocale,
|
|
1101
1199
|
options,
|
|
1200
|
+
timeoutMs,
|
|
1102
1201
|
signal
|
|
1103
1202
|
);
|
|
1104
1203
|
const { values, integrityInputs } = zipResults(protectable, results);
|
|
1105
1204
|
const integrity = checkBatchIntegrity(integrityInputs, extract, compare);
|
|
1106
1205
|
return { values, integrity };
|
|
1107
1206
|
}
|
|
1108
|
-
function callClient2(client, texts, sourceLang, targetLang, options, signal) {
|
|
1109
|
-
return
|
|
1110
|
-
|
|
1111
|
-
signal
|
|
1207
|
+
function callClient2(client, texts, sourceLang, targetLang, options, timeoutMs, signal) {
|
|
1208
|
+
return withRequestTimeout(
|
|
1209
|
+
timeoutMs,
|
|
1210
|
+
signal,
|
|
1211
|
+
() => client.translateText(texts, sourceLang, targetLang, options)
|
|
1112
1212
|
);
|
|
1113
1213
|
}
|
|
1114
|
-
async function callClientChunked(client, texts, sourceLang, targetLang, options, signal) {
|
|
1214
|
+
async function callClientChunked(client, texts, sourceLang, targetLang, options, timeoutMs, signal) {
|
|
1115
1215
|
const results = [];
|
|
1116
1216
|
for (const chunk2 of chunkTextsForDeepL(texts)) {
|
|
1117
|
-
const chunkResults = await callClient2(
|
|
1217
|
+
const chunkResults = await callClient2(
|
|
1218
|
+
client,
|
|
1219
|
+
chunk2,
|
|
1220
|
+
sourceLang,
|
|
1221
|
+
targetLang,
|
|
1222
|
+
options,
|
|
1223
|
+
timeoutMs,
|
|
1224
|
+
signal
|
|
1225
|
+
);
|
|
1118
1226
|
results.push(...chunkResults);
|
|
1119
1227
|
}
|
|
1120
1228
|
return results;
|
|
1121
1229
|
}
|
|
1122
1230
|
var geminiConfigSchema = zod.z.object({
|
|
1123
1231
|
model: zod.z.string().min(1),
|
|
1124
|
-
maxOutputTokens: zod.z.number().int().positive()
|
|
1232
|
+
maxOutputTokens: zod.z.number().int().positive(),
|
|
1233
|
+
/**
|
|
1234
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
1235
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
1236
|
+
* server cannot hold a locale's write lock open forever.
|
|
1237
|
+
*/
|
|
1238
|
+
requestTimeoutMs: zod.z.number().int().positive().optional()
|
|
1125
1239
|
});
|
|
1126
1240
|
var DEFAULT_GEMINI_RETRY = { attempts: 3, baseDelayMs: 250 };
|
|
1127
1241
|
function isRetryableStatus(error) {
|
|
@@ -1311,20 +1425,27 @@ function createGeminiProvider(config, deps = {}) {
|
|
|
1311
1425
|
};
|
|
1312
1426
|
}
|
|
1313
1427
|
function createMechanism2(client, config) {
|
|
1428
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
1314
1429
|
return {
|
|
1315
1430
|
translate: async ({ payloadJson, signal }) => {
|
|
1316
|
-
const
|
|
1317
|
-
|
|
1431
|
+
const response = await withRequestTimeout(
|
|
1432
|
+
timeoutMs,
|
|
1433
|
+
signal,
|
|
1434
|
+
(requestSignal) => client.models.generateContent(buildGeminiRequest(config, payloadJson, requestSignal))
|
|
1435
|
+
);
|
|
1318
1436
|
return extractGeminiResult(response);
|
|
1319
1437
|
}
|
|
1320
1438
|
};
|
|
1321
1439
|
}
|
|
1322
|
-
function callClient3(client, request, signal) {
|
|
1323
|
-
return guardProviderCall(() => client.models.generateContent(request), signal);
|
|
1324
|
-
}
|
|
1325
1440
|
var openAiConfigSchema = zod.z.object({
|
|
1326
1441
|
model: zod.z.string().min(1),
|
|
1327
|
-
maxOutputTokens: zod.z.number().int().positive()
|
|
1442
|
+
maxOutputTokens: zod.z.number().int().positive(),
|
|
1443
|
+
/**
|
|
1444
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
1445
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive
|
|
1446
|
+
* server cannot hold a locale's write lock open forever.
|
|
1447
|
+
*/
|
|
1448
|
+
requestTimeoutMs: zod.z.number().int().positive().optional()
|
|
1328
1449
|
});
|
|
1329
1450
|
function createDefaultClient4() {
|
|
1330
1451
|
const sdk = new OpenAI__default.default({ apiKey: requireOpenAiKey(), logLevel: "off" });
|
|
@@ -1479,18 +1600,20 @@ function createOpenAiProvider(config, deps = {}) {
|
|
|
1479
1600
|
};
|
|
1480
1601
|
}
|
|
1481
1602
|
function createMechanism3(client, config) {
|
|
1603
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
1482
1604
|
return {
|
|
1483
1605
|
translate: async ({ payloadJson, signal }) => {
|
|
1484
1606
|
const body = buildOpenAiRequest(config, payloadJson);
|
|
1485
|
-
const completion = await
|
|
1607
|
+
const completion = await callClient3(client, body, timeoutMs, signal);
|
|
1486
1608
|
return extractOpenAiResult(completion);
|
|
1487
1609
|
}
|
|
1488
1610
|
};
|
|
1489
1611
|
}
|
|
1490
|
-
function
|
|
1491
|
-
return
|
|
1492
|
-
|
|
1493
|
-
signal
|
|
1612
|
+
function callClient3(client, body, timeoutMs, signal) {
|
|
1613
|
+
return withRequestTimeout(
|
|
1614
|
+
timeoutMs,
|
|
1615
|
+
signal,
|
|
1616
|
+
(requestSignal) => client.chat.completions.create(body, { signal: requestSignal })
|
|
1494
1617
|
);
|
|
1495
1618
|
}
|
|
1496
1619
|
var HOSTED_PROVIDER_ENV_VARS = new Set(
|
|
@@ -1513,7 +1636,13 @@ var openAiCompatibleConfigSchema = zod.z.object({
|
|
|
1513
1636
|
maxOutputTokens: zod.z.number().int().positive(),
|
|
1514
1637
|
apiKeyEnvVar: zod.z.string().min(1).refine(isNotHostedProviderEnvVar, {
|
|
1515
1638
|
message: "apiKeyEnvVar must not name a hosted provider's environment variable."
|
|
1516
|
-
}).optional()
|
|
1639
|
+
}).optional(),
|
|
1640
|
+
/**
|
|
1641
|
+
* Optional verbatra-imposed per-request timeout in milliseconds. A positive integer; when absent,
|
|
1642
|
+
* the shared default request timeout applies. Bounds each outbound request so a hung-but-alive local
|
|
1643
|
+
* server (the reported stuck-LM-Studio case) cannot hold a locale's write lock open forever.
|
|
1644
|
+
*/
|
|
1645
|
+
requestTimeoutMs: zod.z.number().int().positive().optional()
|
|
1517
1646
|
});
|
|
1518
1647
|
function createDefaultClient5(config) {
|
|
1519
1648
|
const sdk = new OpenAI__default.default({
|
|
@@ -1545,18 +1674,20 @@ function createOpenAiCompatibleProvider(config, deps = {}) {
|
|
|
1545
1674
|
};
|
|
1546
1675
|
}
|
|
1547
1676
|
function createMechanism4(client, config) {
|
|
1677
|
+
const timeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
1548
1678
|
return {
|
|
1549
1679
|
translate: async ({ payloadJson, signal }) => {
|
|
1550
1680
|
const body = buildOpenAiRequest(config, payloadJson, "strict-schema", "max_tokens");
|
|
1551
|
-
const completion = await
|
|
1681
|
+
const completion = await callClient4(client, body, timeoutMs, signal);
|
|
1552
1682
|
return extractOpenAiResult(completion, true);
|
|
1553
1683
|
}
|
|
1554
1684
|
};
|
|
1555
1685
|
}
|
|
1556
|
-
function
|
|
1557
|
-
return
|
|
1558
|
-
|
|
1559
|
-
signal
|
|
1686
|
+
function callClient4(client, body, timeoutMs, signal) {
|
|
1687
|
+
return withRequestTimeout(
|
|
1688
|
+
timeoutMs,
|
|
1689
|
+
signal,
|
|
1690
|
+
(requestSignal) => client.chat.completions.create(body, { signal: requestSignal })
|
|
1560
1691
|
);
|
|
1561
1692
|
}
|
|
1562
1693
|
var SCAFFOLD_MODELS = {
|
|
@@ -1766,6 +1897,8 @@ var LOCAL_DIR_NAME = ".verbatra-local";
|
|
|
1766
1897
|
var LOCK_FILE_GUARD_STEM = "_lockfile";
|
|
1767
1898
|
var DEFAULT_POLL_INTERVAL_MS = 100;
|
|
1768
1899
|
var DEFAULT_ACQUIRE_TIMEOUT_MS = 10 * 6e4;
|
|
1900
|
+
var WAIT_NOTICE_INTERVAL_MS = 1e3;
|
|
1901
|
+
var MAX_LOCK_PAYLOAD_BYTES = 64 * 1024;
|
|
1769
1902
|
function lockPath(cwd, stem) {
|
|
1770
1903
|
return path.resolve(cwd, LOCAL_DIR_NAME, "locks", `${stem}.lock`);
|
|
1771
1904
|
}
|
|
@@ -1783,7 +1916,47 @@ function sleep(ms) {
|
|
|
1783
1916
|
function lockPayload() {
|
|
1784
1917
|
return JSON.stringify({ pid: process.pid, acquiredAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1785
1918
|
}
|
|
1786
|
-
|
|
1919
|
+
function parseHolder(read) {
|
|
1920
|
+
if (read.kind !== "ok") {
|
|
1921
|
+
return void 0;
|
|
1922
|
+
}
|
|
1923
|
+
let parsed;
|
|
1924
|
+
try {
|
|
1925
|
+
parsed = JSON.parse(read.content);
|
|
1926
|
+
} catch {
|
|
1927
|
+
return void 0;
|
|
1928
|
+
}
|
|
1929
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
1930
|
+
return void 0;
|
|
1931
|
+
}
|
|
1932
|
+
const record = parsed;
|
|
1933
|
+
const holder = {};
|
|
1934
|
+
if (typeof record.pid === "number") {
|
|
1935
|
+
holder.pid = record.pid;
|
|
1936
|
+
}
|
|
1937
|
+
if (typeof record.acquiredAt === "string") {
|
|
1938
|
+
holder.acquiredAt = record.acquiredAt;
|
|
1939
|
+
}
|
|
1940
|
+
return holder;
|
|
1941
|
+
}
|
|
1942
|
+
function makeWaitNotifier(path, fs, onWait, start) {
|
|
1943
|
+
let holder;
|
|
1944
|
+
let holderRead = false;
|
|
1945
|
+
let lastEmit;
|
|
1946
|
+
return async () => {
|
|
1947
|
+
if (!holderRead) {
|
|
1948
|
+
holderRead = true;
|
|
1949
|
+
holder = parseHolder(await fs.readFileBounded(path, MAX_LOCK_PAYLOAD_BYTES));
|
|
1950
|
+
}
|
|
1951
|
+
const elapsedMs = Date.now() - start;
|
|
1952
|
+
if (lastEmit !== void 0 && elapsedMs - lastEmit < WAIT_NOTICE_INTERVAL_MS) {
|
|
1953
|
+
return;
|
|
1954
|
+
}
|
|
1955
|
+
lastEmit = elapsedMs;
|
|
1956
|
+
onWait({ lockPath: path, elapsedMs, ...holder !== void 0 ? { holder } : {} });
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
async function acquireLock(path, fs, pollIntervalMs, deadline, notify) {
|
|
1787
1960
|
for (; ; ) {
|
|
1788
1961
|
if (await fs.createExclusive(path, lockPayload())) {
|
|
1789
1962
|
return;
|
|
@@ -1794,6 +1967,9 @@ async function acquireLock(path, fs, pollIntervalMs, deadline) {
|
|
|
1794
1967
|
`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.`
|
|
1795
1968
|
);
|
|
1796
1969
|
}
|
|
1970
|
+
if (notify !== void 0) {
|
|
1971
|
+
await notify();
|
|
1972
|
+
}
|
|
1797
1973
|
const jitter = Math.random() * pollIntervalMs;
|
|
1798
1974
|
await sleep(pollIntervalMs + jitter);
|
|
1799
1975
|
}
|
|
@@ -1801,7 +1977,9 @@ async function acquireLock(path, fs, pollIntervalMs, deadline) {
|
|
|
1801
1977
|
async function withFileLock(path, fs, fn, options) {
|
|
1802
1978
|
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
1803
1979
|
const acquireTimeoutMs = options.acquireTimeoutMs ?? DEFAULT_ACQUIRE_TIMEOUT_MS;
|
|
1804
|
-
|
|
1980
|
+
const start = Date.now();
|
|
1981
|
+
const notify = options.onWait !== void 0 ? makeWaitNotifier(path, fs, options.onWait, start) : void 0;
|
|
1982
|
+
await acquireLock(path, fs, pollIntervalMs, start + acquireTimeoutMs, notify);
|
|
1805
1983
|
try {
|
|
1806
1984
|
return await fn();
|
|
1807
1985
|
} finally {
|
|
@@ -3486,6 +3664,9 @@ function gateCandidateValue(sourceEntry, candidateValue, adapter) {
|
|
|
3486
3664
|
if (!adapter.validateMessage(candidateValue)) {
|
|
3487
3665
|
return { accepted: false, reason: "icu" };
|
|
3488
3666
|
}
|
|
3667
|
+
if (assessValueDegeneracy(sourceEntry.value, candidateValue).degenerate) {
|
|
3668
|
+
return { accepted: false, reason: "degenerate" };
|
|
3669
|
+
}
|
|
3489
3670
|
return { accepted: true };
|
|
3490
3671
|
}
|
|
3491
3672
|
|
|
@@ -3773,7 +3954,7 @@ var runBudgetSchema = zod.z.object({
|
|
|
3773
3954
|
});
|
|
3774
3955
|
var runStatusLocaleSchema = zod.z.object({
|
|
3775
3956
|
locale: zod.z.string(),
|
|
3776
|
-
status: zod.z.enum(["succeeded", "failed"]),
|
|
3957
|
+
status: zod.z.enum(["succeeded", "partial", "failed"]),
|
|
3777
3958
|
needsReview: zod.z.array(needsReviewEntrySchema),
|
|
3778
3959
|
usage: usageSummarySchema.optional()
|
|
3779
3960
|
});
|
|
@@ -3918,10 +4099,21 @@ function failureSummary(locale, error) {
|
|
|
3918
4099
|
error: describeError(error)
|
|
3919
4100
|
};
|
|
3920
4101
|
}
|
|
4102
|
+
function deriveLocaleStatus(parts) {
|
|
4103
|
+
const withheld = parts.integrityMismatches.length > 0 || parts.providerFailures.length > 0 || parts.budgetWithheld.length > 0;
|
|
4104
|
+
if (!withheld) {
|
|
4105
|
+
return "succeeded";
|
|
4106
|
+
}
|
|
4107
|
+
const accepted = parts.translated.length > 0 || parts.generated.length > 0;
|
|
4108
|
+
return accepted ? "partial" : "failed";
|
|
4109
|
+
}
|
|
3921
4110
|
function partition(locales) {
|
|
3922
|
-
const
|
|
3923
|
-
|
|
3924
|
-
|
|
4111
|
+
const namesWith = (status) => locales.filter((s) => s.status === status).map((s) => s.locale);
|
|
4112
|
+
return {
|
|
4113
|
+
succeeded: namesWith("succeeded"),
|
|
4114
|
+
partial: namesWith("partial"),
|
|
4115
|
+
failed: namesWith("failed")
|
|
4116
|
+
};
|
|
3925
4117
|
}
|
|
3926
4118
|
|
|
3927
4119
|
// src/flow/batching.ts
|
|
@@ -4402,7 +4594,7 @@ function pluralNoticeFor(params, merged) {
|
|
|
4402
4594
|
function baseSummary(parts) {
|
|
4403
4595
|
return {
|
|
4404
4596
|
locale: parts.locale,
|
|
4405
|
-
status:
|
|
4597
|
+
status: deriveLocaleStatus(parts),
|
|
4406
4598
|
translated: parts.translated,
|
|
4407
4599
|
unchanged: parts.unchanged,
|
|
4408
4600
|
orphaned: parts.orphaned,
|
|
@@ -4461,10 +4653,16 @@ async function runSubBatch(provider, params, batch, accepted, integrityMismatche
|
|
|
4461
4653
|
try {
|
|
4462
4654
|
result = await provider.translateBatch(buildRequest3(params, batch));
|
|
4463
4655
|
} catch (error) {
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4656
|
+
return handleSubBatchFailure(
|
|
4657
|
+
error,
|
|
4658
|
+
provider,
|
|
4659
|
+
params,
|
|
4660
|
+
batch,
|
|
4661
|
+
accepted,
|
|
4662
|
+
integrityMismatches,
|
|
4663
|
+
providerFailures,
|
|
4664
|
+
reviewFlags
|
|
4665
|
+
);
|
|
4468
4666
|
}
|
|
4469
4667
|
for (const entry of batch) {
|
|
4470
4668
|
foldEntryResult(entry, result, params.adapter, accepted, integrityMismatches, providerFailures);
|
|
@@ -4476,6 +4674,44 @@ async function runSubBatch(provider, params, batch, accepted, integrityMismatche
|
|
|
4476
4674
|
}
|
|
4477
4675
|
return { notices: readNotices(result), usage: result.usage };
|
|
4478
4676
|
}
|
|
4677
|
+
function isOutputTruncated(error) {
|
|
4678
|
+
return error instanceof ProviderError && error.code === "OUTPUT_TRUNCATED";
|
|
4679
|
+
}
|
|
4680
|
+
async function handleSubBatchFailure(error, provider, params, batch, accepted, integrityMismatches, providerFailures, reviewFlags) {
|
|
4681
|
+
if (isOutputTruncated(error) && batch.length > 1) {
|
|
4682
|
+
return retryTruncatedSplit(
|
|
4683
|
+
provider,
|
|
4684
|
+
params,
|
|
4685
|
+
batch,
|
|
4686
|
+
accepted,
|
|
4687
|
+
integrityMismatches,
|
|
4688
|
+
providerFailures,
|
|
4689
|
+
reviewFlags
|
|
4690
|
+
);
|
|
4691
|
+
}
|
|
4692
|
+
for (const entry of batch) {
|
|
4693
|
+
providerFailures.push(entry.key);
|
|
4694
|
+
}
|
|
4695
|
+
return { notices: [subBatchFailedNotice(batch.length, error)], usage: void 0 };
|
|
4696
|
+
}
|
|
4697
|
+
async function retryTruncatedSplit(provider, params, batch, accepted, integrityMismatches, providerFailures, reviewFlags) {
|
|
4698
|
+
const notices = [];
|
|
4699
|
+
let usage;
|
|
4700
|
+
for (const half of chunk(batch, Math.ceil(batch.length / 2))) {
|
|
4701
|
+
const sub = await runSubBatch(
|
|
4702
|
+
provider,
|
|
4703
|
+
params,
|
|
4704
|
+
half,
|
|
4705
|
+
accepted,
|
|
4706
|
+
integrityMismatches,
|
|
4707
|
+
providerFailures,
|
|
4708
|
+
reviewFlags
|
|
4709
|
+
);
|
|
4710
|
+
notices.push(...sub.notices);
|
|
4711
|
+
usage = combineUsage(usage, sub.usage);
|
|
4712
|
+
}
|
|
4713
|
+
return { notices, usage };
|
|
4714
|
+
}
|
|
4479
4715
|
function foldEntryResult(entry, result, adapter, accepted, integrityMismatches, providerFailures) {
|
|
4480
4716
|
const value = result.values.get(entry.key);
|
|
4481
4717
|
if (value === void 0) {
|
|
@@ -4559,16 +4795,26 @@ async function runDryLocale(context, targetLocale, lock) {
|
|
|
4559
4795
|
return (await runLocale(params)).summary;
|
|
4560
4796
|
}
|
|
4561
4797
|
async function runLiveLocale(context, targetLocale) {
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4798
|
+
const lockOptions = {
|
|
4799
|
+
...context.onLockWait !== void 0 ? { onWait: context.onLockWait } : {},
|
|
4800
|
+
...context.lockAcquireTimeoutMs !== void 0 ? { acquireTimeoutMs: context.lockAcquireTimeoutMs } : {}
|
|
4801
|
+
};
|
|
4802
|
+
return withLocaleWriteLock(
|
|
4803
|
+
context.cwd,
|
|
4804
|
+
targetLocale,
|
|
4805
|
+
context.fs,
|
|
4806
|
+
async () => {
|
|
4807
|
+
const lock = await readLockFile(lockFilePath(context.cwd), context.fs);
|
|
4808
|
+
const params = buildLocaleRunParams(context, targetLocale, baselineFor(lock, targetLocale));
|
|
4809
|
+
const result = await runLocale(params);
|
|
4810
|
+
await updateLockFileLocale(context.cwd, context.fs, targetLocale, {
|
|
4811
|
+
mode: "replace",
|
|
4812
|
+
entries: result.lockEntries
|
|
4813
|
+
});
|
|
4814
|
+
return result.summary;
|
|
4815
|
+
},
|
|
4816
|
+
lockOptions
|
|
4817
|
+
);
|
|
4572
4818
|
}
|
|
4573
4819
|
async function runOneLocale(targetLocale, run) {
|
|
4574
4820
|
try {
|
|
@@ -4622,10 +4868,12 @@ async function translate2(input, deps = {}) {
|
|
|
4622
4868
|
generatePlurals,
|
|
4623
4869
|
maxBatchSize,
|
|
4624
4870
|
fs,
|
|
4625
|
-
budget
|
|
4871
|
+
budget,
|
|
4872
|
+
...input.onLockWait !== void 0 ? { onLockWait: input.onLockWait } : {},
|
|
4873
|
+
...input.lockAcquireTimeoutMs !== void 0 ? { lockAcquireTimeoutMs: input.lockAcquireTimeoutMs } : {}
|
|
4626
4874
|
};
|
|
4627
4875
|
const summaries = dryRun ? await runAllLocalesDry(context, config.targetLocales) : await runAllLocalesLive(context, config.targetLocales);
|
|
4628
|
-
const { succeeded, failed } = partition(summaries);
|
|
4876
|
+
const { succeeded, partial, failed } = partition(summaries);
|
|
4629
4877
|
const usage = summaries.reduce(
|
|
4630
4878
|
(total, summary2) => combineUsage(total, summary2.usage),
|
|
4631
4879
|
void 0
|
|
@@ -4635,6 +4883,7 @@ async function translate2(input, deps = {}) {
|
|
|
4635
4883
|
dryRun,
|
|
4636
4884
|
locales: summaries,
|
|
4637
4885
|
succeeded,
|
|
4886
|
+
partial,
|
|
4638
4887
|
failed,
|
|
4639
4888
|
...usage !== void 0 ? { usage } : {},
|
|
4640
4889
|
...budgetSummary !== void 0 ? { budget: budgetSummary } : {}
|
|
@@ -5193,15 +5442,23 @@ function importLocale(params) {
|
|
|
5193
5442
|
classifyRows(params, buckets);
|
|
5194
5443
|
const rowKeys = new Set(params.sheet.rows.map((row) => row.key));
|
|
5195
5444
|
const invalidIcuSource = [...new Set(params.sourceInvalidIcuKeys)].filter((key) => rowKeys.has(key)).sort();
|
|
5445
|
+
const translated = [...buckets.accepted.keys()].sort();
|
|
5446
|
+
const integrityMismatches = [...buckets.mismatches].sort();
|
|
5196
5447
|
const summary = {
|
|
5197
5448
|
locale: params.sheet.locale,
|
|
5198
|
-
status:
|
|
5199
|
-
|
|
5449
|
+
status: deriveLocaleStatus({
|
|
5450
|
+
translated,
|
|
5451
|
+
generated: [],
|
|
5452
|
+
integrityMismatches,
|
|
5453
|
+
providerFailures: [],
|
|
5454
|
+
budgetWithheld: []
|
|
5455
|
+
}),
|
|
5456
|
+
translated,
|
|
5200
5457
|
unchanged: diff2.unchanged,
|
|
5201
5458
|
orphaned: diff2.orphaned,
|
|
5202
5459
|
pruned: [],
|
|
5203
5460
|
invalidIcuSource,
|
|
5204
|
-
integrityMismatches
|
|
5461
|
+
integrityMismatches,
|
|
5205
5462
|
providerFailures: [],
|
|
5206
5463
|
budgetWithheld: [],
|
|
5207
5464
|
generated: [],
|
|
@@ -5330,8 +5587,8 @@ async function importWorkbook(input, deps = {}) {
|
|
|
5330
5587
|
summaries.push(failureSummary(sheet.locale, error));
|
|
5331
5588
|
}
|
|
5332
5589
|
}
|
|
5333
|
-
const { succeeded, failed } = partition(summaries);
|
|
5334
|
-
return { dryRun, locales: summaries, succeeded, failed };
|
|
5590
|
+
const { succeeded, partial, failed } = partition(summaries);
|
|
5591
|
+
return { dryRun, locales: summaries, succeeded, partial, failed };
|
|
5335
5592
|
}
|
|
5336
5593
|
|
|
5337
5594
|
// src/lock/load-lock-file.ts
|
|
@@ -5389,7 +5646,12 @@ async function watch(input, deps = {}) {
|
|
|
5389
5646
|
);
|
|
5390
5647
|
}
|
|
5391
5648
|
const runTranslate = deps.runTranslate ?? defaultRunTranslate(deps);
|
|
5392
|
-
const runInput = {
|
|
5649
|
+
const runInput = {
|
|
5650
|
+
config: input.config,
|
|
5651
|
+
cwd,
|
|
5652
|
+
...input.onLockWait !== void 0 ? { onLockWait: input.onLockWait } : {},
|
|
5653
|
+
...input.lockAcquireTimeoutMs !== void 0 ? { lockAcquireTimeoutMs: input.lockAcquireTimeoutMs } : {}
|
|
5654
|
+
};
|
|
5393
5655
|
let state = "idle";
|
|
5394
5656
|
let pending = false;
|
|
5395
5657
|
let stopped = false;
|