@belocal/js-sdk 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.cjs CHANGED
@@ -24,141 +24,151 @@ function _interopNamespace(e) {
24
24
 
25
25
  var http2__namespace = /*#__PURE__*/_interopNamespace(http2);
26
26
 
27
- // src/transports/batch.ts
28
- function generateRequestId(text, lang, source_lang, ctx) {
29
- const data = {
30
- text,
31
- lang,
32
- source_lang: source_lang || null,
33
- ctx: ctx || null
34
- };
35
- return jsMd5.md5(JSON.stringify(data));
27
+ // src/transports/multi.ts
28
+ function generateRequestId(texts, lang, sourceLang, context) {
29
+ const sortedTexts = [...texts].sort();
30
+ let sortedContext = null;
31
+ if (context && Object.keys(context).length > 0) {
32
+ sortedContext = {};
33
+ const sortedKeys = Object.keys(context).sort();
34
+ for (const key of sortedKeys) {
35
+ sortedContext[key] = context[key];
36
+ }
37
+ }
38
+ const data = [sortedTexts, lang, sourceLang || null, sortedContext];
39
+ const json = JSON.stringify(data);
40
+ return jsMd5.md5(json);
36
41
  }
37
- async function sendBatch(config, batch, state) {
42
+ async function sendMulti(config, items, state) {
38
43
  if (config.debug) {
39
- console.log(`[BeLocal Batch Transport] Sending batch of ${batch.length} requests`);
44
+ console.log(`[BeLocal Multi Transport] Sending multi request with ${items.length} texts`);
40
45
  }
41
46
  try {
42
- const batchRequests = batch.map((item) => ({
43
- requestId: item.requestId,
44
- payload: item.payload
45
- }));
46
- const batchResponse = await config.baseTransport.post({ batch: batchRequests }, "/v1/translate/batch");
47
+ const groups = /* @__PURE__ */ new Map();
48
+ items.forEach((item) => {
49
+ const groupKey = JSON.stringify({
50
+ lang: item.lang,
51
+ sourceLang: item.sourceLang || null,
52
+ context: item.context || null
53
+ });
54
+ if (!groups.has(groupKey)) {
55
+ groups.set(groupKey, []);
56
+ }
57
+ groups.get(groupKey).push(item);
58
+ });
59
+ const requestIdToGroupItems = /* @__PURE__ */ new Map();
60
+ const requests = Array.from(groups.entries()).map(([groupKey, groupItems]) => {
61
+ const firstItem = groupItems[0];
62
+ const texts = groupItems.map((item) => item.text);
63
+ const requestId = generateRequestId(
64
+ texts,
65
+ firstItem.lang,
66
+ firstItem.sourceLang,
67
+ firstItem.context
68
+ );
69
+ requestIdToGroupItems.set(requestId, groupItems);
70
+ return {
71
+ requestId,
72
+ texts,
73
+ lang: firstItem.lang,
74
+ sourceLang: firstItem.sourceLang,
75
+ context: firstItem.context
76
+ };
77
+ });
78
+ const multiResponse = await config.baseTransport.post({ requests }, "/v1/translate/multi");
47
79
  if (config.debug) {
48
- console.log(`[BeLocal Batch Transport] Batch response received with ${batchResponse.results.length} results`);
80
+ console.log(`[BeLocal Multi Transport] Multi response received with ${multiResponse.results.length} groups`);
49
81
  }
50
82
  const resultMap = /* @__PURE__ */ new Map();
51
- batchResponse.results.forEach((result) => {
52
- resultMap.set(result.requestId, { data: result.data, error: result.error });
83
+ multiResponse.results.forEach((result) => {
84
+ resultMap.set(result.requestId, { texts: result.data.texts, status: result.data.status });
53
85
  });
54
- batch.forEach((item) => {
55
- const result = resultMap.get(item.requestId);
86
+ requestIdToGroupItems.forEach((groupItems, requestId) => {
87
+ const result = resultMap.get(requestId);
56
88
  if (!result) {
57
89
  if (config.debug) {
58
- console.error(`[BeLocal Batch Transport] No result found for requestId: ${item.requestId}`);
90
+ console.error(`[BeLocal Multi Transport] No result found for requestId: ${requestId}`);
59
91
  }
60
- item.reject(new Error(`No result found for request ${item.requestId}`));
92
+ groupItems.forEach((item) => {
93
+ item.reject(new Error(`No result found for request ${requestId}`));
94
+ });
61
95
  return;
62
96
  }
63
- if (result.error) {
97
+ if (result.texts.length !== groupItems.length) {
98
+ const error = new Error(`Mismatch: expected ${groupItems.length} texts, got ${result.texts.length} for requestId ${requestId}`);
64
99
  if (config.debug) {
65
- console.error(`[BeLocal Batch Transport] Error for requestId ${item.requestId}:`, result.error.message);
100
+ console.error(`[BeLocal Multi Transport]`, error.message);
66
101
  }
67
- item.reject(new Error(result.error.message));
68
- } else if (result.data) {
69
- if (config.debug) {
70
- console.log(`[BeLocal Batch Transport] Success for requestId ${item.requestId}: "${result.data.text}"`);
71
- }
72
- const status = result.data.status || "success";
73
- item.resolve({ text: result.data.text, status });
74
- } else {
102
+ groupItems.forEach((item) => item.reject(error));
103
+ return;
104
+ }
105
+ groupItems.forEach((item, index) => {
106
+ const translatedText = result.texts[index];
107
+ const status = result.status || "success";
75
108
  if (config.debug) {
76
- console.warn(`[BeLocal Batch Transport] No data or error for requestId ${item.requestId}, returning original text`);
109
+ console.log(`[BeLocal Multi Transport] Success for requestId ${requestId}[${index}]: "${translatedText}"`);
77
110
  }
78
- item.resolve({ text: item.payload.text, status: "error" });
79
- }
111
+ item.resolve({ text: translatedText, status });
112
+ });
80
113
  });
81
114
  } catch (error) {
82
115
  if (config.debug) {
83
- console.error(`[BeLocal Batch Transport] Batch request error:`, error);
116
+ console.error(`[BeLocal Multi Transport] Multi request error:`, error);
84
117
  }
85
118
  const errorToReject = error instanceof Error ? error : new Error(String(error));
86
- batch.forEach((item) => item.reject(errorToReject));
119
+ items.forEach((item) => item.reject(errorToReject));
87
120
  } finally {
88
121
  }
89
122
  }
90
- function processBatch(config, state) {
91
- if (state.currentBatch.length === 0 || state.isRequestInFlight) {
123
+ function processMulti(config, state) {
124
+ if (state.currentMulti.length === 0 || state.isRequestInFlight) {
92
125
  return;
93
126
  }
94
- const batchToSend = [...state.currentBatch];
95
- state.currentBatch = [];
96
- state.batchTimer = null;
127
+ const itemsToSend = [...state.currentMulti];
128
+ state.currentMulti = [];
129
+ state.multiTimer = null;
97
130
  state.isRequestInFlight = true;
98
- sendBatch(config, batchToSend).finally(() => {
131
+ sendMulti(config, itemsToSend).finally(() => {
99
132
  state.isRequestInFlight = false;
100
- if (state.currentBatch.length > 0) {
133
+ if (state.currentMulti.length > 0) {
101
134
  const windowMs = config.batchWindowMs ?? 50;
102
- state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);
135
+ state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
103
136
  }
104
137
  });
105
138
  }
106
- function createBatchTransport(config) {
139
+ function createMultiTransport(config) {
107
140
  const windowMs = config.batchWindowMs ?? 50;
108
141
  const state = {
109
- currentBatch: [],
110
- batchTimer: null,
142
+ currentMulti: [],
143
+ multiTimer: null,
111
144
  isRequestInFlight: false
112
145
  };
113
146
  return ({ text, lang, source_lang, ctx }) => {
114
147
  return new Promise((resolve, reject) => {
115
- const requestId = generateRequestId(text, lang, source_lang, ctx);
116
148
  if (config.debug) {
117
- console.log(`[BeLocal Batch Transport] Queuing request ${requestId}: "${text}" to ${lang}`);
149
+ const tempRequestId = jsMd5.md5(JSON.stringify([text, lang, source_lang || null, ctx || null]));
150
+ console.log(`[BeLocal Multi Transport] Queuing request ${tempRequestId}: "${text}" to ${lang}`);
118
151
  }
119
152
  const requestItem = {
120
- requestId,
121
- payload: { text, lang, source_lang, ctx },
153
+ text,
154
+ lang,
155
+ sourceLang: source_lang,
156
+ context: ctx,
122
157
  resolve,
123
158
  reject
124
159
  };
125
- state.currentBatch.push(requestItem);
126
- if (state.batchTimer === null && !state.isRequestInFlight) {
127
- state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);
160
+ state.currentMulti.push(requestItem);
161
+ if (state.multiTimer === null && !state.isRequestInFlight) {
162
+ state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
128
163
  }
129
164
  });
130
165
  };
131
166
  }
132
167
 
133
- // src/transports/single.ts
134
- function createSingleTransport(config) {
135
- return async ({ text, lang, source_lang, ctx }) => {
136
- if (config.debug) {
137
- console.log(`[BeLocal Single Transport] Translating "${text}" to ${lang}`);
138
- }
139
- try {
140
- const result = await config.baseTransport.post({ text, lang, source_lang, ctx }, "/v1/translate");
141
- if (config.debug) {
142
- if (result.status === "error") {
143
- console.log(`[BeLocal Single Transport] Translation failed: "${result.text || text}"`);
144
- } else {
145
- console.log(`[BeLocal Single Transport] Translation successful: "${result.text || text}"`);
146
- }
147
- }
148
- return { text: result.text || text, status: result.status || "error" };
149
- } catch (error) {
150
- if (config.debug) {
151
- console.error(`[BeLocal Single Transport] Request failed:`, error);
152
- }
153
- throw error;
154
- }
155
- };
156
- }
157
-
158
168
  // src/version.ts
159
169
  var SDK_VERSION = (() => {
160
170
  try {
161
- return true ? "0.4.2" : "undefined";
171
+ return true ? "0.5.0" : "undefined";
162
172
  } catch {
163
173
  return "undefined";
164
174
  }
@@ -331,53 +341,63 @@ var BelocalEngine = class {
331
341
  timeoutMs,
332
342
  debug: this.debug
333
343
  });
334
- if (batchWindowMs > 0) {
335
- this.transport = createBatchTransport({
336
- baseTransport,
337
- debug: this.debug,
344
+ this.transport = createMultiTransport({
345
+ baseTransport,
346
+ debug: this.debug,
347
+ batchWindowMs
348
+ });
349
+ if (this.debug) {
350
+ console.log("[BeLocal Engine] Multi transport created with config:", {
351
+ baseUrl,
352
+ timeoutMs,
338
353
  batchWindowMs
339
354
  });
340
- if (this.debug) {
341
- console.log("[BeLocal Engine] Batch transport created with config:", {
342
- baseUrl,
343
- timeoutMs,
344
- batchWindowMs
345
- });
346
- }
347
- } else {
348
- this.transport = createSingleTransport({
349
- baseTransport,
350
- debug: this.debug
351
- });
352
- if (this.debug) {
353
- console.log("[BeLocal Engine] Single transport created with config:", {
354
- baseUrl,
355
- timeoutMs
356
- });
357
- }
358
355
  }
359
356
  }
360
357
  async translate(text, lang, source_lang, ctx) {
361
- const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);
362
- const cachedResult = this.cache.get(cacheKey);
363
- if (cachedResult) {
364
- if (this.debug) {
365
- console.log("[BeLocal Engine] Translation from local cache:", text);
358
+ const results = await this.translateMany([text], lang, source_lang, ctx);
359
+ return results[0];
360
+ }
361
+ async translateMany(texts, lang, source_lang, ctx) {
362
+ const results = new Array(texts.length);
363
+ const cacheMisses = [];
364
+ for (let i = 0; i < texts.length; i++) {
365
+ const text = texts[i];
366
+ const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);
367
+ const cachedResult = this.cache.get(cacheKey);
368
+ if (cachedResult) {
369
+ results[i] = cachedResult;
370
+ if (this.debug) {
371
+ console.log("[BeLocal Engine] Translation from local cache:", text);
372
+ }
373
+ continue;
366
374
  }
367
- return cachedResult;
375
+ results[i] = null;
376
+ cacheMisses.push({ index: i, text });
368
377
  }
369
- const result = await this.transport({ text, lang, source_lang, ctx });
370
- if (result.status !== "error") {
371
- this.cache.set(cacheKey, result.text);
372
- if (this.debug) {
373
- console.log("[BeLocal Engine] Translation from API, cached in local:", text);
374
- }
375
- } else {
376
- if (this.debug) {
377
- console.log("[BeLocal Engine] Translation from API (not cached due to error status):", text);
378
- }
378
+ if (cacheMisses.length > 0) {
379
+ const translations = await Promise.all(
380
+ cacheMisses.map(async ({ index, text }) => {
381
+ const result = await this.transport({ text, lang, source_lang, ctx });
382
+ if (result.status !== "error") {
383
+ const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);
384
+ this.cache.set(cacheKey, result.text);
385
+ if (this.debug) {
386
+ console.log("[BeLocal Engine] Translation from API, cached in local:", text);
387
+ }
388
+ } else {
389
+ if (this.debug) {
390
+ console.log("[BeLocal Engine] Translation from API (not cached due to error status):", text);
391
+ }
392
+ }
393
+ return { index, translation: result.text };
394
+ })
395
+ );
396
+ translations.forEach(({ index, translation }) => {
397
+ results[index] = translation;
398
+ });
379
399
  }
380
- return result.text;
400
+ return results;
381
401
  }
382
402
  async t(text, lang, source_lang, context) {
383
403
  if (context) {
@@ -403,7 +423,6 @@ var BelocalEngine = class {
403
423
  exports.BaseNodeTransport = BaseNodeTransport;
404
424
  exports.BelocalEngine = BelocalEngine;
405
425
  exports.createBaseNodeTransport = createBaseNodeTransport;
406
- exports.createBatchTransport = createBatchTransport;
407
- exports.createSingleTransport = createSingleTransport;
426
+ exports.createMultiTransport = createMultiTransport;
408
427
  //# sourceMappingURL=node.cjs.map
409
428
  //# sourceMappingURL=node.cjs.map
package/dist/node.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transports/batch.ts","../src/transports/single.ts","../src/version.ts","../src/transports/base/node.ts","../src/cache/local.ts","../src/core/engine/node.ts"],"names":["md5","session","URL","http2","headers"],"mappings":"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","file":"node.cjs","sourcesContent":["import type { Transport, BaseTransport } from '../core/types';\nimport { md5 } from 'js-md5';\n\nexport interface BatchTransportConfig {\n baseTransport: BaseTransport;\n debug?: boolean;\n batchWindowMs?: number;\n}\n\ninterface BatchRequest {\n requestId: string;\n payload: { text: string; lang: string; source_lang?: string; ctx?: Record<string, string> };\n}\n\ninterface BatchRequestItem {\n requestId: string;\n payload: { text: string; lang: string; source_lang?: string; ctx?: Record<string, string> };\n resolve: (value: { text: string; status: string }) => void;\n reject: (error: Error) => void;\n}\n\ninterface BatchResponse {\n results: Array<{\n requestId: string;\n data?: { text: string; status: string };\n error?: { message: string };\n }>;\n}\n\ninterface BatchState {\n currentBatch: BatchRequestItem[];\n batchTimer: ReturnType<typeof setTimeout> | null;\n isRequestInFlight: boolean;\n}\n\nfunction generateRequestId(text: string, lang: string, source_lang?: string, ctx?: Record<string, string>): string {\n const data = {\n text,\n lang,\n source_lang: source_lang || null,\n ctx: ctx || null\n };\n return md5(JSON.stringify(data));\n}\n\nasync function sendBatch(\n config: BatchTransportConfig,\n batch: BatchRequestItem[],\n state: BatchState\n): Promise<void> {\n if (config.debug) {\n console.log(`[BeLocal Batch Transport] Sending batch of ${batch.length} requests`);\n }\n\n try {\n const batchRequests: BatchRequest[] = batch.map(item => ({\n requestId: item.requestId,\n payload: item.payload,\n }));\n\n const batchResponse: BatchResponse = await config.baseTransport.post({ batch: batchRequests }, '/v1/translate/batch');\n \n if (config.debug) {\n console.log(`[BeLocal Batch Transport] Batch response received with ${batchResponse.results.length} results`);\n }\n\n // Создаем map для быстрого поиска результатов по requestId\n const resultMap = new Map<string, { data?: { text: string; status?: string }; error?: { message: string } }>();\n batchResponse.results.forEach(result => {\n resultMap.set(result.requestId, { data: result.data, error: result.error });\n });\n\n // Раздаем результаты каждому промису\n batch.forEach(item => {\n const result = resultMap.get(item.requestId);\n \n if (!result) {\n if (config.debug) {\n console.error(`[BeLocal Batch Transport] No result found for requestId: ${item.requestId}`);\n }\n item.reject(new Error(`No result found for request ${item.requestId}`));\n return;\n }\n\n if (result.error) {\n if (config.debug) {\n console.error(`[BeLocal Batch Transport] Error for requestId ${item.requestId}:`, result.error.message);\n }\n item.reject(new Error(result.error.message));\n } else if (result.data) {\n if (config.debug) {\n console.log(`[BeLocal Batch Transport] Success for requestId ${item.requestId}: \"${result.data.text}\"`);\n }\n // Use status from data if available, otherwise default to 'success'\n const status = result.data.status || 'success';\n item.resolve({ text: result.data.text, status });\n } else {\n // Фоллбэк: если нет ни data, ни error, возвращаем оригинальный текст с error status\n if (config.debug) {\n console.warn(`[BeLocal Batch Transport] No data or error for requestId ${item.requestId}, returning original text`);\n }\n item.resolve({ text: item.payload.text, status: 'error' });\n }\n });\n\n } catch (error) {\n if (config.debug) {\n console.error(`[BeLocal Batch Transport] Batch request error:`, error);\n }\n \n // При ошибке сети отклоняем все промисы в батче\n const errorToReject = error instanceof Error ? error : new Error(String(error));\n batch.forEach(item => item.reject(errorToReject));\n } finally {\n // Cleanup handled by base transport\n }\n}\n\nfunction processBatch(config: BatchTransportConfig, state: BatchState): void {\n if (state.currentBatch.length === 0 || state.isRequestInFlight) {\n return;\n }\n\n const batchToSend = [...state.currentBatch];\n state.currentBatch = [];\n state.batchTimer = null;\n state.isRequestInFlight = true;\n\n sendBatch(config, batchToSend, state).finally(() => {\n state.isRequestInFlight = false;\n \n if (state.currentBatch.length > 0) {\n const windowMs = config.batchWindowMs ?? 50;\n state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);\n }\n });\n}\n\nexport function createBatchTransport(config: BatchTransportConfig): Transport {\n const windowMs = config.batchWindowMs ?? 50;\n\n const state: BatchState = {\n currentBatch: [],\n batchTimer: null,\n isRequestInFlight: false,\n };\n \n return ({ text, lang, source_lang, ctx }) => {\n return new Promise<{ text: string; status: string }>((resolve, reject) => {\n const requestId = generateRequestId(text, lang, source_lang, ctx);\n \n if (config.debug) {\n console.log(`[BeLocal Batch Transport] Queuing request ${requestId}: \"${text}\" to ${lang}`);\n }\n\n const requestItem: BatchRequestItem = {\n requestId,\n payload: { text, lang, source_lang, ctx },\n resolve,\n reject,\n };\n\n state.currentBatch.push(requestItem);\n\n if (state.batchTimer === null && !state.isRequestInFlight) {\n state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);\n }\n });\n };\n}\n","import type { Transport, BaseTransport } from '../core/types';\n\nexport interface SingleTransportConfig {\n baseTransport: BaseTransport;\n debug?: boolean;\n}\n\ninterface TranslationResponse {\n text: string;\n status: string;\n}\n\nexport function createSingleTransport(config: SingleTransportConfig): Transport {\n return async ({ text, lang, source_lang, ctx }) => {\n if (config.debug) {\n console.log(`[BeLocal Single Transport] Translating \"${text}\" to ${lang}`);\n }\n\n try {\n const result: TranslationResponse = await config.baseTransport.post({ text, lang, source_lang, ctx }, '/v1/translate');\n \n if (config.debug) {\n if (result.status === 'error') {\n console.log(`[BeLocal Single Transport] Translation failed: \"${result.text || text}\"`);\n } else {\n console.log(`[BeLocal Single Transport] Translation successful: \"${result.text || text}\"`);\n }\n }\n \n return { text: result.text || text, status: result.status || 'error' };\n } catch (error) {\n if (config.debug) {\n console.error(`[BeLocal Single Transport] Request failed:`, error);\n }\n throw error;\n }\n };\n}\n","// SDK version - will be replaced during build with tsup define\ndeclare const __SDK_VERSION__: string | undefined;\n\n// Safely check if __SDK_VERSION__ is defined (replaced during build)\nexport const SDK_VERSION: string = \n (() => { try { return typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : 'undefined'; } catch { return 'undefined'; } })();\n\nexport const SDK_NAME = 'js';\n\n","import * as http2 from 'node:http2';\nimport { URL } from 'node:url';\nimport type { BaseTransport } from '../../core/types';\nimport { SDK_NAME, SDK_VERSION } from '../../version';\n\nexport interface BaseNodeTransportConfig {\n baseUrl: string;\n headers?: Record<string, string>;\n timeoutMs?: number;\n retries?: number;\n debug?: boolean;\n}\n\n// Global session cache for HTTP/2 connections\nconst sessionCache = new Map<string, http2.ClientHttp2Session>();\n\nfunction getOrCreateSession(baseUrl: string, debug?: boolean): http2.ClientHttp2Session {\n if (sessionCache.has(baseUrl)) {\n const session = sessionCache.get(baseUrl)!;\n if (!session.destroyed) {\n return session;\n }\n sessionCache.delete(baseUrl);\n }\n\n const parsedUrl = new URL(baseUrl);\n const session = http2.connect(parsedUrl.origin);\n\n session.socket?.unref();\n \n // Set up session cleanup\n session.on('error', () => {\n sessionCache.delete(baseUrl);\n });\n \n session.on('close', () => {\n sessionCache.delete(baseUrl);\n });\n\n // Add debug logging if enabled\n if (debug) {\n session.on('connect', () => console.log('[Base Node Transport H2] new session connected'));\n session.on('goaway', (code, lastStreamID, opaque) =>\n console.log('[Base Node Transport H2] goaway', code, lastStreamID)\n );\n }\n \n sessionCache.set(baseUrl, session);\n return session;\n}\n\nfunction makeHttp2Request(\n session: http2.ClientHttp2Session,\n path: string,\n headers: Record<string, string>,\n body: string,\n timeoutMs?: number\n): Promise<{ statusCode: number; headers: Record<string, string>; body: string }> {\n return new Promise((resolve, reject) => {\n const req = session.request({\n ':method': 'POST',\n ':path': path,\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(body),\n ...headers,\n });\n\n let timeout: NodeJS.Timeout | null = null;\n if (timeoutMs) {\n timeout = setTimeout(() => {\n req.destroy();\n reject(new Error(`Request timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n }\n\n let responseData = '';\n let statusCode = 0;\n let responseHeaders: Record<string, string> = {};\n\n req.on('response', (headers) => {\n statusCode = headers[':status'] as number;\n responseHeaders = headers as Record<string, string>;\n });\n\n req.on('data', (chunk) => {\n responseData += chunk;\n });\n\n req.on('end', () => {\n if (timeout) clearTimeout(timeout);\n resolve({\n statusCode,\n headers: responseHeaders,\n body: responseData,\n });\n });\n\n req.on('error', (error) => {\n if (timeout) clearTimeout(timeout);\n reject(error);\n });\n\n req.write(body);\n req.end();\n });\n}\n\nexport class BaseNodeTransport implements BaseTransport {\n constructor(private config: BaseNodeTransportConfig) {}\n\n async post(data: any, endpointPath: string): Promise<any> {\n const maxRetries = this.config.retries || 0;\n let attempt = 0;\n const url = `${this.config.baseUrl}${endpointPath}`;\n\n if (this.config.debug) {\n console.log(`[Base Node Transport] POST request to ${url}`, data);\n }\n\n while (attempt <= maxRetries) {\n try {\n const session = getOrCreateSession(this.config.baseUrl, this.config.debug);\n const body = JSON.stringify(data);\n \n // Add SDK headers\n const headers = {\n 'x-sdk': SDK_NAME,\n 'x-sdk-version': SDK_VERSION,\n ...this.config.headers,\n };\n\n const response = await makeHttp2Request(\n session,\n endpointPath,\n headers,\n body,\n this.config.timeoutMs\n );\n\n if (response.statusCode < 200 || response.statusCode >= 300) {\n const errorMsg = `HTTP ${response.statusCode}: Request failed`;\n if (this.config.debug) {\n console.error(`[Base Node Transport] Request failed:`, errorMsg);\n }\n throw new Error(errorMsg);\n }\n\n const result = JSON.parse(response.body);\n if (this.config.debug) {\n console.log(`[Base Node Transport] Request successful:`, result);\n }\n \n return result;\n } catch (error) {\n attempt++;\n if (this.config.debug) {\n console.error(`[Base Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));\n }\n if (attempt > maxRetries) {\n throw error;\n }\n\n // Exponential backoff\n await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));\n }\n }\n\n // This should never be reached, but TypeScript requires it\n throw new Error('Max retries exceeded');\n }\n}\n\nexport function createBaseNodeTransport(config: BaseNodeTransportConfig): BaseNodeTransport {\n return new BaseNodeTransport(config);\n}\n","import type { Cache } from './types';\n\nexport class LocalCache implements Cache {\n private storage = new Map<string, string>();\n\n get(key: string): string | null {\n return this.storage.get(key) || null;\n }\n\n set(key: string, value: string): void {\n this.storage.set(key, value);\n }\n\n isAvailable(): boolean {\n return true;\n }\n}\n","import type { BelocalEngineOptions, KV, Lang, Transport } from '../types';\nimport { createBatchTransport } from '../../transports/batch';\nimport { createSingleTransport } from '../../transports/single';\nimport { createBaseNodeTransport } from '../../transports/base/node';\nimport { LocalCache } from '../../cache/local';\nimport type { Cache } from '../../cache/types';\nimport { md5 } from 'js-md5';\n\nexport class BelocalEngine {\n private transport: Transport;\n private debug: boolean;\n private cache: Cache;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n batchWindowMs = 50,\n timeoutMs = 10000,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Use local cache for Node.js\n this.cache = new LocalCache();\n \n if (this.debug) {\n console.log('[BeLocal Engine] Using local (memory) cache');\n }\n\n const authHeaders = {\n 'Authorization': `Bearer ${apiKey}`\n };\n\n // Create base node transport\n const baseTransport = createBaseNodeTransport({\n baseUrl,\n headers: authHeaders,\n timeoutMs,\n debug: this.debug\n });\n\n // Create appropriate transport based on batchWindowMs config\n if (batchWindowMs > 0) {\n // Use batch transport with node base transport\n this.transport = createBatchTransport({\n baseTransport,\n debug: this.debug,\n batchWindowMs\n });\n \n if (this.debug) {\n console.log('[BeLocal Engine] Batch transport created with config:', {\n baseUrl,\n timeoutMs,\n batchWindowMs\n });\n }\n } else {\n // Use single transport with node base transport\n this.transport = createSingleTransport({\n baseTransport,\n debug: this.debug\n });\n \n if (this.debug) {\n console.log('[BeLocal Engine] Single transport created with config:', {\n baseUrl,\n timeoutMs\n });\n }\n }\n }\n\n async translate(text: string, lang: Lang, source_lang?: string, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);\n \n // Try to get from cache first\n const cachedResult = this.cache.get(cacheKey);\n if (cachedResult) {\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from local cache:', text);\n }\n return cachedResult;\n }\n\n // Cache miss, get translation from transport\n const result = await this.transport({ text, lang, source_lang, ctx });\n \n // Store in cache only if status is not 'error'\n if (result.status !== 'error') {\n this.cache.set(cacheKey, result.text);\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API, cached in local:', text);\n }\n } else {\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API (not cached due to error status):', text);\n }\n }\n return result.text;\n }\n\n async t(text: string, lang: Lang, source_lang?: string, context?: string): Promise<string> {\n if (context) {\n return this.translate(text, lang, source_lang, {user_ctx: context});\n }\n return this.translate(text, lang, source_lang);\n }\n\n private generateCacheKey(text: string, lang: Lang, source_lang?: string, ctx?: KV): string {\n const sortedCtx = ctx ? Object.keys(ctx)\n .sort()\n .reduce((acc, key) => {\n acc[key] = ctx[key];\n return acc;\n }, {} as KV) : null;\n\n const data = {\n text,\n lang,\n source_lang: source_lang || null,\n ctx: sortedCtx\n };\n return md5(JSON.stringify(data));\n }\n}\n\n// Re-export types and transports\nexport type { BelocalEngineOptions, Lang, KV, BaseTransport } from '../types';\nexport { BaseNodeTransport, createBaseNodeTransport } from '../../transports/base';\nexport { createBatchTransport } from '../../transports/batch';\nexport { createSingleTransport } from '../../transports/single';\n"]}
1
+ {"version":3,"sources":["../src/transports/multi.ts","../src/version.ts","../src/transports/base/node.ts","../src/cache/local.ts","../src/core/engine/node.ts"],"names":["md5","session","URL","http2","headers"],"mappings":"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","file":"node.cjs","sourcesContent":["import type { Transport, BaseTransport } from '../core/types';\nimport { md5 } from 'js-md5';\n\nexport interface MultiTransportConfig {\n baseTransport: BaseTransport;\n debug?: boolean;\n batchWindowMs?: number;\n}\n\ninterface MultiRequest {\n requestId: string;\n texts: string[];\n lang: string;\n sourceLang?: string;\n context?: Record<string, string>;\n}\n\ninterface MultiRequestItem {\n text: string;\n lang: string;\n sourceLang?: string;\n context?: Record<string, string>;\n resolve: (value: { text: string; status: string }) => void;\n reject: (error: Error) => void;\n}\n\ninterface MultiResponse {\n results: Array<{\n requestId: string;\n data: { texts: string[]; status: string };\n }>;\n}\n\ninterface MultiState {\n currentMulti: MultiRequestItem[];\n multiTimer: ReturnType<typeof setTimeout> | null;\n isRequestInFlight: boolean;\n}\n\nfunction generateRequestId(texts: string[], lang: string, sourceLang?: string, context?: Record<string, string>): string {\n // Сортируем тексты (создаем копию, чтобы не изменять оригинал)\n const sortedTexts = [...texts].sort();\n \n // Сортируем ключи контекста (создаем копию, чтобы не изменять оригинал)\n let sortedContext: Record<string, string> | null = null;\n if (context && Object.keys(context).length > 0) {\n sortedContext = {};\n const sortedKeys = Object.keys(context).sort();\n for (const key of sortedKeys) {\n sortedContext[key] = context[key];\n }\n }\n \n // Создаем JSON массив: [sortedTexts, lang, sourceLang, context]\n // В PHP примере: [$sortedTexts, $this->lang, $context] (sourceLang не включен)\n // Но мы включаем sourceLang для правильной группировки запросов с разными sourceLang\n const data = [sortedTexts, lang, sourceLang || null, sortedContext];\n const json = JSON.stringify(data);\n \n return md5(json);\n}\n\nasync function sendMulti(\n config: MultiTransportConfig,\n items: MultiRequestItem[],\n state: MultiState\n): Promise<void> {\n if (config.debug) {\n console.log(`[BeLocal Multi Transport] Sending multi request with ${items.length} texts`);\n }\n\n try {\n // Группируем тексты по параметрам перевода (lang, sourceLang, context)\n const groups = new Map<string, MultiRequestItem[]>();\n \n items.forEach(item => {\n // Используем ключ для группировки без текстов (только параметры перевода)\n const groupKey = JSON.stringify({\n lang: item.lang,\n sourceLang: item.sourceLang || null,\n context: item.context || null\n });\n \n if (!groups.has(groupKey)) {\n groups.set(groupKey, []);\n }\n groups.get(groupKey)!.push(item);\n });\n\n // Создаем запросы для каждой группы и сохраняем соответствие requestId -> groupItems\n const requestIdToGroupItems = new Map<string, MultiRequestItem[]>();\n const requests: MultiRequest[] = Array.from(groups.entries()).map(([groupKey, groupItems]) => {\n const firstItem = groupItems[0];\n const texts = groupItems.map(item => item.text);\n \n // Генерируем requestId включая отсортированные тексты группы\n // Включаем sourceLang для правильной группировки запросов с разными sourceLang\n const requestId = generateRequestId(\n texts,\n firstItem.lang,\n firstItem.sourceLang,\n firstItem.context\n );\n \n // Сохраняем соответствие requestId -> groupItems\n requestIdToGroupItems.set(requestId, groupItems);\n \n return {\n requestId,\n texts,\n lang: firstItem.lang,\n sourceLang: firstItem.sourceLang,\n context: firstItem.context\n };\n });\n\n const multiResponse: MultiResponse = await config.baseTransport.post({ requests }, '/v1/translate/multi');\n \n if (config.debug) {\n console.log(`[BeLocal Multi Transport] Multi response received with ${multiResponse.results.length} groups`);\n }\n\n // Создаем map для быстрого поиска результатов по requestId\n const resultMap = new Map<string, { texts: string[]; status: string }>();\n multiResponse.results.forEach(result => {\n resultMap.set(result.requestId, { texts: result.data.texts, status: result.data.status });\n });\n\n // Раздаем результаты каждому промису\n requestIdToGroupItems.forEach((groupItems, requestId) => {\n const result = resultMap.get(requestId);\n \n if (!result) {\n if (config.debug) {\n console.error(`[BeLocal Multi Transport] No result found for requestId: ${requestId}`);\n }\n groupItems.forEach(item => {\n item.reject(new Error(`No result found for request ${requestId}`));\n });\n return;\n }\n\n // Маппим тексты обратно на промисы по индексу\n if (result.texts.length !== groupItems.length) {\n const error = new Error(`Mismatch: expected ${groupItems.length} texts, got ${result.texts.length} for requestId ${requestId}`);\n if (config.debug) {\n console.error(`[BeLocal Multi Transport]`, error.message);\n }\n groupItems.forEach(item => item.reject(error));\n return;\n }\n\n groupItems.forEach((item, index) => {\n const translatedText = result.texts[index];\n const status = result.status || 'success';\n \n if (config.debug) {\n console.log(`[BeLocal Multi Transport] Success for requestId ${requestId}[${index}]: \"${translatedText}\"`);\n }\n \n item.resolve({ text: translatedText, status });\n });\n });\n\n } catch (error) {\n if (config.debug) {\n console.error(`[BeLocal Multi Transport] Multi request error:`, error);\n }\n \n // При ошибке сети отклоняем все промисы\n const errorToReject = error instanceof Error ? error : new Error(String(error));\n items.forEach(item => item.reject(errorToReject));\n } finally {\n // Cleanup handled by base transport\n }\n}\n\nfunction processMulti(config: MultiTransportConfig, state: MultiState): void {\n if (state.currentMulti.length === 0 || state.isRequestInFlight) {\n return;\n }\n\n const itemsToSend = [...state.currentMulti];\n state.currentMulti = [];\n state.multiTimer = null;\n state.isRequestInFlight = true;\n\n sendMulti(config, itemsToSend, state).finally(() => {\n state.isRequestInFlight = false;\n \n if (state.currentMulti.length > 0) {\n const windowMs = config.batchWindowMs ?? 50;\n state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);\n }\n });\n}\n\nexport function createMultiTransport(config: MultiTransportConfig): Transport {\n const windowMs = config.batchWindowMs ?? 50;\n\n const state: MultiState = {\n currentMulti: [],\n multiTimer: null,\n isRequestInFlight: false,\n };\n \n return ({ text, lang, source_lang, ctx }) => {\n return new Promise<{ text: string; status: string }>((resolve, reject) => {\n if (config.debug) {\n // Для отладки показываем временный requestId (будет пересчитан при группировке)\n const tempRequestId = md5(JSON.stringify([text, lang, source_lang || null, ctx || null]));\n console.log(`[BeLocal Multi Transport] Queuing request ${tempRequestId}: \"${text}\" to ${lang}`);\n }\n\n const requestItem: MultiRequestItem = {\n text,\n lang,\n sourceLang: source_lang,\n context: ctx,\n resolve,\n reject,\n };\n\n state.currentMulti.push(requestItem);\n\n if (state.multiTimer === null && !state.isRequestInFlight) {\n state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);\n }\n });\n };\n}\n\n","// SDK version - will be replaced during build with tsup define\ndeclare const __SDK_VERSION__: string | undefined;\n\n// Safely check if __SDK_VERSION__ is defined (replaced during build)\nexport const SDK_VERSION: string = \n (() => { try { return typeof __SDK_VERSION__ !== 'undefined' ? __SDK_VERSION__ : 'undefined'; } catch { return 'undefined'; } })();\n\nexport const SDK_NAME = 'js';\n\n","import * as http2 from 'node:http2';\nimport { URL } from 'node:url';\nimport type { BaseTransport } from '../../core/types';\nimport { SDK_NAME, SDK_VERSION } from '../../version';\n\nexport interface BaseNodeTransportConfig {\n baseUrl: string;\n headers?: Record<string, string>;\n timeoutMs?: number;\n retries?: number;\n debug?: boolean;\n}\n\n// Global session cache for HTTP/2 connections\nconst sessionCache = new Map<string, http2.ClientHttp2Session>();\n\nfunction getOrCreateSession(baseUrl: string, debug?: boolean): http2.ClientHttp2Session {\n if (sessionCache.has(baseUrl)) {\n const session = sessionCache.get(baseUrl)!;\n if (!session.destroyed) {\n return session;\n }\n sessionCache.delete(baseUrl);\n }\n\n const parsedUrl = new URL(baseUrl);\n const session = http2.connect(parsedUrl.origin);\n\n session.socket?.unref();\n \n // Set up session cleanup\n session.on('error', () => {\n sessionCache.delete(baseUrl);\n });\n \n session.on('close', () => {\n sessionCache.delete(baseUrl);\n });\n\n // Add debug logging if enabled\n if (debug) {\n session.on('connect', () => console.log('[Base Node Transport H2] new session connected'));\n session.on('goaway', (code, lastStreamID, opaque) =>\n console.log('[Base Node Transport H2] goaway', code, lastStreamID)\n );\n }\n \n sessionCache.set(baseUrl, session);\n return session;\n}\n\nfunction makeHttp2Request(\n session: http2.ClientHttp2Session,\n path: string,\n headers: Record<string, string>,\n body: string,\n timeoutMs?: number\n): Promise<{ statusCode: number; headers: Record<string, string>; body: string }> {\n return new Promise((resolve, reject) => {\n const req = session.request({\n ':method': 'POST',\n ':path': path,\n 'content-type': 'application/json',\n 'content-length': Buffer.byteLength(body),\n ...headers,\n });\n\n let timeout: NodeJS.Timeout | null = null;\n if (timeoutMs) {\n timeout = setTimeout(() => {\n req.destroy();\n reject(new Error(`Request timeout after ${timeoutMs}ms`));\n }, timeoutMs);\n }\n\n let responseData = '';\n let statusCode = 0;\n let responseHeaders: Record<string, string> = {};\n\n req.on('response', (headers) => {\n statusCode = headers[':status'] as number;\n responseHeaders = headers as Record<string, string>;\n });\n\n req.on('data', (chunk) => {\n responseData += chunk;\n });\n\n req.on('end', () => {\n if (timeout) clearTimeout(timeout);\n resolve({\n statusCode,\n headers: responseHeaders,\n body: responseData,\n });\n });\n\n req.on('error', (error) => {\n if (timeout) clearTimeout(timeout);\n reject(error);\n });\n\n req.write(body);\n req.end();\n });\n}\n\nexport class BaseNodeTransport implements BaseTransport {\n constructor(private config: BaseNodeTransportConfig) {}\n\n async post(data: any, endpointPath: string): Promise<any> {\n const maxRetries = this.config.retries || 0;\n let attempt = 0;\n const url = `${this.config.baseUrl}${endpointPath}`;\n\n if (this.config.debug) {\n console.log(`[Base Node Transport] POST request to ${url}`, data);\n }\n\n while (attempt <= maxRetries) {\n try {\n const session = getOrCreateSession(this.config.baseUrl, this.config.debug);\n const body = JSON.stringify(data);\n \n // Add SDK headers\n const headers = {\n 'x-sdk': SDK_NAME,\n 'x-sdk-version': SDK_VERSION,\n ...this.config.headers,\n };\n\n const response = await makeHttp2Request(\n session,\n endpointPath,\n headers,\n body,\n this.config.timeoutMs\n );\n\n if (response.statusCode < 200 || response.statusCode >= 300) {\n const errorMsg = `HTTP ${response.statusCode}: Request failed`;\n if (this.config.debug) {\n console.error(`[Base Node Transport] Request failed:`, errorMsg);\n }\n throw new Error(errorMsg);\n }\n\n const result = JSON.parse(response.body);\n if (this.config.debug) {\n console.log(`[Base Node Transport] Request successful:`, result);\n }\n \n return result;\n } catch (error) {\n attempt++;\n if (this.config.debug) {\n console.error(`[Base Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));\n }\n if (attempt > maxRetries) {\n throw error;\n }\n\n // Exponential backoff\n await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));\n }\n }\n\n // This should never be reached, but TypeScript requires it\n throw new Error('Max retries exceeded');\n }\n}\n\nexport function createBaseNodeTransport(config: BaseNodeTransportConfig): BaseNodeTransport {\n return new BaseNodeTransport(config);\n}\n","import type { Cache } from './types';\n\nexport class LocalCache implements Cache {\n private storage = new Map<string, string>();\n\n get(key: string): string | null {\n return this.storage.get(key) || null;\n }\n\n set(key: string, value: string): void {\n this.storage.set(key, value);\n }\n\n isAvailable(): boolean {\n return true;\n }\n}\n","import type { BelocalEngineOptions, KV, Lang, Transport } from '../types';\nimport { createMultiTransport } from '../../transports/multi';\nimport { createBaseNodeTransport } from '../../transports/base/node';\nimport { LocalCache } from '../../cache/local';\nimport type { Cache } from '../../cache/types';\nimport { md5 } from 'js-md5';\n\nexport class BelocalEngine {\n private transport: Transport;\n private debug: boolean;\n private cache: Cache;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n batchWindowMs = 50,\n timeoutMs = 10000,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Use local cache for Node.js\n this.cache = new LocalCache();\n \n if (this.debug) {\n console.log('[BeLocal Engine] Using local (memory) cache');\n }\n\n const authHeaders = {\n 'Authorization': `Bearer ${apiKey}`\n };\n\n // Create base node transport\n const baseTransport = createBaseNodeTransport({\n baseUrl,\n headers: authHeaders,\n timeoutMs,\n debug: this.debug\n });\n\n // Always use multi transport\n this.transport = createMultiTransport({\n baseTransport,\n debug: this.debug,\n batchWindowMs\n });\n \n if (this.debug) {\n console.log('[BeLocal Engine] Multi transport created with config:', {\n baseUrl,\n timeoutMs,\n batchWindowMs\n });\n }\n }\n\n async translate(text: string, lang: Lang, source_lang?: string, ctx?: KV): Promise<string> {\n const results = await this.translateMany([text], lang, source_lang, ctx);\n return results[0];\n }\n\n async translateMany(texts: string[], lang: Lang, source_lang?: string, ctx?: KV): Promise<string[]> {\n const results: (string | null)[] = new Array(texts.length);\n const cacheMisses: Array<{ index: number; text: string }> = [];\n\n for (let i = 0; i < texts.length; i++) {\n const text = texts[i];\n const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);\n \n const cachedResult = this.cache.get(cacheKey);\n if (cachedResult) {\n results[i] = cachedResult;\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from local cache:', text);\n }\n continue;\n }\n \n results[i] = null;\n cacheMisses.push({ index: i, text });\n }\n\n if (cacheMisses.length > 0) {\n const translations = await Promise.all(\n cacheMisses.map(async ({ index, text }) => {\n const result = await this.transport({ text, lang, source_lang, ctx });\n \n if (result.status !== 'error') {\n const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);\n this.cache.set(cacheKey, result.text);\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API, cached in local:', text);\n }\n } else {\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API (not cached due to error status):', text);\n }\n }\n \n return { index, translation: result.text };\n })\n );\n\n translations.forEach(({ index, translation }) => {\n results[index] = translation;\n });\n }\n\n return results as string[];\n }\n\n async t(text: string, lang: Lang, source_lang?: string, context?: string): Promise<string> {\n if (context) {\n return this.translate(text, lang, source_lang, {user_ctx: context});\n }\n return this.translate(text, lang, source_lang);\n }\n\n private generateCacheKey(text: string, lang: Lang, source_lang?: string, ctx?: KV): string {\n const sortedCtx = ctx ? Object.keys(ctx)\n .sort()\n .reduce((acc, key) => {\n acc[key] = ctx[key];\n return acc;\n }, {} as KV) : null;\n\n const data = {\n text,\n lang,\n source_lang: source_lang || null,\n ctx: sortedCtx\n };\n return md5(JSON.stringify(data));\n }\n}\n\n// Re-export types and transports\nexport type { BelocalEngineOptions, Lang, KV, BaseTransport } from '../types';\nexport { BaseNodeTransport, createBaseNodeTransport } from '../../transports/base';\nexport { createMultiTransport } from '../../transports/multi';\n"]}
package/dist/node.d.ts CHANGED
@@ -34,18 +34,12 @@ declare class BaseNodeTransport implements BaseTransport {
34
34
  }
35
35
  declare function createBaseNodeTransport(config: BaseNodeTransportConfig): BaseNodeTransport;
36
36
 
37
- interface BatchTransportConfig {
37
+ interface MultiTransportConfig {
38
38
  baseTransport: BaseTransport;
39
39
  debug?: boolean;
40
40
  batchWindowMs?: number;
41
41
  }
42
- declare function createBatchTransport(config: BatchTransportConfig): Transport;
43
-
44
- interface SingleTransportConfig {
45
- baseTransport: BaseTransport;
46
- debug?: boolean;
47
- }
48
- declare function createSingleTransport(config: SingleTransportConfig): Transport;
42
+ declare function createMultiTransport(config: MultiTransportConfig): Transport;
49
43
 
50
44
  declare class BelocalEngine {
51
45
  private transport;
@@ -53,8 +47,9 @@ declare class BelocalEngine {
53
47
  private cache;
54
48
  constructor(options: BelocalEngineOptions);
55
49
  translate(text: string, lang: Lang, source_lang?: string, ctx?: KV): Promise<string>;
50
+ translateMany(texts: string[], lang: Lang, source_lang?: string, ctx?: KV): Promise<string[]>;
56
51
  t(text: string, lang: Lang, source_lang?: string, context?: string): Promise<string>;
57
52
  private generateCacheKey;
58
53
  }
59
54
 
60
- export { BaseNodeTransport, type BaseTransport, BelocalEngine, type BelocalEngineOptions, type KV, type Lang, createBaseNodeTransport, createBatchTransport, createSingleTransport };
55
+ export { BaseNodeTransport, type BaseTransport, BelocalEngine, type BelocalEngineOptions, type KV, type Lang, createBaseNodeTransport, createMultiTransport };