@belocal/js-sdk 0.7.0 → 1.0.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.d.ts CHANGED
@@ -46,63 +46,14 @@ interface BelocalEngineOptions {
46
46
  debug?: boolean;
47
47
  }
48
48
 
49
- interface BaseNodeTransportConfig {
50
- headers?: Record<string, string>;
51
- timeoutMs?: number;
52
- retries?: number;
53
- debug?: boolean;
54
- }
55
- declare class BaseNodeTransport implements BaseTransport {
56
- private config;
57
- constructor(config: BaseNodeTransportConfig);
58
- post(data: any, endpointPath: string): Promise<any>;
59
- }
60
- declare function createBaseNodeTransport(config: BaseNodeTransportConfig): BaseTransport;
61
-
62
- interface MultiTransportConfig {
63
- baseTransport: BaseTransport;
64
- debug?: boolean;
65
- batchWindowMs?: number;
66
- }
67
- declare function createMultiTransport(config: MultiTransportConfig): Transport;
68
-
69
49
  /**
70
- * BeLocal translation engine for Node.js environments.
71
- *
72
- * Provides on-demand translation with automatic request batching, caching, and deduplication.
73
- * Optimized for Node.js environments using HTTP/2 with connection pooling and automatic retries.
74
- *
75
- * @example
76
- * ```typescript
77
- * const engine = new BelocalEngine({
78
- * apiKey: 'your-api-key',
79
- * debug: true
80
- * });
81
- *
82
- * const translated = await engine.translate('Hello world', 'es');
83
- * ```
50
+ * Base engine implementation shared between browser and Node.js environments.
84
51
  */
85
- declare class BelocalEngine {
52
+ declare class BelocalEngine$1 {
86
53
  private transport;
87
54
  private debug;
88
55
  private cache;
89
- /**
90
- * Creates a new BelocalEngine instance.
91
- *
92
- * @param options - Configuration options for the engine
93
- * @throws {Error} If apiKey is not provided or invalid
94
- *
95
- * @example
96
- * ```typescript
97
- * const engine = new BelocalEngine({
98
- * apiKey: 'your-api-key',
99
- * batchWindowMs: 100,
100
- * timeoutMs: 10000,
101
- * debug: false
102
- * });
103
- * ```
104
- */
105
- constructor(options: BelocalEngineOptions);
56
+ constructor(options: BelocalEngineOptions, baseTransportFactory: (opts: any) => BaseTransport);
106
57
  /**
107
58
  * Translates a single text string to the target language.
108
59
  *
@@ -112,7 +63,7 @@ declare class BelocalEngine {
112
63
  * @param text - The text to translate
113
64
  * @param lang - Target language code (e.g., 'es', 'fr', 'ru')
114
65
  * @param source_lang - Optional source language code. If not provided, auto-detection is used
115
- * @param ctx - Optional key-value pairs for translation context. Supported keys: `user_ctx` (string - descriptive context in English), `cache_type` ('managed' | string)
66
+ * @param ctx - Optional key-value pairs for translation context. Supported keys: `user_ctx` (string - descriptive context), `cache_type` ('managed')
116
67
  * @returns Promise resolving to the translated text
117
68
  * @throws {Error} If the translation request fails (network error, API error, timeout)
118
69
  *
@@ -218,4 +169,60 @@ declare class BelocalEngine {
218
169
  private generateCacheKey;
219
170
  }
220
171
 
172
+ interface BaseNodeTransportConfig {
173
+ headers?: Record<string, string>;
174
+ timeoutMs?: number;
175
+ retries?: number;
176
+ debug?: boolean;
177
+ }
178
+ declare class BaseNodeTransport implements BaseTransport {
179
+ private config;
180
+ constructor(config: BaseNodeTransportConfig);
181
+ post(data: any, endpointPath: string): Promise<any>;
182
+ }
183
+ declare function createBaseNodeTransport(config: BaseNodeTransportConfig): BaseTransport;
184
+
185
+ interface MultiTransportConfig {
186
+ baseTransport: BaseTransport;
187
+ debug?: boolean;
188
+ batchWindowMs?: number;
189
+ }
190
+ declare function createMultiTransport(config: MultiTransportConfig): Transport;
191
+
192
+ /**
193
+ * BeLocal translation engine for Node.js environments.
194
+ *
195
+ * Provides on-demand translation with automatic request batching, caching, and deduplication.
196
+ * Optimized for Node.js environments using HTTP/2 with connection pooling and automatic retries.
197
+ *
198
+ * @example
199
+ * ```typescript
200
+ * const engine = new BelocalEngine({
201
+ * apiKey: 'your-api-key',
202
+ * debug: true
203
+ * });
204
+ *
205
+ * const translated = await engine.translate('Hello world', 'es');
206
+ * ```
207
+ */
208
+ declare class BelocalEngine extends BelocalEngine$1 {
209
+ /**
210
+ * Creates a new BelocalEngine instance for Node.js environments.
211
+ *
212
+ * @param options - Configuration options for the engine
213
+ * @throws {Error} If apiKey is not provided or invalid
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * const engine = new BelocalEngine({
218
+ * apiKey: 'your-api-key',
219
+ * batchWindowMs: 100,
220
+ * timeoutMs: 10000,
221
+ * debug: false
222
+ * });
223
+ * ```
224
+ */
225
+ constructor(options: BelocalEngineOptions);
226
+ }
227
+
221
228
  export { BaseNodeTransport, type BaseTransport, BelocalEngine, type BelocalEngineOptions, type KV, type Lang, createBaseNodeTransport, createMultiTransport };
package/dist/node.mjs CHANGED
@@ -1,152 +1,13 @@
1
- import { md5 } from 'js-md5';
2
1
  import * as http2 from 'http2';
3
2
  import { URL } from 'url';
3
+ import { md5 } from 'js-md5';
4
4
 
5
- // src/transports/multi.ts
6
- function generateRequestId(texts, lang, sourceLang, context) {
7
- const sortedTexts = [...texts].sort();
8
- let sortedContext = null;
9
- if (context && Object.keys(context).length > 0) {
10
- sortedContext = {};
11
- const sortedKeys = Object.keys(context).sort();
12
- for (const key of sortedKeys) {
13
- sortedContext[key] = context[key];
14
- }
15
- }
16
- const data = [sortedTexts, lang, sourceLang || null, sortedContext];
17
- const json = JSON.stringify(data);
18
- return md5(json);
19
- }
20
- async function sendMulti(config, items, state) {
21
- if (config.debug) {
22
- console.log(`[BeLocal Multi Transport] Sending multi request with ${items.length} texts`);
23
- }
24
- try {
25
- const groups = /* @__PURE__ */ new Map();
26
- items.forEach((item) => {
27
- const groupKey = JSON.stringify({
28
- lang: item.lang,
29
- sourceLang: item.sourceLang || null,
30
- context: item.context || null
31
- });
32
- if (!groups.has(groupKey)) {
33
- groups.set(groupKey, []);
34
- }
35
- groups.get(groupKey).push(item);
36
- });
37
- const requestIdToGroupItems = /* @__PURE__ */ new Map();
38
- const requests = Array.from(groups.entries()).map(([groupKey, groupItems]) => {
39
- const firstItem = groupItems[0];
40
- const texts = groupItems.map((item) => item.text);
41
- const requestId = generateRequestId(
42
- texts,
43
- firstItem.lang,
44
- firstItem.sourceLang,
45
- firstItem.context
46
- );
47
- requestIdToGroupItems.set(requestId, groupItems);
48
- return {
49
- requestId,
50
- texts,
51
- lang: firstItem.lang,
52
- sourceLang: firstItem.sourceLang,
53
- context: firstItem.context
54
- };
55
- });
56
- const multiResponse = await config.baseTransport.post({ requests }, "/v1/translate/multi");
57
- if (config.debug) {
58
- console.log(`[BeLocal Multi Transport] Multi response received with ${multiResponse.results.length} groups`);
59
- }
60
- const resultMap = /* @__PURE__ */ new Map();
61
- multiResponse.results.forEach((result) => {
62
- resultMap.set(result.requestId, { texts: result.data.texts, status: result.data.status });
63
- });
64
- requestIdToGroupItems.forEach((groupItems, requestId) => {
65
- const result = resultMap.get(requestId);
66
- if (!result) {
67
- if (config.debug) {
68
- console.error(`[BeLocal Multi Transport] No result found for requestId: ${requestId}`);
69
- }
70
- groupItems.forEach((item) => {
71
- item.reject(new Error(`No result found for request ${requestId}`));
72
- });
73
- return;
74
- }
75
- if (result.texts.length !== groupItems.length) {
76
- const error = new Error(`Mismatch: expected ${groupItems.length} texts, got ${result.texts.length} for requestId ${requestId}`);
77
- if (config.debug) {
78
- console.error(`[BeLocal Multi Transport]`, error.message);
79
- }
80
- groupItems.forEach((item) => item.reject(error));
81
- return;
82
- }
83
- groupItems.forEach((item, index) => {
84
- const translatedText = result.texts[index];
85
- const status = result.status || "success";
86
- if (config.debug) {
87
- console.log(`[BeLocal Multi Transport] Success for requestId ${requestId}[${index}]: "${translatedText}"`);
88
- }
89
- item.resolve({ text: translatedText, status });
90
- });
91
- });
92
- } catch (error) {
93
- if (config.debug) {
94
- console.error(`[BeLocal Multi Transport] Multi request error:`, error);
95
- }
96
- const errorToReject = error instanceof Error ? error : new Error(String(error));
97
- items.forEach((item) => item.reject(errorToReject));
98
- } finally {
99
- }
100
- }
101
- function processMulti(config, state) {
102
- if (state.currentMulti.length === 0 || state.isRequestInFlight) {
103
- return;
104
- }
105
- const itemsToSend = [...state.currentMulti];
106
- state.currentMulti = [];
107
- state.multiTimer = null;
108
- state.isRequestInFlight = true;
109
- sendMulti(config, itemsToSend).finally(() => {
110
- state.isRequestInFlight = false;
111
- if (state.currentMulti.length > 0) {
112
- const windowMs = config.batchWindowMs ?? 50;
113
- state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
114
- }
115
- });
116
- }
117
- function createMultiTransport(config) {
118
- const windowMs = config.batchWindowMs ?? 50;
119
- const state = {
120
- currentMulti: [],
121
- multiTimer: null,
122
- isRequestInFlight: false
123
- };
124
- return ({ text, lang, source_lang, ctx }) => {
125
- return new Promise((resolve, reject) => {
126
- if (config.debug) {
127
- const tempRequestId = md5(JSON.stringify([text, lang, source_lang || null, ctx || null]));
128
- console.log(`[BeLocal Multi Transport] Queuing request ${tempRequestId}: "${text}" to ${lang}`);
129
- }
130
- const requestItem = {
131
- text,
132
- lang,
133
- sourceLang: source_lang,
134
- context: ctx,
135
- resolve,
136
- reject
137
- };
138
- state.currentMulti.push(requestItem);
139
- if (state.multiTimer === null && !state.isRequestInFlight) {
140
- state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
141
- }
142
- });
143
- };
144
- }
5
+ // src/transports/base/node.ts
145
6
 
146
7
  // src/version.ts
147
8
  var SDK_VERSION = (() => {
148
9
  try {
149
- return true ? "0.7.0" : "undefined";
10
+ return true ? "1.0.0" : "undefined";
150
11
  } catch {
151
12
  return "undefined";
152
13
  }
@@ -351,6 +212,145 @@ function createBaseNodeTransport(config) {
351
212
  const transport = new BaseNodeTransport(config);
352
213
  return new DedupeTransport(transport, config.debug);
353
214
  }
215
+ function generateRequestId(texts, lang, sourceLang, context) {
216
+ const sortedTexts = [...texts].sort();
217
+ let sortedContext = null;
218
+ if (context && Object.keys(context).length > 0) {
219
+ sortedContext = {};
220
+ const sortedKeys = Object.keys(context).sort();
221
+ for (const key of sortedKeys) {
222
+ sortedContext[key] = context[key];
223
+ }
224
+ }
225
+ const data = [sortedTexts, lang, sourceLang || null, sortedContext];
226
+ const json = JSON.stringify(data);
227
+ return md5(json);
228
+ }
229
+ async function sendMulti(config, items, state) {
230
+ if (config.debug) {
231
+ console.log(`[BeLocal Multi Transport] Sending multi request with ${items.length} texts`);
232
+ }
233
+ try {
234
+ const groups = /* @__PURE__ */ new Map();
235
+ items.forEach((item) => {
236
+ const groupKey = JSON.stringify({
237
+ lang: item.lang,
238
+ sourceLang: item.sourceLang || null,
239
+ context: item.context || null
240
+ });
241
+ if (!groups.has(groupKey)) {
242
+ groups.set(groupKey, []);
243
+ }
244
+ groups.get(groupKey).push(item);
245
+ });
246
+ const requestIdToGroupItems = /* @__PURE__ */ new Map();
247
+ const requests = Array.from(groups.entries()).map(([groupKey, groupItems]) => {
248
+ const firstItem = groupItems[0];
249
+ const texts = groupItems.map((item) => item.text);
250
+ const requestId = generateRequestId(
251
+ texts,
252
+ firstItem.lang,
253
+ firstItem.sourceLang,
254
+ firstItem.context
255
+ );
256
+ requestIdToGroupItems.set(requestId, groupItems);
257
+ return {
258
+ request_id: requestId,
259
+ texts,
260
+ lang: firstItem.lang,
261
+ source_lang: firstItem.sourceLang,
262
+ ctx: firstItem.context
263
+ };
264
+ });
265
+ const multiResponse = await config.baseTransport.post({ requests }, "/v1/translate/multi");
266
+ if (config.debug) {
267
+ console.log(`[BeLocal Multi Transport] Multi response received with ${multiResponse.results.length} groups`);
268
+ }
269
+ const resultMap = /* @__PURE__ */ new Map();
270
+ multiResponse.results.forEach((result) => {
271
+ resultMap.set(result.request_id, { texts: result.data.texts, status: result.data.status });
272
+ });
273
+ requestIdToGroupItems.forEach((groupItems, requestId) => {
274
+ const result = resultMap.get(requestId);
275
+ if (!result) {
276
+ if (config.debug) {
277
+ console.error(`[BeLocal Multi Transport] No result found for request_id: ${requestId}`);
278
+ }
279
+ groupItems.forEach((item) => {
280
+ item.reject(new Error(`No result found for request ${requestId}`));
281
+ });
282
+ return;
283
+ }
284
+ if (result.texts.length !== groupItems.length) {
285
+ const error = new Error(`Mismatch: expected ${groupItems.length} texts, got ${result.texts.length} for request_id ${requestId}`);
286
+ if (config.debug) {
287
+ console.error(`[BeLocal Multi Transport]`, error.message);
288
+ }
289
+ groupItems.forEach((item) => item.reject(error));
290
+ return;
291
+ }
292
+ groupItems.forEach((item, index) => {
293
+ const translatedText = result.texts[index];
294
+ const status = result.status || "success";
295
+ if (config.debug) {
296
+ console.log(`[BeLocal Multi Transport] Success for request_id ${requestId}[${index}]: "${translatedText}"`);
297
+ }
298
+ item.resolve({ text: translatedText, status });
299
+ });
300
+ });
301
+ } catch (error) {
302
+ if (config.debug) {
303
+ console.error(`[BeLocal Multi Transport] Multi request error:`, error);
304
+ }
305
+ const errorToReject = error instanceof Error ? error : new Error(String(error));
306
+ items.forEach((item) => item.reject(errorToReject));
307
+ } finally {
308
+ }
309
+ }
310
+ function processMulti(config, state) {
311
+ if (state.currentMulti.length === 0 || state.isRequestInFlight) {
312
+ return;
313
+ }
314
+ const itemsToSend = [...state.currentMulti];
315
+ state.currentMulti = [];
316
+ state.multiTimer = null;
317
+ state.isRequestInFlight = true;
318
+ sendMulti(config, itemsToSend).finally(() => {
319
+ state.isRequestInFlight = false;
320
+ if (state.currentMulti.length > 0) {
321
+ const windowMs = config.batchWindowMs ?? 50;
322
+ state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
323
+ }
324
+ });
325
+ }
326
+ function createMultiTransport(config) {
327
+ const windowMs = config.batchWindowMs ?? 50;
328
+ const state = {
329
+ currentMulti: [],
330
+ multiTimer: null,
331
+ isRequestInFlight: false
332
+ };
333
+ return ({ text, lang, source_lang, ctx }) => {
334
+ return new Promise((resolve, reject) => {
335
+ if (config.debug) {
336
+ const tempRequestId = md5(JSON.stringify([text, lang, source_lang || null, ctx || null]));
337
+ console.log(`[BeLocal Multi Transport] Queuing request ${tempRequestId}: "${text}" to ${lang}`);
338
+ }
339
+ const requestItem = {
340
+ text,
341
+ lang,
342
+ sourceLang: source_lang,
343
+ context: ctx,
344
+ resolve,
345
+ reject
346
+ };
347
+ state.currentMulti.push(requestItem);
348
+ if (state.multiTimer === null && !state.isRequestInFlight) {
349
+ state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
350
+ }
351
+ });
352
+ };
353
+ }
354
354
 
355
355
  // src/cache/local.ts
356
356
  var LocalCache = class {
@@ -368,23 +368,7 @@ var LocalCache = class {
368
368
  }
369
369
  };
370
370
  var BelocalEngine = class {
371
- /**
372
- * Creates a new BelocalEngine instance.
373
- *
374
- * @param options - Configuration options for the engine
375
- * @throws {Error} If apiKey is not provided or invalid
376
- *
377
- * @example
378
- * ```typescript
379
- * const engine = new BelocalEngine({
380
- * apiKey: 'your-api-key',
381
- * batchWindowMs: 100,
382
- * timeoutMs: 10000,
383
- * debug: false
384
- * });
385
- * ```
386
- */
387
- constructor(options) {
371
+ constructor(options, baseTransportFactory) {
388
372
  const {
389
373
  apiKey,
390
374
  batchWindowMs = 50,
@@ -393,13 +377,10 @@ var BelocalEngine = class {
393
377
  } = options;
394
378
  this.debug = debug;
395
379
  this.cache = new LocalCache();
396
- if (this.debug) {
397
- console.log("[BeLocal Engine] Using local (memory) cache");
398
- }
399
380
  const authHeaders = {
400
381
  "Authorization": `Bearer ${apiKey}`
401
382
  };
402
- const baseTransport = createBaseNodeTransport({
383
+ const baseTransport = baseTransportFactory({
403
384
  headers: authHeaders,
404
385
  timeoutMs,
405
386
  debug: this.debug
@@ -426,7 +407,7 @@ var BelocalEngine = class {
426
407
  * @param text - The text to translate
427
408
  * @param lang - Target language code (e.g., 'es', 'fr', 'ru')
428
409
  * @param source_lang - Optional source language code. If not provided, auto-detection is used
429
- * @param ctx - Optional key-value pairs for translation context. Supported keys: `user_ctx` (string - descriptive context in English), `cache_type` ('managed' | string)
410
+ * @param ctx - Optional key-value pairs for translation context. Supported keys: `user_ctx` (string - descriptive context), `cache_type` ('managed')
430
411
  * @returns Promise resolving to the translated text
431
412
  * @throws {Error} If the translation request fails (network error, API error, timeout)
432
413
  *
@@ -512,7 +493,7 @@ var BelocalEngine = class {
512
493
  if (cachedResult) {
513
494
  results[i] = cachedResult;
514
495
  if (this.debug) {
515
- console.log("[BeLocal Engine] Translation from local cache:", text);
496
+ console.log("[BeLocal Engine] Translation from cache:", text);
516
497
  }
517
498
  continue;
518
499
  }
@@ -527,7 +508,7 @@ var BelocalEngine = class {
527
508
  const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);
528
509
  this.cache.set(cacheKey, result.text);
529
510
  if (this.debug) {
530
- console.log("[BeLocal Engine] Translation from API, cached in local:", text);
511
+ console.log("[BeLocal Engine] Translation from API, cached:", text);
531
512
  }
532
513
  } else {
533
514
  if (this.debug) {
@@ -592,6 +573,29 @@ var BelocalEngine = class {
592
573
  }
593
574
  };
594
575
 
595
- export { BaseNodeTransport, BelocalEngine, createBaseNodeTransport, createMultiTransport };
576
+ // src/core/engine/node.ts
577
+ var BelocalEngine2 = class extends BelocalEngine {
578
+ /**
579
+ * Creates a new BelocalEngine instance for Node.js environments.
580
+ *
581
+ * @param options - Configuration options for the engine
582
+ * @throws {Error} If apiKey is not provided or invalid
583
+ *
584
+ * @example
585
+ * ```typescript
586
+ * const engine = new BelocalEngine({
587
+ * apiKey: 'your-api-key',
588
+ * batchWindowMs: 100,
589
+ * timeoutMs: 10000,
590
+ * debug: false
591
+ * });
592
+ * ```
593
+ */
594
+ constructor(options) {
595
+ super(options, createBaseNodeTransport);
596
+ }
597
+ };
598
+
599
+ export { BaseNodeTransport, BelocalEngine2 as BelocalEngine, createBaseNodeTransport, createMultiTransport };
596
600
  //# sourceMappingURL=node.mjs.map
597
601
  //# sourceMappingURL=node.mjs.map