@belocal/js-sdk 0.7.0 → 1.0.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/node.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var jsMd5 = require('js-md5');
4
3
  var http2 = require('http2');
5
4
  var url = require('url');
5
+ var jsMd5 = require('js-md5');
6
6
 
7
7
  function _interopNamespace(e) {
8
8
  if (e && e.__esModule) return e;
@@ -24,155 +24,10 @@ function _interopNamespace(e) {
24
24
 
25
25
  var http2__namespace = /*#__PURE__*/_interopNamespace(http2);
26
26
 
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);
41
- }
42
- async function sendMulti(config, items, state) {
43
- if (config.debug) {
44
- console.log(`[BeLocal Multi Transport] Sending multi request with ${items.length} texts`);
45
- }
46
- try {
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");
79
- if (config.debug) {
80
- console.log(`[BeLocal Multi Transport] Multi response received with ${multiResponse.results.length} groups`);
81
- }
82
- const resultMap = /* @__PURE__ */ new Map();
83
- multiResponse.results.forEach((result) => {
84
- resultMap.set(result.requestId, { texts: result.data.texts, status: result.data.status });
85
- });
86
- requestIdToGroupItems.forEach((groupItems, requestId) => {
87
- const result = resultMap.get(requestId);
88
- if (!result) {
89
- if (config.debug) {
90
- console.error(`[BeLocal Multi Transport] No result found for requestId: ${requestId}`);
91
- }
92
- groupItems.forEach((item) => {
93
- item.reject(new Error(`No result found for request ${requestId}`));
94
- });
95
- return;
96
- }
97
- if (result.texts.length !== groupItems.length) {
98
- const error = new Error(`Mismatch: expected ${groupItems.length} texts, got ${result.texts.length} for requestId ${requestId}`);
99
- if (config.debug) {
100
- console.error(`[BeLocal Multi Transport]`, error.message);
101
- }
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";
108
- if (config.debug) {
109
- console.log(`[BeLocal Multi Transport] Success for requestId ${requestId}[${index}]: "${translatedText}"`);
110
- }
111
- item.resolve({ text: translatedText, status });
112
- });
113
- });
114
- } catch (error) {
115
- if (config.debug) {
116
- console.error(`[BeLocal Multi Transport] Multi request error:`, error);
117
- }
118
- const errorToReject = error instanceof Error ? error : new Error(String(error));
119
- items.forEach((item) => item.reject(errorToReject));
120
- } finally {
121
- }
122
- }
123
- function processMulti(config, state) {
124
- if (state.currentMulti.length === 0 || state.isRequestInFlight) {
125
- return;
126
- }
127
- const itemsToSend = [...state.currentMulti];
128
- state.currentMulti = [];
129
- state.multiTimer = null;
130
- state.isRequestInFlight = true;
131
- sendMulti(config, itemsToSend).finally(() => {
132
- state.isRequestInFlight = false;
133
- if (state.currentMulti.length > 0) {
134
- const windowMs = config.batchWindowMs ?? 50;
135
- state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
136
- }
137
- });
138
- }
139
- function createMultiTransport(config) {
140
- const windowMs = config.batchWindowMs ?? 50;
141
- const state = {
142
- currentMulti: [],
143
- multiTimer: null,
144
- isRequestInFlight: false
145
- };
146
- return ({ text, lang, source_lang, ctx }) => {
147
- return new Promise((resolve, reject) => {
148
- if (config.debug) {
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}`);
151
- }
152
- const requestItem = {
153
- text,
154
- lang,
155
- sourceLang: source_lang,
156
- context: ctx,
157
- resolve,
158
- reject
159
- };
160
- state.currentMulti.push(requestItem);
161
- if (state.multiTimer === null && !state.isRequestInFlight) {
162
- state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
163
- }
164
- });
165
- };
166
- }
27
+ // src/transports/base/node.ts
167
28
 
168
29
  // src/version.ts
169
- var SDK_VERSION = (() => {
170
- try {
171
- return true ? "0.7.0" : "undefined";
172
- } catch {
173
- return "undefined";
174
- }
175
- })();
30
+ var SDK_VERSION = "1.0.1" ;
176
31
  var SDK_NAME = "js";
177
32
 
178
33
  // src/transports/base/dedupe.ts
@@ -373,6 +228,136 @@ function createBaseNodeTransport(config) {
373
228
  const transport = new BaseNodeTransport(config);
374
229
  return new DedupeTransport(transport, config.debug);
375
230
  }
231
+ function generateRequestId(texts, lang, sourceLang, context) {
232
+ const sortedTexts = [...texts].sort();
233
+ const sortedContext = context && Object.keys(context).length > 0 ? Object.fromEntries(Object.entries(context).sort(([a], [b]) => a.localeCompare(b))) : null;
234
+ const data = [sortedTexts, lang, sourceLang || null, sortedContext];
235
+ return jsMd5.md5(JSON.stringify(data));
236
+ }
237
+ async function sendMulti(config, items, state) {
238
+ if (config.debug) {
239
+ console.log(`[BeLocal Multi Transport] Sending multi request with ${items.length} texts`);
240
+ }
241
+ try {
242
+ const groups = /* @__PURE__ */ new Map();
243
+ items.forEach((item) => {
244
+ const groupKey = JSON.stringify({
245
+ lang: item.lang,
246
+ sourceLang: item.sourceLang || null,
247
+ context: item.context || null
248
+ });
249
+ if (!groups.has(groupKey)) {
250
+ groups.set(groupKey, []);
251
+ }
252
+ groups.get(groupKey).push(item);
253
+ });
254
+ const requestIdToGroupItems = /* @__PURE__ */ new Map();
255
+ const requests = Array.from(groups.entries()).map(([groupKey, groupItems]) => {
256
+ const firstItem = groupItems[0];
257
+ const texts = groupItems.map((item) => item.text);
258
+ const requestId = generateRequestId(
259
+ texts,
260
+ firstItem.lang,
261
+ firstItem.sourceLang,
262
+ firstItem.context
263
+ );
264
+ requestIdToGroupItems.set(requestId, groupItems);
265
+ return {
266
+ request_id: requestId,
267
+ texts,
268
+ lang: firstItem.lang,
269
+ source_lang: firstItem.sourceLang,
270
+ ctx: firstItem.context
271
+ };
272
+ });
273
+ const multiResponse = await config.baseTransport.post({ requests }, "/v1/translate/multi");
274
+ if (config.debug) {
275
+ console.log(`[BeLocal Multi Transport] Multi response received with ${multiResponse.results.length} groups`);
276
+ }
277
+ const resultMap = /* @__PURE__ */ new Map();
278
+ multiResponse.results.forEach((result) => {
279
+ resultMap.set(result.request_id, { texts: result.data.texts, status: result.data.status });
280
+ });
281
+ requestIdToGroupItems.forEach((groupItems, requestId) => {
282
+ const result = resultMap.get(requestId);
283
+ if (!result) {
284
+ if (config.debug) {
285
+ console.error(`[BeLocal Multi Transport] No result found for request_id: ${requestId}`);
286
+ }
287
+ groupItems.forEach((item) => {
288
+ item.reject(new Error(`No result found for request ${requestId}`));
289
+ });
290
+ return;
291
+ }
292
+ if (result.texts.length !== groupItems.length) {
293
+ const error = new Error(`Mismatch: expected ${groupItems.length} texts, got ${result.texts.length} for request_id ${requestId}`);
294
+ if (config.debug) {
295
+ console.error(`[BeLocal Multi Transport]`, error.message);
296
+ }
297
+ groupItems.forEach((item) => item.reject(error));
298
+ return;
299
+ }
300
+ groupItems.forEach((item, index) => {
301
+ const translatedText = result.texts[index];
302
+ const status = result.status || "success";
303
+ if (config.debug) {
304
+ console.log(`[BeLocal Multi Transport] Success for request_id ${requestId}[${index}]: "${translatedText}"`);
305
+ }
306
+ item.resolve({ text: translatedText, status });
307
+ });
308
+ });
309
+ } catch (error) {
310
+ if (config.debug) {
311
+ console.error(`[BeLocal Multi Transport] Multi request error:`, error);
312
+ }
313
+ const errorToReject = error instanceof Error ? error : new Error(String(error));
314
+ items.forEach((item) => item.reject(errorToReject));
315
+ }
316
+ }
317
+ function processMulti(config, state) {
318
+ if (state.currentMulti.length === 0 || state.isRequestInFlight) {
319
+ return;
320
+ }
321
+ const itemsToSend = [...state.currentMulti];
322
+ state.currentMulti = [];
323
+ state.multiTimer = null;
324
+ state.isRequestInFlight = true;
325
+ sendMulti(config, itemsToSend).finally(() => {
326
+ state.isRequestInFlight = false;
327
+ if (state.currentMulti.length > 0) {
328
+ const windowMs = config.batchWindowMs ?? 50;
329
+ state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
330
+ }
331
+ });
332
+ }
333
+ function createMultiTransport(config) {
334
+ const windowMs = config.batchWindowMs ?? 50;
335
+ const state = {
336
+ currentMulti: [],
337
+ multiTimer: null,
338
+ isRequestInFlight: false
339
+ };
340
+ return ({ text, lang, source_lang, ctx }) => {
341
+ return new Promise((resolve, reject) => {
342
+ if (config.debug) {
343
+ const tempRequestId = jsMd5.md5(JSON.stringify([text, lang, source_lang || null, ctx || null]));
344
+ console.log(`[BeLocal Multi Transport] Queuing request ${tempRequestId}: "${text}" to ${lang}`);
345
+ }
346
+ const requestItem = {
347
+ text,
348
+ lang,
349
+ sourceLang: source_lang,
350
+ context: ctx,
351
+ resolve,
352
+ reject
353
+ };
354
+ state.currentMulti.push(requestItem);
355
+ if (state.multiTimer === null && !state.isRequestInFlight) {
356
+ state.multiTimer = setTimeout(() => processMulti(config, state), windowMs);
357
+ }
358
+ });
359
+ };
360
+ }
376
361
 
377
362
  // src/cache/local.ts
378
363
  var LocalCache = class {
@@ -385,28 +370,9 @@ var LocalCache = class {
385
370
  set(key, value) {
386
371
  this.storage.set(key, value);
387
372
  }
388
- isAvailable() {
389
- return true;
390
- }
391
373
  };
392
374
  var BelocalEngine = class {
393
- /**
394
- * Creates a new BelocalEngine instance.
395
- *
396
- * @param options - Configuration options for the engine
397
- * @throws {Error} If apiKey is not provided or invalid
398
- *
399
- * @example
400
- * ```typescript
401
- * const engine = new BelocalEngine({
402
- * apiKey: 'your-api-key',
403
- * batchWindowMs: 100,
404
- * timeoutMs: 10000,
405
- * debug: false
406
- * });
407
- * ```
408
- */
409
- constructor(options) {
375
+ constructor(options, baseTransportFactory) {
410
376
  const {
411
377
  apiKey,
412
378
  batchWindowMs = 50,
@@ -415,13 +381,10 @@ var BelocalEngine = class {
415
381
  } = options;
416
382
  this.debug = debug;
417
383
  this.cache = new LocalCache();
418
- if (this.debug) {
419
- console.log("[BeLocal Engine] Using local (memory) cache");
420
- }
421
384
  const authHeaders = {
422
385
  "Authorization": `Bearer ${apiKey}`
423
386
  };
424
- const baseTransport = createBaseNodeTransport({
387
+ const baseTransport = baseTransportFactory({
425
388
  headers: authHeaders,
426
389
  timeoutMs,
427
390
  debug: this.debug
@@ -439,91 +402,12 @@ var BelocalEngine = class {
439
402
  });
440
403
  }
441
404
  }
442
- /**
443
- * Translates a single text string to the target language.
444
- *
445
- * Uses in-memory cache to avoid redundant API calls. Results are automatically cached
446
- * for subsequent requests with the same parameters.
447
- *
448
- * @param text - The text to translate
449
- * @param lang - Target language code (e.g., 'es', 'fr', 'ru')
450
- * @param source_lang - Optional source language code. If not provided, auto-detection is used
451
- * @param ctx - Optional key-value pairs for translation context. Supported keys: `user_ctx` (string - descriptive context in English), `cache_type` ('managed' | string)
452
- * @returns Promise resolving to the translated text
453
- * @throws {Error} If the translation request fails (network error, API error, timeout)
454
- *
455
- * @example
456
- * ```typescript
457
- * // Simple translation
458
- * const result = await engine.translate('Hello world', 'es');
459
- *
460
- * // With source language
461
- * const result = await engine.translate('Hello world', 'es', 'en');
462
- *
463
- * // With context (user_ctx) - descriptive context helps improve translation quality
464
- * const result = await engine.translate('Hello world', 'es', undefined, {
465
- * user_ctx: 'greeting message on the homepage'
466
- * });
467
- *
468
- * // With cache_type
469
- * const result = await engine.translate('Hello world', 'es', undefined, { cache_type: 'managed' });
470
- *
471
- * // With source language and context
472
- * const result = await engine.translate('Hello world', 'es', 'en', {
473
- * user_ctx: 'greeting message on the homepage'
474
- * });
475
- * ```
476
- */
405
+ /** Translates a single text string to the target language. */
477
406
  async translate(text, lang, source_lang, ctx) {
478
407
  const results = await this.translateMany([text], lang, source_lang, ctx);
479
408
  return results[0];
480
409
  }
481
- /**
482
- * Translates multiple text strings to the target language in a single batch.
483
- *
484
- * This method is more efficient than calling `translate()` multiple times as it:
485
- * - Batches requests together to reduce API calls
486
- * - Checks cache for each text individually
487
- * - Only requests translations for cache misses
488
- * - Maintains the order of input texts in the result array
489
- *
490
- * @param texts - Array of texts to translate
491
- * @param lang - Target language code (e.g., 'es', 'fr', 'ru')
492
- * @param source_lang - Optional source language code. If not provided, auto-detection is used
493
- * @param ctx - Optional key-value pairs for translation context. Supported keys: `user_ctx` (string - descriptive context in English), `cache_type` ('managed' | string)
494
- * @returns Promise resolving to an array of translated texts in the same order as input
495
- * @throws {Error} If the translation request fails (network error, API error, timeout)
496
- *
497
- * @example
498
- * ```typescript
499
- * // Translate multiple texts
500
- * const results = await engine.translateMany(['Hello', 'World', 'Test'], 'es');
501
- * // Returns: ['Hola', 'Mundo', 'Prueba']
502
- *
503
- * // With source language
504
- * const results = await engine.translateMany(['Hello', 'World'], 'fr', 'en');
505
- *
506
- * // With context (user_ctx) - descriptive context helps improve translation quality
507
- * const results = await engine.translateMany(
508
- * ['Hello', 'World'],
509
- * 'es',
510
- * undefined,
511
- * { user_ctx: 'greeting message on the homepage' }
512
- * );
513
- *
514
- * // With cache_type
515
- * const results = await engine.translateMany(
516
- * ['Hello', 'World'],
517
- * 'es',
518
- * undefined,
519
- * { cache_type: 'managed' }
520
- * );
521
- *
522
- * // Empty array returns empty array
523
- * const results = await engine.translateMany([], 'es');
524
- * // Returns: []
525
- * ```
526
- */
410
+ /** Translates multiple text strings to the target language in a single batch. */
527
411
  async translateMany(texts, lang, source_lang, ctx) {
528
412
  const results = new Array(texts.length);
529
413
  const cacheMisses = [];
@@ -534,7 +418,7 @@ var BelocalEngine = class {
534
418
  if (cachedResult) {
535
419
  results[i] = cachedResult;
536
420
  if (this.debug) {
537
- console.log("[BeLocal Engine] Translation from local cache:", text);
421
+ console.log("[BeLocal Engine] Translation from cache:", text);
538
422
  }
539
423
  continue;
540
424
  }
@@ -549,7 +433,7 @@ var BelocalEngine = class {
549
433
  const cacheKey = this.generateCacheKey(text, lang, source_lang, ctx);
550
434
  this.cache.set(cacheKey, result.text);
551
435
  if (this.debug) {
552
- console.log("[BeLocal Engine] Translation from API, cached in local:", text);
436
+ console.log("[BeLocal Engine] Translation from API, cached:", text);
553
437
  }
554
438
  } else {
555
439
  if (this.debug) {
@@ -565,45 +449,13 @@ var BelocalEngine = class {
565
449
  }
566
450
  return results;
567
451
  }
568
- /**
569
- * Shortcut method for translation with simplified API.
570
- *
571
- * This is a convenience method that wraps `translate()`. When `context` is provided as a string,
572
- * it is automatically wrapped in `{user_ctx: context}` object.
573
- *
574
- * @param text - The text to translate
575
- * @param lang - Target language code (e.g., 'es', 'fr', 'ru')
576
- * @param source_lang - Optional source language code
577
- * @param context - Optional descriptive context string in English (will be wrapped as {user_ctx: context})
578
- * @returns Promise resolving to the translated text
579
- * @throws {Error} If the translation request fails (network error, API error, timeout)
580
- *
581
- * @example
582
- * ```typescript
583
- * // Simple translation
584
- * const result = await engine.t('Hello world', 'es');
585
- *
586
- * // With source language
587
- * const result = await engine.t('Hello world', 'fr', 'en');
588
- *
589
- * // With context string (automatically wrapped as {user_ctx: 'greeting message on the homepage'})
590
- * const result = await engine.t('Hello world', 'es', undefined, 'greeting message on the homepage');
591
- *
592
- * // With source language and context
593
- * const result = await engine.t('Hello world', 'es', 'en', 'greeting message on the homepage');
594
- * ```
595
- */
596
- async t(text, lang, source_lang, context) {
597
- if (context) {
598
- return this.translate(text, lang, source_lang, { user_ctx: context });
599
- }
600
- return this.translate(text, lang, source_lang);
452
+ /** Shortcut for translate() */
453
+ async t(text, lang, source_lang, context, managed = false) {
454
+ const ctx = context || managed ? { ...context ? { user_ctx: context } : {}, ...managed ? { cache_type: "managed" } : {} } : void 0;
455
+ return this.translate(text, lang, source_lang, ctx);
601
456
  }
602
457
  generateCacheKey(text, lang, source_lang, ctx) {
603
- const sortedCtx = ctx ? Object.keys(ctx).sort().reduce((acc, key) => {
604
- acc[key] = ctx[key];
605
- return acc;
606
- }, {}) : null;
458
+ const sortedCtx = ctx ? Object.fromEntries(Object.entries(ctx).sort(([a], [b]) => a.localeCompare(b))) : null;
607
459
  const data = {
608
460
  text,
609
461
  lang,
@@ -614,8 +466,21 @@ var BelocalEngine = class {
614
466
  }
615
467
  };
616
468
 
469
+ // src/core/types.ts
470
+ var USER_TYPE_PRODUCT = "product";
471
+ var USER_TYPE_CHAT = "chat";
472
+
473
+ // src/core/engine/node.ts
474
+ var BelocalEngine2 = class extends BelocalEngine {
475
+ constructor(options) {
476
+ super(options, createBaseNodeTransport);
477
+ }
478
+ };
479
+
617
480
  exports.BaseNodeTransport = BaseNodeTransport;
618
- exports.BelocalEngine = BelocalEngine;
481
+ exports.BelocalEngine = BelocalEngine2;
482
+ exports.USER_TYPE_CHAT = USER_TYPE_CHAT;
483
+ exports.USER_TYPE_PRODUCT = USER_TYPE_PRODUCT;
619
484
  exports.createBaseNodeTransport = createBaseNodeTransport;
620
485
  exports.createMultiTransport = createMultiTransport;
621
486
  //# sourceMappingURL=node.cjs.map