@belocal/js-sdk 0.2.2 → 0.3.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/browser.cjs CHANGED
@@ -1,3 +1,3 @@
1
- 'use strict';var jsMd5=require('js-md5');function p(r){return async({text:e,lang:t,ctx:s})=>{let a=`${r.baseUrl}${r.path}`,i=new AbortController,o=r.timeoutMs?setTimeout(()=>i.abort(),r.timeoutMs):null;r.debug&&console.log(`[BeLocal Browser Transport] Translating "${e}" to ${t} with url ${a}`);try{let n=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json",...r.headers},body:JSON.stringify({text:e,lang:t,ctx:s}),signal:i.signal});if(!n.ok){let g=`HTTP ${n.status}: ${n.statusText}`;throw r.debug&&console.error("[BeLocal Browser Transport] Request failed:",g),new Error(g)}let c=await n.json();return r.debug&&console.log(`[BeLocal Browser Transport] Translation successful: "${c.text||e}"`),c.text||e}finally{o&&clearTimeout(o);}}}var l=class{constructor(e="belocal_"){this.prefix=e;}get(e){try{return localStorage.getItem(this.prefix+e)}catch{return null}}set(e,t){try{localStorage.setItem(this.prefix+e,t);}catch{}}isAvailable(){try{let e=this.prefix+"__test__";return localStorage.setItem(e,"test"),localStorage.removeItem(e),!0}catch{return false}}};var h=class{constructor(){this.storage=new Map;}get(e){return this.storage.get(e)||null}set(e,t){this.storage.set(e,t);}isAvailable(){return true}};var u=class{constructor(e){let{apiKey:t,baseUrl:s="https://dynamic.belocal.dev",path:a="/v1/translate",timeoutMs:i=1e4,debug:o=false}=e;this.debug=o;let n=new l("belocal_translations_");n.isAvailable()?this.cache=n:this.cache=new h,this.isCacheAvailable=this.cache.isAvailable();let c={Authorization:`Bearer ${t}`};this.transport=p({baseUrl:s,path:a,headers:c,timeoutMs:i,debug:this.debug}),this.debug&&(console.log("[BeLocal Engine] Browser transport created with config:",{baseUrl:s,path:a,timeoutMs:i}),console.log("[BeLocal Engine] Cache available:",this.isCacheAvailable));}async t(e,t,s){let a=this.generateCacheKey(e,t,s);if(this.isCacheAvailable){let o=this.cache.get(a);if(o){if(this.debug){let n=this.cache instanceof l?"localStorage":"local";console.log(`[BeLocal Engine] Translation from ${n} cache:`,e);}return o}}let i=await this.transport({text:e,lang:t,ctx:s});if(this.isCacheAvailable){if(this.cache.set(a,i),this.debug){let o=this.cache instanceof l?"localStorage":"local";console.log(`[BeLocal Engine] Translation from API, cached in ${o}:`,e);}}else this.debug&&console.log("[BeLocal Engine] Translation from API (no cache):",e);return i}generateCacheKey(e,t,s){return jsMd5.md5(JSON.stringify({text:e,lang:t,ctx:s||null}))}};
2
- exports.BelocalEngine=u;exports.createBrowserTransport=p;//# sourceMappingURL=browser.cjs.map
1
+ 'use strict';var jsMd5=require('js-md5');function f(t){return async({text:e,lang:s,ctx:o})=>{t.debug&&console.log(`[BeLocal Single Transport] Translating "${e}" to ${s}`);try{let a=await t.baseTransport.post({text:e,lang:s,ctx:o});return t.debug&&console.log(`[BeLocal Single Transport] Translation successful: "${a.text||e}"`),a.text||e}catch(a){throw t.debug&&console.error("[BeLocal Single Transport] Request failed:",a),a}}}function y(t,e,s){return jsMd5.md5(JSON.stringify({text:t,lang:e,ctx:s||null}))}async function w(t,e,s){t.debug&&console.log(`[BeLocal Batch Transport] Sending batch of ${e.length} requests`);try{let o=e.map(r=>({requestId:r.requestId,payload:r.payload})),a=await t.baseTransport.post({batch:o});t.debug&&console.log(`[BeLocal Batch Transport] Batch response received with ${a.results.length} results`);let n=new Map;a.results.forEach(r=>{n.set(r.requestId,{data:r.data,error:r.error});}),e.forEach(r=>{let i=n.get(r.requestId);if(!i){t.debug&&console.error(`[BeLocal Batch Transport] No result found for requestId: ${r.requestId}`),r.reject(new Error(`No result found for request ${r.requestId}`));return}i.error?(t.debug&&console.error(`[BeLocal Batch Transport] Error for requestId ${r.requestId}:`,i.error.message),r.reject(new Error(i.error.message))):i.data?(t.debug&&console.log(`[BeLocal Batch Transport] Success for requestId ${r.requestId}: "${i.data.text}"`),r.resolve(i.data.text)):(t.debug&&console.warn(`[BeLocal Batch Transport] No data or error for requestId ${r.requestId}, returning original text`),r.resolve(r.payload.text));});}catch(o){t.debug&&console.error("[BeLocal Batch Transport] Batch request error:",o);let a=o instanceof Error?o:new Error(String(o));e.forEach(n=>n.reject(a));}finally{}}function T(t,e){if(e.currentBatch.length===0||e.isRequestInFlight)return;let s=[...e.currentBatch];e.currentBatch=[],e.batchTimer=null,e.isRequestInFlight=true,w(t,s).finally(()=>{if(e.isRequestInFlight=false,e.currentBatch.length>0){let o=t.batchWindowMs??50;e.batchTimer=setTimeout(()=>T(t,e),o);}});}function d(t){let e=t.batchWindowMs??50,s={currentBatch:[],batchTimer:null,isRequestInFlight:false};return ({text:o,lang:a,ctx:n})=>new Promise((r,i)=>{let l=y(o,a,n);t.debug&&console.log(`[BeLocal Batch Transport] Queuing request ${l}: "${o}" to ${a}`);let h={requestId:l,payload:{text:o,lang:a,ctx:n},resolve:r,reject:i};s.currentBatch.push(h),s.batchTimer===null&&!s.isRequestInFlight&&(s.batchTimer=setTimeout(()=>T(t,s),e));})}var p=class{constructor(e){this.config=e;}async post(e){let s=`${this.config.baseUrl}${this.config.path||""}`,o=new AbortController,a=this.config.timeoutMs?setTimeout(()=>o.abort(),this.config.timeoutMs):null;this.config.debug&&console.log(`[Base Browser Transport] POST request to ${s}`,e);try{let n=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify(e),signal:o.signal});if(!n.ok){let i=`HTTP ${n.status}: ${n.statusText}`;throw this.config.debug&&console.error("[Base Browser Transport] Request failed:",i),new Error(i)}let r=await n.json();return this.config.debug&&console.log("[Base Browser Transport] Request successful:",r),r}finally{a&&clearTimeout(a);}}};function u(t){return new p(t)}var c=class{constructor(e="belocal_"){this.prefix=e;}get(e){try{return localStorage.getItem(this.prefix+e)}catch{return null}}set(e,s){try{localStorage.setItem(this.prefix+e,s);}catch{}}isAvailable(){try{let e=this.prefix+"__test__";return localStorage.setItem(e,"test"),localStorage.removeItem(e),!0}catch{return false}}};var g=class{constructor(){this.storage=new Map;}get(e){return this.storage.get(e)||null}set(e,s){this.storage.set(e,s);}isAvailable(){return true}};var b=class{constructor(e){let{apiKey:s,baseUrl:o="https://dynamic.belocal.dev",path:a="/v1/translate",batchWindowMs:n=50,timeoutMs:r=1e4,debug:i=false}=e;this.debug=i;let l=new c("belocal_translations_");l.isAvailable()?this.cache=l:this.cache=new g,this.isCacheAvailable=this.cache.isAvailable();let h={Authorization:`Bearer ${s}`},B=u({baseUrl:o,path:a,headers:h,timeoutMs:r,debug:this.debug});n>0?(this.transport=d({baseTransport:B,debug:this.debug,batchWindowMs:n}),this.debug&&console.log("[BeLocal Engine] Batch transport created with config:",{baseUrl:o,path:a,timeoutMs:r,batchWindowMs:n})):(this.transport=f({baseTransport:B,debug:this.debug}),this.debug&&console.log("[BeLocal Engine] Single transport created with config:",{baseUrl:o,path:a,timeoutMs:r})),this.debug&&console.log("[BeLocal Engine] Cache available:",this.isCacheAvailable);}async t(e,s,o){let a=this.generateCacheKey(e,s,o);if(this.isCacheAvailable){let r=this.cache.get(a);if(r){if(this.debug){let i=this.cache instanceof c?"localStorage":"local";console.log(`[BeLocal Engine] Translation from ${i} cache:`,e);}return r}}let n=await this.transport({text:e,lang:s,ctx:o});if(this.isCacheAvailable){if(this.cache.set(a,n),this.debug){let r=this.cache instanceof c?"localStorage":"local";console.log(`[BeLocal Engine] Translation from API, cached in ${r}:`,e);}}else this.debug&&console.log("[BeLocal Engine] Translation from API (no cache):",e);return n}generateCacheKey(e,s,o){return jsMd5.md5(JSON.stringify({text:e,lang:s,ctx:o||null}))}};
2
+ exports.BaseBrowserTransport=p;exports.BelocalEngine=b;exports.createBaseBrowserTransport=u;exports.createBatchTransport=d;exports.createSingleTransport=f;//# sourceMappingURL=browser.cjs.map
3
3
  //# sourceMappingURL=browser.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transports/browser.ts","../src/cache/localStorage.ts","../src/cache/local.ts","../src/core/engine/browser.ts"],"names":["createBrowserTransport","config","text","lang","ctx","url","controller","timeoutId","response","errorMsg","result","LocalStorageCache","prefix","key","value","testKey","LocalCache","BelocalEngine","options","apiKey","baseUrl","path","timeoutMs","debug","localStorageCache","authHeaders","cacheKey","cachedResult","cacheType","md5"],"mappings":"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","file":"browser.cjs","sourcesContent":["import type { Transport } from '../core/types';\n\nexport interface BrowserTransportConfig {\n baseUrl: string;\n path?: string;\n headers?: Record<string, string>;\n timeoutMs?: number;\n debug?: boolean;\n}\n\nexport function createBrowserTransport(config: BrowserTransportConfig): Transport {\n return async ({ text, lang, ctx }) => {\n const url = `${config.baseUrl}${config.path}`;\n const controller = new AbortController();\n const timeoutId = config.timeoutMs ? setTimeout(() => controller.abort(), config.timeoutMs) : null;\n\n if (config.debug) {\n console.log(`[BeLocal Browser Transport] Translating \"${text}\" to ${lang} with url ${url}`);\n }\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...config.headers,\n },\n body: JSON.stringify({ text, lang, ctx }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorMsg = `HTTP ${response.status}: ${response.statusText}`;\n if (config.debug) {\n console.error(`[BeLocal Browser Transport] Request failed:`, errorMsg);\n }\n throw new Error(errorMsg);\n }\n\n const result = await response.json();\n if (config.debug) {\n console.log(`[BeLocal Browser Transport] Translation successful: \"${result.text || text}\"`);\n }\n return result.text || text;\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n };\n}","import type { Cache } from './types';\n\nexport class LocalStorageCache implements Cache {\n private prefix: string;\n\n constructor(prefix: string = 'belocal_') {\n this.prefix = prefix;\n }\n\n get(key: string): string | null {\n try {\n return localStorage.getItem(this.prefix + key);\n } catch {\n // localStorage might not be available in some environments\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(this.prefix + key, value);\n } catch {\n // localStorage might not be available or quota exceeded\n // Silently fail\n }\n }\n\n isAvailable(): boolean {\n try {\n const testKey = this.prefix + '__test__';\n localStorage.setItem(testKey, 'test');\n localStorage.removeItem(testKey);\n return true;\n } catch {\n return false;\n }\n }\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 { createBrowserTransport } from '../../transports/browser';\nimport { LocalStorageCache } from '../../cache/localStorage';\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 private isCacheAvailable: boolean;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n path = '/v1/translate',\n timeoutMs = 10000,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Try localStorage first, fallback to local cache\n const localStorageCache = new LocalStorageCache('belocal_translations_');\n if (localStorageCache.isAvailable()) {\n this.cache = localStorageCache;\n } else {\n this.cache = new LocalCache();\n }\n this.isCacheAvailable = this.cache.isAvailable();\n\n const authHeaders = {\n 'Authorization': `Bearer ${apiKey}`\n };\n\n this.transport = createBrowserTransport({\n baseUrl,\n path,\n headers: authHeaders,\n timeoutMs,\n debug: this.debug\n });\n\n if (this.debug) {\n console.log('[BeLocal Engine] Browser transport created with config:', {\n baseUrl,\n path,\n timeoutMs\n });\n console.log('[BeLocal Engine] Cache available:', this.isCacheAvailable);\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, lang, ctx);\n \n // Try to get from cache first\n if (this.isCacheAvailable) {\n const cachedResult = this.cache.get(cacheKey);\n if (cachedResult) {\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from ${cacheType} cache:`, text);\n }\n return cachedResult;\n }\n }\n\n // Cache miss, get translation from transport\n const result = await this.transport({ text, lang, ctx });\n \n // Store in cache\n if (this.isCacheAvailable) {\n this.cache.set(cacheKey, result);\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from API, cached in ${cacheType}:`, text);\n }\n } else {\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API (no cache):', text);\n }\n }\n\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\n };\n return md5(JSON.stringify(data));\n }\n}\n\n// Re-export types and transport\nexport type { BelocalEngineOptions, Lang, KV } from '../types';\nexport { createBrowserTransport } from '../../transports/browser';\n"]}
1
+ {"version":3,"sources":["../src/transports/single.ts","../src/transports/batch.ts","../src/transports/base/browser.ts","../src/cache/localStorage.ts","../src/cache/local.ts","../src/core/engine/browser.ts"],"names":["createSingleTransport","config","text","lang","ctx","result","error","generateRequestId","md5","sendBatch","batch","state","batchRequests","item","batchResponse","resultMap","errorToReject","processBatch","batchToSend","windowMs","createBatchTransport","resolve","reject","requestId","requestItem","BaseBrowserTransport","data","url","controller","timeoutId","response","errorMsg","createBaseBrowserTransport","LocalStorageCache","prefix","key","value","testKey","LocalCache","BelocalEngine","options","apiKey","baseUrl","path","batchWindowMs","timeoutMs","debug","localStorageCache","authHeaders","baseTransport","cacheKey","cachedResult","cacheType"],"mappings":"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","file":"browser.cjs","sourcesContent":["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}\n\nexport function createSingleTransport(config: SingleTransportConfig): Transport {\n return async ({ text, 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, ctx });\n \n if (config.debug) {\n console.log(`[BeLocal Single Transport] Translation successful: \"${result.text || text}\"`);\n }\n \n return result.text || text;\n } catch (error) {\n if (config.debug) {\n console.error(`[BeLocal Single Transport] Request failed:`, error);\n }\n throw error;\n }\n };\n}\n","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; ctx?: Record<string, unknown> };\n}\n\ninterface BatchRequestItem {\n requestId: string;\n payload: { text: string; lang: string; ctx?: Record<string, unknown> };\n resolve: (value: string) => void;\n reject: (error: Error) => void;\n}\n\ninterface BatchResponse {\n results: Array<{\n requestId: string;\n data?: { text: 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, ctx?: Record<string, unknown>): string {\n const data = {\n text,\n lang,\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 });\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 }; 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 item.resolve(result.data.text);\n } else {\n // Фоллбэк: если нет ни data, ни error, возвращаем оригинальный текст\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(item.payload.text);\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, ctx }) => {\n return new Promise<string>((resolve, reject) => {\n const requestId = generateRequestId(text, 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, 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 { BaseTransport } from '../../core/types';\n\nexport interface BaseBrowserTransportConfig {\n baseUrl: string;\n path?: string;\n headers?: Record<string, string>;\n timeoutMs?: number;\n debug?: boolean;\n}\n\nexport class BaseBrowserTransport implements BaseTransport {\n constructor(private config: BaseBrowserTransportConfig) {}\n\n async post(data: any): Promise<any> {\n const url = `${this.config.baseUrl}${this.config.path || ''}`;\n const controller = new AbortController();\n const timeoutId = this.config.timeoutMs \n ? setTimeout(() => controller.abort(), this.config.timeoutMs) \n : null;\n\n if (this.config.debug) {\n console.log(`[Base Browser Transport] POST request to ${url}`, data);\n }\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n },\n body: JSON.stringify(data),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorMsg = `HTTP ${response.status}: ${response.statusText}`;\n if (this.config.debug) {\n console.error(`[Base Browser Transport] Request failed:`, errorMsg);\n }\n throw new Error(errorMsg);\n }\n\n const result = await response.json();\n if (this.config.debug) {\n console.log(`[Base Browser Transport] Request successful:`, result);\n }\n \n return result;\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n}\n\nexport function createBaseBrowserTransport(config: BaseBrowserTransportConfig): BaseBrowserTransport {\n return new BaseBrowserTransport(config);\n}\n","import type { Cache } from './types';\n\nexport class LocalStorageCache implements Cache {\n private prefix: string;\n\n constructor(prefix: string = 'belocal_') {\n this.prefix = prefix;\n }\n\n get(key: string): string | null {\n try {\n return localStorage.getItem(this.prefix + key);\n } catch {\n // localStorage might not be available in some environments\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(this.prefix + key, value);\n } catch {\n // localStorage might not be available or quota exceeded\n // Silently fail\n }\n }\n\n isAvailable(): boolean {\n try {\n const testKey = this.prefix + '__test__';\n localStorage.setItem(testKey, 'test');\n localStorage.removeItem(testKey);\n return true;\n } catch {\n return false;\n }\n }\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 { createSingleTransport } from '../../transports/single';\nimport { createBatchTransport } from '../../transports/batch';\nimport { createBaseBrowserTransport } from '../../transports/base/browser';\nimport { LocalStorageCache } from '../../cache/localStorage';\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 private isCacheAvailable: boolean;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n path = '/v1/translate',\n batchWindowMs = 50,\n timeoutMs = 10000,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Try localStorage first, fallback to local cache\n const localStorageCache = new LocalStorageCache('belocal_translations_');\n if (localStorageCache.isAvailable()) {\n this.cache = localStorageCache;\n } else {\n this.cache = new LocalCache();\n }\n this.isCacheAvailable = this.cache.isAvailable();\n\n const authHeaders = {\n 'Authorization': `Bearer ${apiKey}`\n };\n\n // Create base browser transport\n const baseTransport = createBaseBrowserTransport({\n baseUrl,\n path,\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 browser 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 path,\n timeoutMs,\n batchWindowMs\n });\n }\n } else {\n // Use single transport with browser 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 path,\n timeoutMs\n });\n }\n }\n \n if (this.debug) {\n console.log('[BeLocal Engine] Cache available:', this.isCacheAvailable);\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, lang, ctx);\n \n // Try to get from cache first\n if (this.isCacheAvailable) {\n const cachedResult = this.cache.get(cacheKey);\n if (cachedResult) {\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from ${cacheType} cache:`, text);\n }\n return cachedResult;\n }\n }\n\n // Cache miss, get translation from transport\n const result = await this.transport({ text, lang, ctx });\n \n // Store in cache\n if (this.isCacheAvailable) {\n this.cache.set(cacheKey, result);\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from API, cached in ${cacheType}:`, text);\n }\n } else {\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API (no cache):', text);\n }\n }\n\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\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 { createSingleTransport } from '../../transports/single';\nexport { createBatchTransport } from '../../transports/batch';\nexport { BaseBrowserTransport, createBaseBrowserTransport } from '../../transports/base';\n"]}
package/dist/browser.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  type Lang = string;
2
2
  type KV = Record<string, unknown>;
3
+ interface BaseTransport {
4
+ post(data: any): Promise<any>;
5
+ }
3
6
  type Transport = (params: {
4
7
  text: string;
5
8
  lang: Lang;
@@ -9,19 +12,37 @@ interface BelocalEngineOptions {
9
12
  apiKey: string;
10
13
  baseUrl?: string;
11
14
  path?: string;
15
+ batchWindowMs?: number;
12
16
  timeoutMs?: number;
13
- retries?: number;
14
17
  debug?: boolean;
15
18
  }
16
19
 
17
- interface BrowserTransportConfig {
20
+ interface SingleTransportConfig {
21
+ baseTransport: BaseTransport;
22
+ debug?: boolean;
23
+ }
24
+ declare function createSingleTransport(config: SingleTransportConfig): Transport;
25
+
26
+ interface BatchTransportConfig {
27
+ baseTransport: BaseTransport;
28
+ debug?: boolean;
29
+ batchWindowMs?: number;
30
+ }
31
+ declare function createBatchTransport(config: BatchTransportConfig): Transport;
32
+
33
+ interface BaseBrowserTransportConfig {
18
34
  baseUrl: string;
19
35
  path?: string;
20
36
  headers?: Record<string, string>;
21
37
  timeoutMs?: number;
22
38
  debug?: boolean;
23
39
  }
24
- declare function createBrowserTransport(config: BrowserTransportConfig): Transport;
40
+ declare class BaseBrowserTransport implements BaseTransport {
41
+ private config;
42
+ constructor(config: BaseBrowserTransportConfig);
43
+ post(data: any): Promise<any>;
44
+ }
45
+ declare function createBaseBrowserTransport(config: BaseBrowserTransportConfig): BaseBrowserTransport;
25
46
 
26
47
  declare class BelocalEngine {
27
48
  private transport;
@@ -33,4 +54,4 @@ declare class BelocalEngine {
33
54
  private generateCacheKey;
34
55
  }
35
56
 
36
- export { BelocalEngine, type BelocalEngineOptions, type KV, type Lang, createBrowserTransport };
57
+ export { BaseBrowserTransport, type BaseTransport, BelocalEngine, type BelocalEngineOptions, type KV, type Lang, createBaseBrowserTransport, createBatchTransport, createSingleTransport };
package/dist/browser.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import {md5}from'js-md5';function p(r){return async({text:e,lang:t,ctx:s})=>{let a=`${r.baseUrl}${r.path}`,i=new AbortController,o=r.timeoutMs?setTimeout(()=>i.abort(),r.timeoutMs):null;r.debug&&console.log(`[BeLocal Browser Transport] Translating "${e}" to ${t} with url ${a}`);try{let n=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json",...r.headers},body:JSON.stringify({text:e,lang:t,ctx:s}),signal:i.signal});if(!n.ok){let g=`HTTP ${n.status}: ${n.statusText}`;throw r.debug&&console.error("[BeLocal Browser Transport] Request failed:",g),new Error(g)}let c=await n.json();return r.debug&&console.log(`[BeLocal Browser Transport] Translation successful: "${c.text||e}"`),c.text||e}finally{o&&clearTimeout(o);}}}var l=class{constructor(e="belocal_"){this.prefix=e;}get(e){try{return localStorage.getItem(this.prefix+e)}catch{return null}}set(e,t){try{localStorage.setItem(this.prefix+e,t);}catch{}}isAvailable(){try{let e=this.prefix+"__test__";return localStorage.setItem(e,"test"),localStorage.removeItem(e),!0}catch{return false}}};var h=class{constructor(){this.storage=new Map;}get(e){return this.storage.get(e)||null}set(e,t){this.storage.set(e,t);}isAvailable(){return true}};var u=class{constructor(e){let{apiKey:t,baseUrl:s="https://dynamic.belocal.dev",path:a="/v1/translate",timeoutMs:i=1e4,debug:o=false}=e;this.debug=o;let n=new l("belocal_translations_");n.isAvailable()?this.cache=n:this.cache=new h,this.isCacheAvailable=this.cache.isAvailable();let c={Authorization:`Bearer ${t}`};this.transport=p({baseUrl:s,path:a,headers:c,timeoutMs:i,debug:this.debug}),this.debug&&(console.log("[BeLocal Engine] Browser transport created with config:",{baseUrl:s,path:a,timeoutMs:i}),console.log("[BeLocal Engine] Cache available:",this.isCacheAvailable));}async t(e,t,s){let a=this.generateCacheKey(e,t,s);if(this.isCacheAvailable){let o=this.cache.get(a);if(o){if(this.debug){let n=this.cache instanceof l?"localStorage":"local";console.log(`[BeLocal Engine] Translation from ${n} cache:`,e);}return o}}let i=await this.transport({text:e,lang:t,ctx:s});if(this.isCacheAvailable){if(this.cache.set(a,i),this.debug){let o=this.cache instanceof l?"localStorage":"local";console.log(`[BeLocal Engine] Translation from API, cached in ${o}:`,e);}}else this.debug&&console.log("[BeLocal Engine] Translation from API (no cache):",e);return i}generateCacheKey(e,t,s){return md5(JSON.stringify({text:e,lang:t,ctx:s||null}))}};
2
- export{u as BelocalEngine,p as createBrowserTransport};//# sourceMappingURL=browser.mjs.map
1
+ import {md5}from'js-md5';function f(t){return async({text:e,lang:s,ctx:o})=>{t.debug&&console.log(`[BeLocal Single Transport] Translating "${e}" to ${s}`);try{let a=await t.baseTransport.post({text:e,lang:s,ctx:o});return t.debug&&console.log(`[BeLocal Single Transport] Translation successful: "${a.text||e}"`),a.text||e}catch(a){throw t.debug&&console.error("[BeLocal Single Transport] Request failed:",a),a}}}function y(t,e,s){return md5(JSON.stringify({text:t,lang:e,ctx:s||null}))}async function w(t,e,s){t.debug&&console.log(`[BeLocal Batch Transport] Sending batch of ${e.length} requests`);try{let o=e.map(r=>({requestId:r.requestId,payload:r.payload})),a=await t.baseTransport.post({batch:o});t.debug&&console.log(`[BeLocal Batch Transport] Batch response received with ${a.results.length} results`);let n=new Map;a.results.forEach(r=>{n.set(r.requestId,{data:r.data,error:r.error});}),e.forEach(r=>{let i=n.get(r.requestId);if(!i){t.debug&&console.error(`[BeLocal Batch Transport] No result found for requestId: ${r.requestId}`),r.reject(new Error(`No result found for request ${r.requestId}`));return}i.error?(t.debug&&console.error(`[BeLocal Batch Transport] Error for requestId ${r.requestId}:`,i.error.message),r.reject(new Error(i.error.message))):i.data?(t.debug&&console.log(`[BeLocal Batch Transport] Success for requestId ${r.requestId}: "${i.data.text}"`),r.resolve(i.data.text)):(t.debug&&console.warn(`[BeLocal Batch Transport] No data or error for requestId ${r.requestId}, returning original text`),r.resolve(r.payload.text));});}catch(o){t.debug&&console.error("[BeLocal Batch Transport] Batch request error:",o);let a=o instanceof Error?o:new Error(String(o));e.forEach(n=>n.reject(a));}finally{}}function T(t,e){if(e.currentBatch.length===0||e.isRequestInFlight)return;let s=[...e.currentBatch];e.currentBatch=[],e.batchTimer=null,e.isRequestInFlight=true,w(t,s).finally(()=>{if(e.isRequestInFlight=false,e.currentBatch.length>0){let o=t.batchWindowMs??50;e.batchTimer=setTimeout(()=>T(t,e),o);}});}function d(t){let e=t.batchWindowMs??50,s={currentBatch:[],batchTimer:null,isRequestInFlight:false};return ({text:o,lang:a,ctx:n})=>new Promise((r,i)=>{let l=y(o,a,n);t.debug&&console.log(`[BeLocal Batch Transport] Queuing request ${l}: "${o}" to ${a}`);let h={requestId:l,payload:{text:o,lang:a,ctx:n},resolve:r,reject:i};s.currentBatch.push(h),s.batchTimer===null&&!s.isRequestInFlight&&(s.batchTimer=setTimeout(()=>T(t,s),e));})}var p=class{constructor(e){this.config=e;}async post(e){let s=`${this.config.baseUrl}${this.config.path||""}`,o=new AbortController,a=this.config.timeoutMs?setTimeout(()=>o.abort(),this.config.timeoutMs):null;this.config.debug&&console.log(`[Base Browser Transport] POST request to ${s}`,e);try{let n=await fetch(s,{method:"POST",headers:{"Content-Type":"application/json",...this.config.headers},body:JSON.stringify(e),signal:o.signal});if(!n.ok){let i=`HTTP ${n.status}: ${n.statusText}`;throw this.config.debug&&console.error("[Base Browser Transport] Request failed:",i),new Error(i)}let r=await n.json();return this.config.debug&&console.log("[Base Browser Transport] Request successful:",r),r}finally{a&&clearTimeout(a);}}};function u(t){return new p(t)}var c=class{constructor(e="belocal_"){this.prefix=e;}get(e){try{return localStorage.getItem(this.prefix+e)}catch{return null}}set(e,s){try{localStorage.setItem(this.prefix+e,s);}catch{}}isAvailable(){try{let e=this.prefix+"__test__";return localStorage.setItem(e,"test"),localStorage.removeItem(e),!0}catch{return false}}};var g=class{constructor(){this.storage=new Map;}get(e){return this.storage.get(e)||null}set(e,s){this.storage.set(e,s);}isAvailable(){return true}};var b=class{constructor(e){let{apiKey:s,baseUrl:o="https://dynamic.belocal.dev",path:a="/v1/translate",batchWindowMs:n=50,timeoutMs:r=1e4,debug:i=false}=e;this.debug=i;let l=new c("belocal_translations_");l.isAvailable()?this.cache=l:this.cache=new g,this.isCacheAvailable=this.cache.isAvailable();let h={Authorization:`Bearer ${s}`},B=u({baseUrl:o,path:a,headers:h,timeoutMs:r,debug:this.debug});n>0?(this.transport=d({baseTransport:B,debug:this.debug,batchWindowMs:n}),this.debug&&console.log("[BeLocal Engine] Batch transport created with config:",{baseUrl:o,path:a,timeoutMs:r,batchWindowMs:n})):(this.transport=f({baseTransport:B,debug:this.debug}),this.debug&&console.log("[BeLocal Engine] Single transport created with config:",{baseUrl:o,path:a,timeoutMs:r})),this.debug&&console.log("[BeLocal Engine] Cache available:",this.isCacheAvailable);}async t(e,s,o){let a=this.generateCacheKey(e,s,o);if(this.isCacheAvailable){let r=this.cache.get(a);if(r){if(this.debug){let i=this.cache instanceof c?"localStorage":"local";console.log(`[BeLocal Engine] Translation from ${i} cache:`,e);}return r}}let n=await this.transport({text:e,lang:s,ctx:o});if(this.isCacheAvailable){if(this.cache.set(a,n),this.debug){let r=this.cache instanceof c?"localStorage":"local";console.log(`[BeLocal Engine] Translation from API, cached in ${r}:`,e);}}else this.debug&&console.log("[BeLocal Engine] Translation from API (no cache):",e);return n}generateCacheKey(e,s,o){return md5(JSON.stringify({text:e,lang:s,ctx:o||null}))}};
2
+ export{p as BaseBrowserTransport,b as BelocalEngine,u as createBaseBrowserTransport,d as createBatchTransport,f as createSingleTransport};//# sourceMappingURL=browser.mjs.map
3
3
  //# sourceMappingURL=browser.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transports/browser.ts","../src/cache/localStorage.ts","../src/cache/local.ts","../src/core/engine/browser.ts"],"names":["createBrowserTransport","config","text","lang","ctx","url","controller","timeoutId","response","errorMsg","result","LocalStorageCache","prefix","key","value","testKey","LocalCache","BelocalEngine","options","apiKey","baseUrl","path","timeoutMs","debug","localStorageCache","authHeaders","cacheKey","cachedResult","cacheType","md5"],"mappings":"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","file":"browser.mjs","sourcesContent":["import type { Transport } from '../core/types';\n\nexport interface BrowserTransportConfig {\n baseUrl: string;\n path?: string;\n headers?: Record<string, string>;\n timeoutMs?: number;\n debug?: boolean;\n}\n\nexport function createBrowserTransport(config: BrowserTransportConfig): Transport {\n return async ({ text, lang, ctx }) => {\n const url = `${config.baseUrl}${config.path}`;\n const controller = new AbortController();\n const timeoutId = config.timeoutMs ? setTimeout(() => controller.abort(), config.timeoutMs) : null;\n\n if (config.debug) {\n console.log(`[BeLocal Browser Transport] Translating \"${text}\" to ${lang} with url ${url}`);\n }\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...config.headers,\n },\n body: JSON.stringify({ text, lang, ctx }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorMsg = `HTTP ${response.status}: ${response.statusText}`;\n if (config.debug) {\n console.error(`[BeLocal Browser Transport] Request failed:`, errorMsg);\n }\n throw new Error(errorMsg);\n }\n\n const result = await response.json();\n if (config.debug) {\n console.log(`[BeLocal Browser Transport] Translation successful: \"${result.text || text}\"`);\n }\n return result.text || text;\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n };\n}","import type { Cache } from './types';\n\nexport class LocalStorageCache implements Cache {\n private prefix: string;\n\n constructor(prefix: string = 'belocal_') {\n this.prefix = prefix;\n }\n\n get(key: string): string | null {\n try {\n return localStorage.getItem(this.prefix + key);\n } catch {\n // localStorage might not be available in some environments\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(this.prefix + key, value);\n } catch {\n // localStorage might not be available or quota exceeded\n // Silently fail\n }\n }\n\n isAvailable(): boolean {\n try {\n const testKey = this.prefix + '__test__';\n localStorage.setItem(testKey, 'test');\n localStorage.removeItem(testKey);\n return true;\n } catch {\n return false;\n }\n }\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 { createBrowserTransport } from '../../transports/browser';\nimport { LocalStorageCache } from '../../cache/localStorage';\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 private isCacheAvailable: boolean;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n path = '/v1/translate',\n timeoutMs = 10000,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Try localStorage first, fallback to local cache\n const localStorageCache = new LocalStorageCache('belocal_translations_');\n if (localStorageCache.isAvailable()) {\n this.cache = localStorageCache;\n } else {\n this.cache = new LocalCache();\n }\n this.isCacheAvailable = this.cache.isAvailable();\n\n const authHeaders = {\n 'Authorization': `Bearer ${apiKey}`\n };\n\n this.transport = createBrowserTransport({\n baseUrl,\n path,\n headers: authHeaders,\n timeoutMs,\n debug: this.debug\n });\n\n if (this.debug) {\n console.log('[BeLocal Engine] Browser transport created with config:', {\n baseUrl,\n path,\n timeoutMs\n });\n console.log('[BeLocal Engine] Cache available:', this.isCacheAvailable);\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, lang, ctx);\n \n // Try to get from cache first\n if (this.isCacheAvailable) {\n const cachedResult = this.cache.get(cacheKey);\n if (cachedResult) {\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from ${cacheType} cache:`, text);\n }\n return cachedResult;\n }\n }\n\n // Cache miss, get translation from transport\n const result = await this.transport({ text, lang, ctx });\n \n // Store in cache\n if (this.isCacheAvailable) {\n this.cache.set(cacheKey, result);\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from API, cached in ${cacheType}:`, text);\n }\n } else {\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API (no cache):', text);\n }\n }\n\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\n };\n return md5(JSON.stringify(data));\n }\n}\n\n// Re-export types and transport\nexport type { BelocalEngineOptions, Lang, KV } from '../types';\nexport { createBrowserTransport } from '../../transports/browser';\n"]}
1
+ {"version":3,"sources":["../src/transports/single.ts","../src/transports/batch.ts","../src/transports/base/browser.ts","../src/cache/localStorage.ts","../src/cache/local.ts","../src/core/engine/browser.ts"],"names":["createSingleTransport","config","text","lang","ctx","result","error","generateRequestId","md5","sendBatch","batch","state","batchRequests","item","batchResponse","resultMap","errorToReject","processBatch","batchToSend","windowMs","createBatchTransport","resolve","reject","requestId","requestItem","BaseBrowserTransport","data","url","controller","timeoutId","response","errorMsg","createBaseBrowserTransport","LocalStorageCache","prefix","key","value","testKey","LocalCache","BelocalEngine","options","apiKey","baseUrl","path","batchWindowMs","timeoutMs","debug","localStorageCache","authHeaders","baseTransport","cacheKey","cachedResult","cacheType"],"mappings":"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","file":"browser.mjs","sourcesContent":["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}\n\nexport function createSingleTransport(config: SingleTransportConfig): Transport {\n return async ({ text, 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, ctx });\n \n if (config.debug) {\n console.log(`[BeLocal Single Transport] Translation successful: \"${result.text || text}\"`);\n }\n \n return result.text || text;\n } catch (error) {\n if (config.debug) {\n console.error(`[BeLocal Single Transport] Request failed:`, error);\n }\n throw error;\n }\n };\n}\n","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; ctx?: Record<string, unknown> };\n}\n\ninterface BatchRequestItem {\n requestId: string;\n payload: { text: string; lang: string; ctx?: Record<string, unknown> };\n resolve: (value: string) => void;\n reject: (error: Error) => void;\n}\n\ninterface BatchResponse {\n results: Array<{\n requestId: string;\n data?: { text: 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, ctx?: Record<string, unknown>): string {\n const data = {\n text,\n lang,\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 });\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 }; 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 item.resolve(result.data.text);\n } else {\n // Фоллбэк: если нет ни data, ни error, возвращаем оригинальный текст\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(item.payload.text);\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, ctx }) => {\n return new Promise<string>((resolve, reject) => {\n const requestId = generateRequestId(text, 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, 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 { BaseTransport } from '../../core/types';\n\nexport interface BaseBrowserTransportConfig {\n baseUrl: string;\n path?: string;\n headers?: Record<string, string>;\n timeoutMs?: number;\n debug?: boolean;\n}\n\nexport class BaseBrowserTransport implements BaseTransport {\n constructor(private config: BaseBrowserTransportConfig) {}\n\n async post(data: any): Promise<any> {\n const url = `${this.config.baseUrl}${this.config.path || ''}`;\n const controller = new AbortController();\n const timeoutId = this.config.timeoutMs \n ? setTimeout(() => controller.abort(), this.config.timeoutMs) \n : null;\n\n if (this.config.debug) {\n console.log(`[Base Browser Transport] POST request to ${url}`, data);\n }\n\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n },\n body: JSON.stringify(data),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const errorMsg = `HTTP ${response.status}: ${response.statusText}`;\n if (this.config.debug) {\n console.error(`[Base Browser Transport] Request failed:`, errorMsg);\n }\n throw new Error(errorMsg);\n }\n\n const result = await response.json();\n if (this.config.debug) {\n console.log(`[Base Browser Transport] Request successful:`, result);\n }\n \n return result;\n } finally {\n if (timeoutId) {\n clearTimeout(timeoutId);\n }\n }\n }\n}\n\nexport function createBaseBrowserTransport(config: BaseBrowserTransportConfig): BaseBrowserTransport {\n return new BaseBrowserTransport(config);\n}\n","import type { Cache } from './types';\n\nexport class LocalStorageCache implements Cache {\n private prefix: string;\n\n constructor(prefix: string = 'belocal_') {\n this.prefix = prefix;\n }\n\n get(key: string): string | null {\n try {\n return localStorage.getItem(this.prefix + key);\n } catch {\n // localStorage might not be available in some environments\n return null;\n }\n }\n\n set(key: string, value: string): void {\n try {\n localStorage.setItem(this.prefix + key, value);\n } catch {\n // localStorage might not be available or quota exceeded\n // Silently fail\n }\n }\n\n isAvailable(): boolean {\n try {\n const testKey = this.prefix + '__test__';\n localStorage.setItem(testKey, 'test');\n localStorage.removeItem(testKey);\n return true;\n } catch {\n return false;\n }\n }\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 { createSingleTransport } from '../../transports/single';\nimport { createBatchTransport } from '../../transports/batch';\nimport { createBaseBrowserTransport } from '../../transports/base/browser';\nimport { LocalStorageCache } from '../../cache/localStorage';\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 private isCacheAvailable: boolean;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n path = '/v1/translate',\n batchWindowMs = 50,\n timeoutMs = 10000,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Try localStorage first, fallback to local cache\n const localStorageCache = new LocalStorageCache('belocal_translations_');\n if (localStorageCache.isAvailable()) {\n this.cache = localStorageCache;\n } else {\n this.cache = new LocalCache();\n }\n this.isCacheAvailable = this.cache.isAvailable();\n\n const authHeaders = {\n 'Authorization': `Bearer ${apiKey}`\n };\n\n // Create base browser transport\n const baseTransport = createBaseBrowserTransport({\n baseUrl,\n path,\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 browser 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 path,\n timeoutMs,\n batchWindowMs\n });\n }\n } else {\n // Use single transport with browser 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 path,\n timeoutMs\n });\n }\n }\n \n if (this.debug) {\n console.log('[BeLocal Engine] Cache available:', this.isCacheAvailable);\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, lang, ctx);\n \n // Try to get from cache first\n if (this.isCacheAvailable) {\n const cachedResult = this.cache.get(cacheKey);\n if (cachedResult) {\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from ${cacheType} cache:`, text);\n }\n return cachedResult;\n }\n }\n\n // Cache miss, get translation from transport\n const result = await this.transport({ text, lang, ctx });\n \n // Store in cache\n if (this.isCacheAvailable) {\n this.cache.set(cacheKey, result);\n if (this.debug) {\n const cacheType = this.cache instanceof LocalStorageCache ? 'localStorage' : 'local';\n console.log(`[BeLocal Engine] Translation from API, cached in ${cacheType}:`, text);\n }\n } else {\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API (no cache):', text);\n }\n }\n\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\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 { createSingleTransport } from '../../transports/single';\nexport { createBatchTransport } from '../../transports/batch';\nexport { BaseBrowserTransport, createBaseBrowserTransport } from '../../transports/base';\n"]}
package/dist/node.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
+ var jsMd5 = require('js-md5');
3
4
  var http2 = require('http2');
4
5
  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,7 +24,130 @@ function _interopNamespace(e) {
24
24
 
25
25
  var http2__namespace = /*#__PURE__*/_interopNamespace(http2);
26
26
 
27
- // src/transports/node.ts
27
+ // src/transports/batch.ts
28
+ function generateRequestId(text, lang, ctx) {
29
+ const data = {
30
+ text,
31
+ lang,
32
+ ctx: ctx || null
33
+ };
34
+ return jsMd5.md5(JSON.stringify(data));
35
+ }
36
+ async function sendBatch(config, batch, state) {
37
+ if (config.debug) {
38
+ console.log(`[BeLocal Batch Transport] Sending batch of ${batch.length} requests`);
39
+ }
40
+ try {
41
+ const batchRequests = batch.map((item) => ({
42
+ requestId: item.requestId,
43
+ payload: item.payload
44
+ }));
45
+ const batchResponse = await config.baseTransport.post({ batch: batchRequests });
46
+ if (config.debug) {
47
+ console.log(`[BeLocal Batch Transport] Batch response received with ${batchResponse.results.length} results`);
48
+ }
49
+ const resultMap = /* @__PURE__ */ new Map();
50
+ batchResponse.results.forEach((result) => {
51
+ resultMap.set(result.requestId, { data: result.data, error: result.error });
52
+ });
53
+ batch.forEach((item) => {
54
+ const result = resultMap.get(item.requestId);
55
+ if (!result) {
56
+ if (config.debug) {
57
+ console.error(`[BeLocal Batch Transport] No result found for requestId: ${item.requestId}`);
58
+ }
59
+ item.reject(new Error(`No result found for request ${item.requestId}`));
60
+ return;
61
+ }
62
+ if (result.error) {
63
+ if (config.debug) {
64
+ console.error(`[BeLocal Batch Transport] Error for requestId ${item.requestId}:`, result.error.message);
65
+ }
66
+ item.reject(new Error(result.error.message));
67
+ } else if (result.data) {
68
+ if (config.debug) {
69
+ console.log(`[BeLocal Batch Transport] Success for requestId ${item.requestId}: "${result.data.text}"`);
70
+ }
71
+ item.resolve(result.data.text);
72
+ } else {
73
+ if (config.debug) {
74
+ console.warn(`[BeLocal Batch Transport] No data or error for requestId ${item.requestId}, returning original text`);
75
+ }
76
+ item.resolve(item.payload.text);
77
+ }
78
+ });
79
+ } catch (error) {
80
+ if (config.debug) {
81
+ console.error(`[BeLocal Batch Transport] Batch request error:`, error);
82
+ }
83
+ const errorToReject = error instanceof Error ? error : new Error(String(error));
84
+ batch.forEach((item) => item.reject(errorToReject));
85
+ } finally {
86
+ }
87
+ }
88
+ function processBatch(config, state) {
89
+ if (state.currentBatch.length === 0 || state.isRequestInFlight) {
90
+ return;
91
+ }
92
+ const batchToSend = [...state.currentBatch];
93
+ state.currentBatch = [];
94
+ state.batchTimer = null;
95
+ state.isRequestInFlight = true;
96
+ sendBatch(config, batchToSend).finally(() => {
97
+ state.isRequestInFlight = false;
98
+ if (state.currentBatch.length > 0) {
99
+ const windowMs = config.batchWindowMs ?? 50;
100
+ state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);
101
+ }
102
+ });
103
+ }
104
+ function createBatchTransport(config) {
105
+ const windowMs = config.batchWindowMs ?? 50;
106
+ const state = {
107
+ currentBatch: [],
108
+ batchTimer: null,
109
+ isRequestInFlight: false
110
+ };
111
+ return ({ text, lang, ctx }) => {
112
+ return new Promise((resolve, reject) => {
113
+ const requestId = generateRequestId(text, lang, ctx);
114
+ if (config.debug) {
115
+ console.log(`[BeLocal Batch Transport] Queuing request ${requestId}: "${text}" to ${lang}`);
116
+ }
117
+ const requestItem = {
118
+ requestId,
119
+ payload: { text, lang, ctx },
120
+ resolve,
121
+ reject
122
+ };
123
+ state.currentBatch.push(requestItem);
124
+ if (state.batchTimer === null && !state.isRequestInFlight) {
125
+ state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);
126
+ }
127
+ });
128
+ };
129
+ }
130
+
131
+ // src/transports/single.ts
132
+ function createSingleTransport(config) {
133
+ return async ({ text, lang, ctx }) => {
134
+ if (config.debug) {
135
+ console.log(`[BeLocal Single Transport] Translating "${text}" to ${lang}`);
136
+ }
137
+ try {
138
+ const result = await config.baseTransport.post({ text, lang, ctx });
139
+ if (config.debug) {
140
+ console.log(`[BeLocal Single Transport] Translation successful: "${result.text || text}"`);
141
+ }
142
+ return result.text || text;
143
+ } catch (error) {
144
+ if (config.debug) {
145
+ console.error(`[BeLocal Single Transport] Request failed:`, error);
146
+ }
147
+ throw error;
148
+ }
149
+ };
150
+ }
28
151
  var sessionCache = /* @__PURE__ */ new Map();
29
152
  function getOrCreateSession(baseUrl, debug) {
30
153
  if (sessionCache.has(baseUrl)) {
@@ -44,10 +167,10 @@ function getOrCreateSession(baseUrl, debug) {
44
167
  sessionCache.delete(baseUrl);
45
168
  });
46
169
  if (debug) {
47
- session.on("connect", () => console.log("[H2] new session connected"));
170
+ session.on("connect", () => console.log("[Base Node Transport H2] new session connected"));
48
171
  session.on(
49
172
  "goaway",
50
- (code, lastStreamID, opaque) => console.log("[H2] goaway", code, lastStreamID)
173
+ (code, lastStreamID, opaque) => console.log("[Base Node Transport H2] goaway", code, lastStreamID)
51
174
  );
52
175
  }
53
176
  sessionCache.set(baseUrl, session);
@@ -95,36 +218,44 @@ function makeHttp2Request(session, path, headers, body, timeoutMs) {
95
218
  req.end();
96
219
  });
97
220
  }
98
- function createNodeTransport(config) {
99
- return async ({ text, lang, ctx }) => {
100
- const maxRetries = config.retries || 0;
221
+ var BaseNodeTransport = class {
222
+ constructor(config) {
223
+ this.config = config;
224
+ }
225
+ async post(data) {
226
+ const maxRetries = this.config.retries || 0;
101
227
  let attempt = 0;
102
- if (config.debug) {
103
- console.log(`[BeLocal Node Transport] Translating "${text}" to ${lang} with url ${config.baseUrl}${config.path}`);
228
+ const url = `${this.config.baseUrl}${this.config.path || ""}`;
229
+ if (this.config.debug) {
230
+ console.log(`[Base Node Transport] POST request to ${url}`, data);
104
231
  }
105
232
  while (attempt <= maxRetries) {
106
233
  try {
107
- const session = getOrCreateSession(config.baseUrl, config.debug);
108
- const body = JSON.stringify({ text, lang, ctx });
234
+ const session = getOrCreateSession(this.config.baseUrl, this.config.debug);
235
+ const body = JSON.stringify(data);
109
236
  const response = await makeHttp2Request(
110
237
  session,
111
- config.path,
112
- config.headers || {},
238
+ this.config.path || "/",
239
+ this.config.headers || {},
113
240
  body,
114
- config.timeoutMs
241
+ this.config.timeoutMs
115
242
  );
116
243
  if (response.statusCode < 200 || response.statusCode >= 300) {
117
- throw new Error(`HTTP ${response.statusCode}: Request failed`);
244
+ const errorMsg = `HTTP ${response.statusCode}: Request failed`;
245
+ if (this.config.debug) {
246
+ console.error(`[Base Node Transport] Request failed:`, errorMsg);
247
+ }
248
+ throw new Error(errorMsg);
118
249
  }
119
250
  const result = JSON.parse(response.body);
120
- if (config.debug) {
121
- console.log(`[BeLocal Node Transport] Translation successful: "${result.text || text}"`);
251
+ if (this.config.debug) {
252
+ console.log(`[Base Node Transport] Request successful:`, result);
122
253
  }
123
- return result.text || text;
254
+ return result;
124
255
  } catch (error) {
125
256
  attempt++;
126
- if (config.debug) {
127
- console.error(`[BeLocal Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));
257
+ if (this.config.debug) {
258
+ console.error(`[Base Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));
128
259
  }
129
260
  if (attempt > maxRetries) {
130
261
  throw error;
@@ -132,8 +263,11 @@ function createNodeTransport(config) {
132
263
  await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3));
133
264
  }
134
265
  }
135
- return text;
136
- };
266
+ throw new Error("Max retries exceeded");
267
+ }
268
+ };
269
+ function createBaseNodeTransport(config) {
270
+ return new BaseNodeTransport(config);
137
271
  }
138
272
 
139
273
  // src/cache/local.ts
@@ -157,57 +291,66 @@ var BelocalEngine = class {
157
291
  apiKey,
158
292
  baseUrl = "https://dynamic.belocal.dev",
159
293
  path = "/v1/translate",
294
+ batchWindowMs = 50,
160
295
  timeoutMs = 1e4,
161
- retries = 3,
162
296
  debug = false
163
297
  } = options;
164
298
  this.debug = debug;
165
299
  this.cache = new LocalCache();
166
- this.isCacheAvailable = this.cache.isAvailable();
167
300
  if (this.debug) {
168
301
  console.log("[BeLocal Engine] Using local (memory) cache");
169
302
  }
170
303
  const authHeaders = {
171
304
  "Authorization": `Bearer ${apiKey}`
172
305
  };
173
- this.transport = createNodeTransport({
306
+ const baseTransport = createBaseNodeTransport({
174
307
  baseUrl,
175
308
  path,
176
309
  headers: authHeaders,
177
310
  timeoutMs,
178
- retries,
179
311
  debug: this.debug
180
312
  });
181
- if (this.debug) {
182
- console.log("[BeLocal Engine] Node transport created with config:", {
183
- baseUrl,
184
- path,
185
- timeoutMs,
186
- retries
313
+ if (batchWindowMs > 0) {
314
+ this.transport = createBatchTransport({
315
+ baseTransport,
316
+ debug: this.debug,
317
+ batchWindowMs
187
318
  });
319
+ if (this.debug) {
320
+ console.log("[BeLocal Engine] Batch transport created with config:", {
321
+ baseUrl,
322
+ path,
323
+ timeoutMs,
324
+ batchWindowMs
325
+ });
326
+ }
327
+ } else {
328
+ this.transport = createSingleTransport({
329
+ baseTransport,
330
+ debug: this.debug
331
+ });
332
+ if (this.debug) {
333
+ console.log("[BeLocal Engine] Single transport created with config:", {
334
+ baseUrl,
335
+ path,
336
+ timeoutMs
337
+ });
338
+ }
188
339
  }
189
340
  }
190
341
  async t(text, lang, ctx) {
191
342
  const cacheKey = this.generateCacheKey(text, lang, ctx);
192
- if (this.isCacheAvailable) {
193
- const cachedResult = this.cache.get(cacheKey);
194
- if (cachedResult) {
195
- if (this.debug) {
196
- console.log("[BeLocal Engine] Translation from local cache:", text);
197
- }
198
- return cachedResult;
343
+ const cachedResult = this.cache.get(cacheKey);
344
+ if (cachedResult) {
345
+ if (this.debug) {
346
+ console.log("[BeLocal Engine] Translation from local cache:", text);
199
347
  }
348
+ return cachedResult;
200
349
  }
201
350
  const result = await this.transport({ text, lang, ctx });
202
- if (this.isCacheAvailable) {
203
- this.cache.set(cacheKey, result);
204
- if (this.debug) {
205
- console.log("[BeLocal Engine] Translation from API, cached in local:", text);
206
- }
207
- } else {
208
- if (this.debug) {
209
- console.log("[BeLocal Engine] Translation from API (no cache):", text);
210
- }
351
+ this.cache.set(cacheKey, result);
352
+ if (this.debug) {
353
+ console.log("[BeLocal Engine] Translation from API, cached in local:", text);
211
354
  }
212
355
  return result;
213
356
  }
@@ -221,7 +364,10 @@ var BelocalEngine = class {
221
364
  }
222
365
  };
223
366
 
367
+ exports.BaseNodeTransport = BaseNodeTransport;
224
368
  exports.BelocalEngine = BelocalEngine;
225
- exports.createNodeTransport = createNodeTransport;
369
+ exports.createBaseNodeTransport = createBaseNodeTransport;
370
+ exports.createBatchTransport = createBatchTransport;
371
+ exports.createSingleTransport = createSingleTransport;
226
372
  //# sourceMappingURL=node.cjs.map
227
373
  //# sourceMappingURL=node.cjs.map
package/dist/node.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transports/node.ts","../src/cache/local.ts","../src/core/engine/node.ts"],"names":["session","URL","http2","headers","md5"],"mappings":"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","file":"node.cjs","sourcesContent":["import * as http2 from 'node:http2';\nimport { URL } from 'node:url';\nimport type { Transport } from '../core/types';\n\nexport interface NodeTransportConfig {\n baseUrl: string;\n path: 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('[H2] new session connected'));\n session.on('goaway', (code, lastStreamID, opaque) =>\n console.log('[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 function createNodeTransport(config: NodeTransportConfig): Transport {\n return async ({ text, lang, ctx }) => {\n const maxRetries = config.retries || 0;\n let attempt = 0;\n\n if (config.debug) {\n console.log(`[BeLocal Node Transport] Translating \"${text}\" to ${lang} with url ${config.baseUrl}${config.path}`);\n }\n\n while (attempt <= maxRetries) {\n try {\n const session = getOrCreateSession(config.baseUrl, config.debug);\n const body = JSON.stringify({ text, lang, ctx });\n \n const response = await makeHttp2Request(\n session,\n config.path,\n config.headers || {},\n body,\n config.timeoutMs\n );\n\n if (response.statusCode < 200 || response.statusCode >= 300) {\n throw new Error(`HTTP ${response.statusCode}: Request failed`);\n }\n\n const result = JSON.parse(response.body);\n if (config.debug) {\n console.log(`[BeLocal Node Transport] Translation successful: \"${result.text || text}\"`);\n }\n return result.text || text;\n } catch (error) {\n attempt++;\n if (config.debug) {\n console.error(`[BeLocal Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));\n }\n if (attempt > maxRetries) {\n throw error;\n }\n\n await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));\n }\n }\n\n return text;\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 { createNodeTransport } from '../../transports/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 private isCacheAvailable: boolean;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n path = '/v1/translate',\n timeoutMs = 10000,\n retries = 3,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Use local cache for Node.js\n this.cache = new LocalCache();\n this.isCacheAvailable = this.cache.isAvailable();\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 this.transport = createNodeTransport({\n baseUrl,\n path,\n headers: authHeaders,\n timeoutMs,\n retries,\n debug: this.debug\n });\n\n if (this.debug) {\n console.log('[BeLocal Engine] Node transport created with config:', {\n baseUrl,\n path,\n timeoutMs,\n retries\n });\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, lang, ctx);\n \n // Try to get from cache first\n if (this.isCacheAvailable) {\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\n // Cache miss, get translation from transport\n const result = await this.transport({ text, lang, ctx });\n \n // Store in cache\n if (this.isCacheAvailable) {\n this.cache.set(cacheKey, result);\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 (no cache):', text);\n }\n }\n\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\n };\n return md5(JSON.stringify(data));\n }\n}\n\n// Re-export types and transport\nexport type { BelocalEngineOptions, Lang, KV } from '../types';\nexport { createNodeTransport } from '../../transports/node';\n"]}
1
+ {"version":3,"sources":["../src/transports/batch.ts","../src/transports/single.ts","../src/transports/base/node.ts","../src/cache/local.ts","../src/core/engine/node.ts"],"names":["md5","session","URL","http2","headers"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAS,iBAAA,CAAkB,IAAA,EAAc,IAAA,EAAc,GAAA,EAAuC;AAC5F,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,IAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAK,GAAA,IAAO;AAAA,GACd;AACA,EAAA,OAAOA,SAAA,CAAI,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AACjC;AAEA,eAAe,SAAA,CACb,MAAA,EACA,KAAA,EACA,KAAA,EACe;AACf,EAAA,IAAI,OAAO,KAAA,EAAO;AAChB,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,2CAAA,EAA8C,KAAA,CAAM,MAAM,CAAA,SAAA,CAAW,CAAA;AAAA,EACnF;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,aAAA,GAAgC,KAAA,CAAM,GAAA,CAAI,CAAA,IAAA,MAAS;AAAA,MACvD,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,SAAS,IAAA,CAAK;AAAA,KAChB,CAAE,CAAA;AAEF,IAAA,MAAM,aAAA,GAA+B,MAAM,MAAA,CAAO,aAAA,CAAc,KAAK,EAAE,KAAA,EAAO,eAAe,CAAA;AAE7F,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,uDAAA,EAA0D,aAAA,CAAc,OAAA,CAAQ,MAAM,CAAA,QAAA,CAAU,CAAA;AAAA,IAC9G;AAGA,IAAA,MAAM,SAAA,uBAAgB,GAAA,EAAsE;AAC5F,IAAA,aAAA,CAAc,OAAA,CAAQ,QAAQ,CAAA,MAAA,KAAU;AACtC,MAAA,SAAA,CAAU,GAAA,CAAI,MAAA,CAAO,SAAA,EAAW,EAAE,IAAA,EAAM,OAAO,IAAA,EAAM,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,CAAA;AAAA,IAC5E,CAAC,CAAA;AAGD,IAAA,KAAA,CAAM,QAAQ,CAAA,IAAA,KAAQ;AACpB,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,SAAS,CAAA;AAE3C,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,yDAAA,EAA4D,IAAA,CAAK,SAAS,CAAA,CAAE,CAAA;AAAA,QAC5F;AACA,QAAA,IAAA,CAAK,OAAO,IAAI,KAAA,CAAM,+BAA+B,IAAA,CAAK,SAAS,EAAE,CAAC,CAAA;AACtE,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,OAAO,KAAA,EAAO;AAChB,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,OAAA,CAAQ,MAAM,CAAA,8CAAA,EAAiD,IAAA,CAAK,SAAS,CAAA,CAAA,CAAA,EAAK,MAAA,CAAO,MAAM,OAAO,CAAA;AAAA,QACxG;AACA,QAAA,IAAA,CAAK,OAAO,IAAI,KAAA,CAAM,MAAA,CAAO,KAAA,CAAM,OAAO,CAAC,CAAA;AAAA,MAC7C,CAAA,MAAA,IAAW,OAAO,IAAA,EAAM;AACtB,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,OAAA,CAAQ,GAAA,CAAI,mDAAmD,IAAA,CAAK,SAAS,MAAM,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,QACxG;AACA,QAAA,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA;AAAA,MAC/B,CAAA,MAAO;AAEL,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,yDAAA,EAA4D,IAAA,CAAK,SAAS,CAAA,yBAAA,CAA2B,CAAA;AAAA,QACpH;AACA,QAAA,IAAA,CAAK,OAAA,CAAQ,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA;AAAA,MAChC;AAAA,IACF,CAAC,CAAA;AAAA,EAEH,SAAS,KAAA,EAAO;AACd,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,OAAA,CAAQ,KAAA,CAAM,kDAAkD,KAAK,CAAA;AAAA,IACvE;AAGA,IAAA,MAAM,aAAA,GAAgB,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AAC9E,IAAA,KAAA,CAAM,OAAA,CAAQ,CAAA,IAAA,KAAQ,IAAA,CAAK,MAAA,CAAO,aAAa,CAAC,CAAA;AAAA,EAClD,CAAA,SAAE;AAAA,EAEF;AACF;AAEA,SAAS,YAAA,CAAa,QAA8B,KAAA,EAAyB;AAC3E,EAAA,IAAI,KAAA,CAAM,YAAA,CAAa,MAAA,KAAW,CAAA,IAAK,MAAM,iBAAA,EAAmB;AAC9D,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,GAAG,KAAA,CAAM,YAAY,CAAA;AAC1C,EAAA,KAAA,CAAM,eAAe,EAAC;AACtB,EAAA,KAAA,CAAM,UAAA,GAAa,IAAA;AACnB,EAAA,KAAA,CAAM,iBAAA,GAAoB,IAAA;AAE1B,EAAA,SAAA,CAAU,MAAA,EAAQ,WAAkB,CAAA,CAAE,QAAQ,MAAM;AAClD,IAAA,KAAA,CAAM,iBAAA,GAAoB,KAAA;AAE1B,IAAA,IAAI,KAAA,CAAM,YAAA,CAAa,MAAA,GAAS,CAAA,EAAG;AACjC,MAAA,MAAM,QAAA,GAAW,OAAO,aAAA,IAAiB,EAAA;AACzC,MAAA,KAAA,CAAM,aAAa,UAAA,CAAW,MAAM,aAAa,MAAA,EAAQ,KAAK,GAAG,QAAQ,CAAA;AAAA,IAC3E;AAAA,EACF,CAAC,CAAA;AACH;AAEO,SAAS,qBAAqB,MAAA,EAAyC;AAC5E,EAAA,MAAM,QAAA,GAAW,OAAO,aAAA,IAAiB,EAAA;AAEzC,EAAA,MAAM,KAAA,GAAoB;AAAA,IACxB,cAAc,EAAC;AAAA,IACf,UAAA,EAAY,IAAA;AAAA,IACZ,iBAAA,EAAmB;AAAA,GACrB;AAEA,EAAA,OAAO,CAAC,EAAE,IAAA,EAAM,IAAA,EAAM,KAAI,KAAM;AAC9B,IAAA,OAAO,IAAI,OAAA,CAAgB,CAAC,OAAA,EAAS,MAAA,KAAW;AAC9C,MAAA,MAAM,SAAA,GAAY,iBAAA,CAAkB,IAAA,EAAM,IAAA,EAAM,GAAG,CAAA;AAEnD,MAAA,IAAI,OAAO,KAAA,EAAO;AAChB,QAAA,OAAA,CAAQ,IAAI,CAAA,0CAAA,EAA6C,SAAS,MAAM,IAAI,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAE,CAAA;AAAA,MAC5F;AAEA,MAAA,MAAM,WAAA,GAAgC;AAAA,QACpC,SAAA;AAAA,QACA,OAAA,EAAS,EAAE,IAAA,EAAM,IAAA,EAAM,GAAA,EAAI;AAAA,QAC3B,OAAA;AAAA,QACA;AAAA,OACF;AAEA,MAAA,KAAA,CAAM,YAAA,CAAa,KAAK,WAAW,CAAA;AAEnC,MAAA,IAAI,KAAA,CAAM,UAAA,KAAe,IAAA,IAAQ,CAAC,MAAM,iBAAA,EAAmB;AACzD,QAAA,KAAA,CAAM,aAAa,UAAA,CAAW,MAAM,aAAa,MAAA,EAAQ,KAAK,GAAG,QAAQ,CAAA;AAAA,MAC3E;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AACF;;;AC3JO,SAAS,sBAAsB,MAAA,EAA0C;AAC9E,EAAA,OAAO,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,KAAI,KAAM;AACpC,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,wCAAA,EAA2C,IAAI,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAE,CAAA;AAAA,IAC3E;AAEA,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAA8B,MAAM,MAAA,CAAO,aAAA,CAAc,KAAK,EAAE,IAAA,EAAM,IAAA,EAAM,GAAA,EAAK,CAAA;AAEvF,MAAA,IAAI,OAAO,KAAA,EAAO;AAChB,QAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,oDAAA,EAAuD,MAAA,CAAO,IAAA,IAAQ,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,MAC3F;AAEA,MAAA,OAAO,OAAO,IAAA,IAAQ,IAAA;AAAA,IACxB,SAAS,KAAA,EAAO;AACd,MAAA,IAAI,OAAO,KAAA,EAAO;AAChB,QAAA,OAAA,CAAQ,KAAA,CAAM,8CAA8C,KAAK,CAAA;AAAA,MACnE;AACA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF,CAAA;AACF;AClBA,IAAM,YAAA,uBAAmB,GAAA,EAAsC;AAE/D,SAAS,kBAAA,CAAmB,SAAiB,KAAA,EAA2C;AACtF,EAAA,IAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA,EAAG;AAC7B,IAAA,MAAMC,QAAAA,GAAU,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AACxC,IAAA,IAAI,CAACA,SAAQ,SAAA,EAAW;AACtB,MAAA,OAAOA,QAAAA;AAAA,IACT;AACA,IAAA,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,EAC7B;AAEA,EAAA,MAAM,SAAA,GAAY,IAAIC,OAAA,CAAI,OAAO,CAAA;AACjC,EAAA,MAAM,OAAA,GAAgBC,gBAAA,CAAA,OAAA,CAAQ,SAAA,CAAU,MAAM,CAAA;AAE9C,EAAA,OAAA,CAAQ,QAAQ,KAAA,EAAM;AAGtB,EAAA,OAAA,CAAQ,EAAA,CAAG,SAAS,MAAM;AACxB,IAAA,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,EAC7B,CAAC,CAAA;AAED,EAAA,OAAA,CAAQ,EAAA,CAAG,SAAS,MAAM;AACxB,IAAA,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,EAC7B,CAAC,CAAA;AAGD,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,OAAA,CAAQ,GAAG,SAAA,EAAW,MAAM,OAAA,CAAQ,GAAA,CAAI,gDAAgD,CAAC,CAAA;AACzF,IAAA,OAAA,CAAQ,EAAA;AAAA,MAAG,QAAA;AAAA,MAAU,CAAC,MAAM,YAAA,EAAc,MAAA,KACxC,QAAQ,GAAA,CAAI,iCAAA,EAAmC,MAAM,YAAY;AAAA,KACnE;AAAA,EACF;AAEA,EAAA,YAAA,CAAa,GAAA,CAAI,SAAS,OAAO,CAAA;AACjC,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,gBAAA,CACP,OAAA,EACA,IAAA,EACA,OAAA,EACA,MACA,SAAA,EACgF;AAChF,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,GAAA,GAAM,QAAQ,OAAA,CAAQ;AAAA,MAC1B,SAAA,EAAW,MAAA;AAAA,MACX,OAAA,EAAS,IAAA;AAAA,MACT,cAAA,EAAgB,kBAAA;AAAA,MAChB,gBAAA,EAAkB,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAAA,MACxC,GAAG;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,OAAA,GAAiC,IAAA;AACrC,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAA,GAAU,WAAW,MAAM;AACzB,QAAA,GAAA,CAAI,OAAA,EAAQ;AACZ,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,SAAS,IAAI,CAAC,CAAA;AAAA,MAC1D,GAAG,SAAS,CAAA;AAAA,IACd;AAEA,IAAA,IAAI,YAAA,GAAe,EAAA;AACnB,IAAA,IAAI,UAAA,GAAa,CAAA;AACjB,IAAA,IAAI,kBAA0C,EAAC;AAE/C,IAAA,GAAA,CAAI,EAAA,CAAG,UAAA,EAAY,CAACC,QAAAA,KAAY;AAC9B,MAAA,UAAA,GAAaA,SAAQ,SAAS,CAAA;AAC9B,MAAA,eAAA,GAAkBA,QAAAA;AAAA,IACpB,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAAU;AACxB,MAAA,YAAA,IAAgB,KAAA;AAAA,IAClB,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,OAAO,MAAM;AAClB,MAAA,IAAI,OAAA,eAAsB,OAAO,CAAA;AACjC,MAAA,OAAA,CAAQ;AAAA,QACN,UAAA;AAAA,QACA,OAAA,EAAS,eAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,OAAA,EAAS,CAAC,KAAA,KAAU;AACzB,MAAA,IAAI,OAAA,eAAsB,OAAO,CAAA;AACjC,MAAA,MAAA,CAAO,KAAK,CAAA;AAAA,IACd,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,MAAM,IAAI,CAAA;AACd,IAAA,GAAA,CAAI,GAAA,EAAI;AAAA,EACV,CAAC,CAAA;AACH;AAEO,IAAM,oBAAN,MAAiD;AAAA,EACtD,YAAoB,MAAA,EAAiC;AAAjC,IAAA,IAAA,CAAA,MAAA,GAAA,MAAA;AAAA,EAAkC;AAAA,EAEtD,MAAM,KAAK,IAAA,EAAyB;AAClC,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,CAAA;AAC1C,IAAA,IAAI,OAAA,GAAU,CAAA;AACd,IAAA,MAAM,GAAA,GAAM,GAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,IAAA,IAAQ,EAAE,CAAA,CAAA;AAE3D,IAAA,IAAI,IAAA,CAAK,OAAO,KAAA,EAAO;AACrB,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,sCAAA,EAAyC,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA;AAAA,IAClE;AAEA,IAAA,OAAO,WAAW,UAAA,EAAY;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,UAAU,kBAAA,CAAmB,IAAA,CAAK,OAAO,OAAA,EAAS,IAAA,CAAK,OAAO,KAAK,CAAA;AACzE,QAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAEhC,QAAA,MAAM,WAAW,MAAM,gBAAA;AAAA,UACrB,OAAA;AAAA,UACA,IAAA,CAAK,OAAO,IAAA,IAAQ,GAAA;AAAA,UACpB,IAAA,CAAK,MAAA,CAAO,OAAA,IAAW,EAAC;AAAA,UACxB,IAAA;AAAA,UACA,KAAK,MAAA,CAAO;AAAA,SACd;AAEA,QAAA,IAAI,QAAA,CAAS,UAAA,GAAa,GAAA,IAAO,QAAA,CAAS,cAAc,GAAA,EAAK;AAC3D,UAAA,MAAM,QAAA,GAAW,CAAA,KAAA,EAAQ,QAAA,CAAS,UAAU,CAAA,gBAAA,CAAA;AAC5C,UAAA,IAAI,IAAA,CAAK,OAAO,KAAA,EAAO;AACrB,YAAA,OAAA,CAAQ,KAAA,CAAM,yCAAyC,QAAQ,CAAA;AAAA,UACjE;AACA,UAAA,MAAM,IAAI,MAAM,QAAQ,CAAA;AAAA,QAC1B;AAEA,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AACvC,QAAA,IAAI,IAAA,CAAK,OAAO,KAAA,EAAO;AACrB,UAAA,OAAA,CAAQ,GAAA,CAAI,6CAA6C,MAAM,CAAA;AAAA,QACjE;AAEA,QAAA,OAAO,MAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,EAAA;AACA,QAAA,IAAI,IAAA,CAAK,OAAO,KAAA,EAAO;AACrB,UAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,8BAAA,EAAiC,OAAO,CAAA,QAAA,CAAA,EAAY,KAAA,YAAiB,QAAQ,KAAA,CAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,QAC1H;AACA,QAAA,IAAI,UAAU,UAAA,EAAY;AACxB,UAAA,MAAM,KAAA;AAAA,QACR;AAGA,QAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAA,GAAI,GAAI,CAAC,CAAA;AAAA,MAC/E;AAAA,IACF;AAGA,IAAA,MAAM,IAAI,MAAM,sBAAsB,CAAA;AAAA,EACxC;AACF;AAEO,SAAS,wBAAwB,MAAA,EAAoD;AAC1F,EAAA,OAAO,IAAI,kBAAkB,MAAM,CAAA;AACrC;;;ACrKO,IAAM,aAAN,MAAkC;AAAA,EAAlC,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,OAAA,uBAAc,GAAA,EAAoB;AAAA,EAAA;AAAA,EAE1C,IAAI,GAAA,EAA4B;AAC9B,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,EAClC;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAqB;AACpC,IAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EAC7B;AAAA,EAEA,WAAA,GAAuB;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AACF,CAAA;ACRO,IAAM,gBAAN,MAAoB;AAAA,EAKzB,YAAY,OAAA,EAA+B;AACzC,IAAA,MAAM;AAAA,MACJ,MAAA;AAAA,MACA,OAAA,GAAU,6BAAA;AAAA,MACV,IAAA,GAAO,eAAA;AAAA,MACP,aAAA,GAAgB,EAAA;AAAA,MAChB,SAAA,GAAY,GAAA;AAAA,MACZ,KAAA,GAAQ;AAAA,KACV,GAAI,OAAA;AAEJ,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AAGb,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAI,UAAA,EAAW;AAE5B,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAI,6CAA6C,CAAA;AAAA,IAC3D;AAEA,IAAA,MAAM,WAAA,GAAc;AAAA,MAClB,eAAA,EAAiB,UAAU,MAAM,CAAA;AAAA,KACnC;AAGA,IAAA,MAAM,gBAAgB,uBAAA,CAAwB;AAAA,MAC5C,OAAA;AAAA,MACA,IAAA;AAAA,MACA,OAAA,EAAS,WAAA;AAAA,MACT,SAAA;AAAA,MACA,OAAO,IAAA,CAAK;AAAA,KACb,CAAA;AAGD,IAAA,IAAI,gBAAgB,CAAA,EAAG;AAErB,MAAA,IAAA,CAAK,YAAY,oBAAA,CAAqB;AAAA,QACpC,aAAA;AAAA,QACA,OAAO,IAAA,CAAK,KAAA;AAAA,QACZ;AAAA,OACD,CAAA;AAED,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,IAAI,uDAAA,EAAyD;AAAA,UACnE,OAAA;AAAA,UACA,IAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,IAAA,CAAK,YAAY,qBAAA,CAAsB;AAAA,QACrC,aAAA;AAAA,QACA,OAAO,IAAA,CAAK;AAAA,OACb,CAAA;AAED,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,IAAI,wDAAA,EAA0D;AAAA,UACpE,OAAA;AAAA,UACA,IAAA;AAAA,UACA;AAAA,SACD,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,CAAA,CAAE,IAAA,EAAc,IAAA,EAAY,GAAA,EAA2B;AAE3D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,gBAAA,CAAiB,IAAA,EAAM,MAAM,GAAG,CAAA;AAGtD,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AAC5C,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,GAAA,CAAI,kDAAkD,IAAI,CAAA;AAAA,MACpE;AACA,MAAA,OAAO,YAAA;AAAA,IACT;AAGA,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AAGvD,IAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,QAAA,EAAU,MAAM,CAAA;AAC/B,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,GAAA,CAAI,2DAA2D,IAAI,CAAA;AAAA,IAC7E;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEQ,gBAAA,CAAiB,IAAA,EAAc,IAAA,EAAY,GAAA,EAAkB;AACnE,IAAA,MAAM,IAAA,GAAO;AAAA,MACX,IAAA;AAAA,MACA,IAAA;AAAA,MACA,KAAK,GAAA,IAAO;AAAA,KACd;AACA,IAAA,OAAOJ,SAAAA,CAAI,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,EACjC;AACF","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; ctx?: Record<string, unknown> };\n}\n\ninterface BatchRequestItem {\n requestId: string;\n payload: { text: string; lang: string; ctx?: Record<string, unknown> };\n resolve: (value: string) => void;\n reject: (error: Error) => void;\n}\n\ninterface BatchResponse {\n results: Array<{\n requestId: string;\n data?: { text: 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, ctx?: Record<string, unknown>): string {\n const data = {\n text,\n lang,\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 });\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 }; 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 item.resolve(result.data.text);\n } else {\n // Фоллбэк: если нет ни data, ни error, возвращаем оригинальный текст\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(item.payload.text);\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, ctx }) => {\n return new Promise<string>((resolve, reject) => {\n const requestId = generateRequestId(text, 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, 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}\n\nexport function createSingleTransport(config: SingleTransportConfig): Transport {\n return async ({ text, 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, ctx });\n \n if (config.debug) {\n console.log(`[BeLocal Single Transport] Translation successful: \"${result.text || text}\"`);\n }\n \n return result.text || text;\n } catch (error) {\n if (config.debug) {\n console.error(`[BeLocal Single Transport] Request failed:`, error);\n }\n throw error;\n }\n };\n}\n","import * as http2 from 'node:http2';\nimport { URL } from 'node:url';\nimport type { BaseTransport } from '../../core/types';\n\nexport interface BaseNodeTransportConfig {\n baseUrl: string;\n path?: 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): Promise<any> {\n const maxRetries = this.config.retries || 0;\n let attempt = 0;\n const url = `${this.config.baseUrl}${this.config.path || ''}`;\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 const response = await makeHttp2Request(\n session,\n this.config.path || '/',\n this.config.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 path = '/v1/translate',\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 path,\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 path,\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 path,\n timeoutMs\n });\n }\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, 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, ctx });\n \n // Store in cache\n this.cache.set(cacheKey, result);\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API, cached in local:', text);\n }\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\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"]}
package/dist/node.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  type Lang = string;
2
2
  type KV = Record<string, unknown>;
3
+ interface BaseTransport {
4
+ post(data: any): Promise<any>;
5
+ }
3
6
  type Transport = (params: {
4
7
  text: string;
5
8
  lang: Lang;
@@ -9,29 +12,46 @@ interface BelocalEngineOptions {
9
12
  apiKey: string;
10
13
  baseUrl?: string;
11
14
  path?: string;
15
+ batchWindowMs?: number;
12
16
  timeoutMs?: number;
13
- retries?: number;
14
17
  debug?: boolean;
15
18
  }
16
19
 
17
- interface NodeTransportConfig {
20
+ interface BaseNodeTransportConfig {
18
21
  baseUrl: string;
19
- path: string;
22
+ path?: string;
20
23
  headers?: Record<string, string>;
21
24
  timeoutMs?: number;
22
25
  retries?: number;
23
26
  debug?: boolean;
24
27
  }
25
- declare function createNodeTransport(config: NodeTransportConfig): Transport;
28
+ declare class BaseNodeTransport implements BaseTransport {
29
+ private config;
30
+ constructor(config: BaseNodeTransportConfig);
31
+ post(data: any): Promise<any>;
32
+ }
33
+ declare function createBaseNodeTransport(config: BaseNodeTransportConfig): BaseNodeTransport;
34
+
35
+ interface BatchTransportConfig {
36
+ baseTransport: BaseTransport;
37
+ debug?: boolean;
38
+ batchWindowMs?: number;
39
+ }
40
+ declare function createBatchTransport(config: BatchTransportConfig): Transport;
41
+
42
+ interface SingleTransportConfig {
43
+ baseTransport: BaseTransport;
44
+ debug?: boolean;
45
+ }
46
+ declare function createSingleTransport(config: SingleTransportConfig): Transport;
26
47
 
27
48
  declare class BelocalEngine {
28
49
  private transport;
29
50
  private debug;
30
51
  private cache;
31
- private isCacheAvailable;
32
52
  constructor(options: BelocalEngineOptions);
33
53
  t(text: string, lang: Lang, ctx?: KV): Promise<string>;
34
54
  private generateCacheKey;
35
55
  }
36
56
 
37
- export { BelocalEngine, type BelocalEngineOptions, type KV, type Lang, createNodeTransport };
57
+ export { BaseNodeTransport, type BaseTransport, BelocalEngine, type BelocalEngineOptions, type KV, type Lang, createBaseNodeTransport, createBatchTransport, createSingleTransport };
package/dist/node.mjs CHANGED
@@ -1,8 +1,131 @@
1
+ import { md5 } from 'js-md5';
1
2
  import * as http2 from 'http2';
2
3
  import { URL } from 'url';
3
- import { md5 } from 'js-md5';
4
4
 
5
- // src/transports/node.ts
5
+ // src/transports/batch.ts
6
+ function generateRequestId(text, lang, ctx) {
7
+ const data = {
8
+ text,
9
+ lang,
10
+ ctx: ctx || null
11
+ };
12
+ return md5(JSON.stringify(data));
13
+ }
14
+ async function sendBatch(config, batch, state) {
15
+ if (config.debug) {
16
+ console.log(`[BeLocal Batch Transport] Sending batch of ${batch.length} requests`);
17
+ }
18
+ try {
19
+ const batchRequests = batch.map((item) => ({
20
+ requestId: item.requestId,
21
+ payload: item.payload
22
+ }));
23
+ const batchResponse = await config.baseTransport.post({ batch: batchRequests });
24
+ if (config.debug) {
25
+ console.log(`[BeLocal Batch Transport] Batch response received with ${batchResponse.results.length} results`);
26
+ }
27
+ const resultMap = /* @__PURE__ */ new Map();
28
+ batchResponse.results.forEach((result) => {
29
+ resultMap.set(result.requestId, { data: result.data, error: result.error });
30
+ });
31
+ batch.forEach((item) => {
32
+ const result = resultMap.get(item.requestId);
33
+ if (!result) {
34
+ if (config.debug) {
35
+ console.error(`[BeLocal Batch Transport] No result found for requestId: ${item.requestId}`);
36
+ }
37
+ item.reject(new Error(`No result found for request ${item.requestId}`));
38
+ return;
39
+ }
40
+ if (result.error) {
41
+ if (config.debug) {
42
+ console.error(`[BeLocal Batch Transport] Error for requestId ${item.requestId}:`, result.error.message);
43
+ }
44
+ item.reject(new Error(result.error.message));
45
+ } else if (result.data) {
46
+ if (config.debug) {
47
+ console.log(`[BeLocal Batch Transport] Success for requestId ${item.requestId}: "${result.data.text}"`);
48
+ }
49
+ item.resolve(result.data.text);
50
+ } else {
51
+ if (config.debug) {
52
+ console.warn(`[BeLocal Batch Transport] No data or error for requestId ${item.requestId}, returning original text`);
53
+ }
54
+ item.resolve(item.payload.text);
55
+ }
56
+ });
57
+ } catch (error) {
58
+ if (config.debug) {
59
+ console.error(`[BeLocal Batch Transport] Batch request error:`, error);
60
+ }
61
+ const errorToReject = error instanceof Error ? error : new Error(String(error));
62
+ batch.forEach((item) => item.reject(errorToReject));
63
+ } finally {
64
+ }
65
+ }
66
+ function processBatch(config, state) {
67
+ if (state.currentBatch.length === 0 || state.isRequestInFlight) {
68
+ return;
69
+ }
70
+ const batchToSend = [...state.currentBatch];
71
+ state.currentBatch = [];
72
+ state.batchTimer = null;
73
+ state.isRequestInFlight = true;
74
+ sendBatch(config, batchToSend).finally(() => {
75
+ state.isRequestInFlight = false;
76
+ if (state.currentBatch.length > 0) {
77
+ const windowMs = config.batchWindowMs ?? 50;
78
+ state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);
79
+ }
80
+ });
81
+ }
82
+ function createBatchTransport(config) {
83
+ const windowMs = config.batchWindowMs ?? 50;
84
+ const state = {
85
+ currentBatch: [],
86
+ batchTimer: null,
87
+ isRequestInFlight: false
88
+ };
89
+ return ({ text, lang, ctx }) => {
90
+ return new Promise((resolve, reject) => {
91
+ const requestId = generateRequestId(text, lang, ctx);
92
+ if (config.debug) {
93
+ console.log(`[BeLocal Batch Transport] Queuing request ${requestId}: "${text}" to ${lang}`);
94
+ }
95
+ const requestItem = {
96
+ requestId,
97
+ payload: { text, lang, ctx },
98
+ resolve,
99
+ reject
100
+ };
101
+ state.currentBatch.push(requestItem);
102
+ if (state.batchTimer === null && !state.isRequestInFlight) {
103
+ state.batchTimer = setTimeout(() => processBatch(config, state), windowMs);
104
+ }
105
+ });
106
+ };
107
+ }
108
+
109
+ // src/transports/single.ts
110
+ function createSingleTransport(config) {
111
+ return async ({ text, lang, ctx }) => {
112
+ if (config.debug) {
113
+ console.log(`[BeLocal Single Transport] Translating "${text}" to ${lang}`);
114
+ }
115
+ try {
116
+ const result = await config.baseTransport.post({ text, lang, ctx });
117
+ if (config.debug) {
118
+ console.log(`[BeLocal Single Transport] Translation successful: "${result.text || text}"`);
119
+ }
120
+ return result.text || text;
121
+ } catch (error) {
122
+ if (config.debug) {
123
+ console.error(`[BeLocal Single Transport] Request failed:`, error);
124
+ }
125
+ throw error;
126
+ }
127
+ };
128
+ }
6
129
  var sessionCache = /* @__PURE__ */ new Map();
7
130
  function getOrCreateSession(baseUrl, debug) {
8
131
  if (sessionCache.has(baseUrl)) {
@@ -22,10 +145,10 @@ function getOrCreateSession(baseUrl, debug) {
22
145
  sessionCache.delete(baseUrl);
23
146
  });
24
147
  if (debug) {
25
- session.on("connect", () => console.log("[H2] new session connected"));
148
+ session.on("connect", () => console.log("[Base Node Transport H2] new session connected"));
26
149
  session.on(
27
150
  "goaway",
28
- (code, lastStreamID, opaque) => console.log("[H2] goaway", code, lastStreamID)
151
+ (code, lastStreamID, opaque) => console.log("[Base Node Transport H2] goaway", code, lastStreamID)
29
152
  );
30
153
  }
31
154
  sessionCache.set(baseUrl, session);
@@ -73,36 +196,44 @@ function makeHttp2Request(session, path, headers, body, timeoutMs) {
73
196
  req.end();
74
197
  });
75
198
  }
76
- function createNodeTransport(config) {
77
- return async ({ text, lang, ctx }) => {
78
- const maxRetries = config.retries || 0;
199
+ var BaseNodeTransport = class {
200
+ constructor(config) {
201
+ this.config = config;
202
+ }
203
+ async post(data) {
204
+ const maxRetries = this.config.retries || 0;
79
205
  let attempt = 0;
80
- if (config.debug) {
81
- console.log(`[BeLocal Node Transport] Translating "${text}" to ${lang} with url ${config.baseUrl}${config.path}`);
206
+ const url = `${this.config.baseUrl}${this.config.path || ""}`;
207
+ if (this.config.debug) {
208
+ console.log(`[Base Node Transport] POST request to ${url}`, data);
82
209
  }
83
210
  while (attempt <= maxRetries) {
84
211
  try {
85
- const session = getOrCreateSession(config.baseUrl, config.debug);
86
- const body = JSON.stringify({ text, lang, ctx });
212
+ const session = getOrCreateSession(this.config.baseUrl, this.config.debug);
213
+ const body = JSON.stringify(data);
87
214
  const response = await makeHttp2Request(
88
215
  session,
89
- config.path,
90
- config.headers || {},
216
+ this.config.path || "/",
217
+ this.config.headers || {},
91
218
  body,
92
- config.timeoutMs
219
+ this.config.timeoutMs
93
220
  );
94
221
  if (response.statusCode < 200 || response.statusCode >= 300) {
95
- throw new Error(`HTTP ${response.statusCode}: Request failed`);
222
+ const errorMsg = `HTTP ${response.statusCode}: Request failed`;
223
+ if (this.config.debug) {
224
+ console.error(`[Base Node Transport] Request failed:`, errorMsg);
225
+ }
226
+ throw new Error(errorMsg);
96
227
  }
97
228
  const result = JSON.parse(response.body);
98
- if (config.debug) {
99
- console.log(`[BeLocal Node Transport] Translation successful: "${result.text || text}"`);
229
+ if (this.config.debug) {
230
+ console.log(`[Base Node Transport] Request successful:`, result);
100
231
  }
101
- return result.text || text;
232
+ return result;
102
233
  } catch (error) {
103
234
  attempt++;
104
- if (config.debug) {
105
- console.error(`[BeLocal Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));
235
+ if (this.config.debug) {
236
+ console.error(`[Base Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));
106
237
  }
107
238
  if (attempt > maxRetries) {
108
239
  throw error;
@@ -110,8 +241,11 @@ function createNodeTransport(config) {
110
241
  await new Promise((resolve) => setTimeout(resolve, Math.pow(2, attempt) * 1e3));
111
242
  }
112
243
  }
113
- return text;
114
- };
244
+ throw new Error("Max retries exceeded");
245
+ }
246
+ };
247
+ function createBaseNodeTransport(config) {
248
+ return new BaseNodeTransport(config);
115
249
  }
116
250
 
117
251
  // src/cache/local.ts
@@ -135,57 +269,66 @@ var BelocalEngine = class {
135
269
  apiKey,
136
270
  baseUrl = "https://dynamic.belocal.dev",
137
271
  path = "/v1/translate",
272
+ batchWindowMs = 50,
138
273
  timeoutMs = 1e4,
139
- retries = 3,
140
274
  debug = false
141
275
  } = options;
142
276
  this.debug = debug;
143
277
  this.cache = new LocalCache();
144
- this.isCacheAvailable = this.cache.isAvailable();
145
278
  if (this.debug) {
146
279
  console.log("[BeLocal Engine] Using local (memory) cache");
147
280
  }
148
281
  const authHeaders = {
149
282
  "Authorization": `Bearer ${apiKey}`
150
283
  };
151
- this.transport = createNodeTransport({
284
+ const baseTransport = createBaseNodeTransport({
152
285
  baseUrl,
153
286
  path,
154
287
  headers: authHeaders,
155
288
  timeoutMs,
156
- retries,
157
289
  debug: this.debug
158
290
  });
159
- if (this.debug) {
160
- console.log("[BeLocal Engine] Node transport created with config:", {
161
- baseUrl,
162
- path,
163
- timeoutMs,
164
- retries
291
+ if (batchWindowMs > 0) {
292
+ this.transport = createBatchTransport({
293
+ baseTransport,
294
+ debug: this.debug,
295
+ batchWindowMs
296
+ });
297
+ if (this.debug) {
298
+ console.log("[BeLocal Engine] Batch transport created with config:", {
299
+ baseUrl,
300
+ path,
301
+ timeoutMs,
302
+ batchWindowMs
303
+ });
304
+ }
305
+ } else {
306
+ this.transport = createSingleTransport({
307
+ baseTransport,
308
+ debug: this.debug
165
309
  });
310
+ if (this.debug) {
311
+ console.log("[BeLocal Engine] Single transport created with config:", {
312
+ baseUrl,
313
+ path,
314
+ timeoutMs
315
+ });
316
+ }
166
317
  }
167
318
  }
168
319
  async t(text, lang, ctx) {
169
320
  const cacheKey = this.generateCacheKey(text, lang, ctx);
170
- if (this.isCacheAvailable) {
171
- const cachedResult = this.cache.get(cacheKey);
172
- if (cachedResult) {
173
- if (this.debug) {
174
- console.log("[BeLocal Engine] Translation from local cache:", text);
175
- }
176
- return cachedResult;
321
+ const cachedResult = this.cache.get(cacheKey);
322
+ if (cachedResult) {
323
+ if (this.debug) {
324
+ console.log("[BeLocal Engine] Translation from local cache:", text);
177
325
  }
326
+ return cachedResult;
178
327
  }
179
328
  const result = await this.transport({ text, lang, ctx });
180
- if (this.isCacheAvailable) {
181
- this.cache.set(cacheKey, result);
182
- if (this.debug) {
183
- console.log("[BeLocal Engine] Translation from API, cached in local:", text);
184
- }
185
- } else {
186
- if (this.debug) {
187
- console.log("[BeLocal Engine] Translation from API (no cache):", text);
188
- }
329
+ this.cache.set(cacheKey, result);
330
+ if (this.debug) {
331
+ console.log("[BeLocal Engine] Translation from API, cached in local:", text);
189
332
  }
190
333
  return result;
191
334
  }
@@ -199,6 +342,6 @@ var BelocalEngine = class {
199
342
  }
200
343
  };
201
344
 
202
- export { BelocalEngine, createNodeTransport };
345
+ export { BaseNodeTransport, BelocalEngine, createBaseNodeTransport, createBatchTransport, createSingleTransport };
203
346
  //# sourceMappingURL=node.mjs.map
204
347
  //# sourceMappingURL=node.mjs.map
package/dist/node.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/transports/node.ts","../src/cache/local.ts","../src/core/engine/node.ts"],"names":["session","headers"],"mappings":";;;;;AAcA,IAAM,YAAA,uBAAmB,GAAA,EAAsC;AAE/D,SAAS,kBAAA,CAAmB,SAAiB,KAAA,EAA2C;AACtF,EAAA,IAAI,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA,EAAG;AAC7B,IAAA,MAAMA,QAAAA,GAAU,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AACxC,IAAA,IAAI,CAACA,SAAQ,SAAA,EAAW;AACtB,MAAA,OAAOA,QAAAA;AAAA,IACT;AACA,IAAA,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,EAC7B;AAEA,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,OAAO,CAAA;AACjC,EAAA,MAAM,OAAA,GAAgB,KAAA,CAAA,OAAA,CAAQ,SAAA,CAAU,MAAM,CAAA;AAE9C,EAAA,OAAA,CAAQ,QAAQ,KAAA,EAAM;AAGtB,EAAA,OAAA,CAAQ,EAAA,CAAG,SAAS,MAAM;AACxB,IAAA,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,EAC7B,CAAC,CAAA;AAED,EAAA,OAAA,CAAQ,EAAA,CAAG,SAAS,MAAM;AACxB,IAAA,YAAA,CAAa,OAAO,OAAO,CAAA;AAAA,EAC7B,CAAC,CAAA;AAGD,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,OAAA,CAAQ,GAAG,SAAA,EAAW,MAAM,OAAA,CAAQ,GAAA,CAAI,4BAA4B,CAAC,CAAA;AACrE,IAAA,OAAA,CAAQ,EAAA;AAAA,MAAG,QAAA;AAAA,MAAU,CAAC,MAAM,YAAA,EAAc,MAAA,KACxC,QAAQ,GAAA,CAAI,aAAA,EAAe,MAAM,YAAY;AAAA,KAC/C;AAAA,EACF;AAEA,EAAA,YAAA,CAAa,GAAA,CAAI,SAAS,OAAO,CAAA;AACjC,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,gBAAA,CACP,OAAA,EACA,IAAA,EACA,OAAA,EACA,MACA,SAAA,EACgF;AAChF,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,GAAA,GAAM,QAAQ,OAAA,CAAQ;AAAA,MAC1B,SAAA,EAAW,MAAA;AAAA,MACX,OAAA,EAAS,IAAA;AAAA,MACT,cAAA,EAAgB,kBAAA;AAAA,MAChB,gBAAA,EAAkB,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAAA,MACxC,GAAG;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,OAAA,GAAiC,IAAA;AACrC,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAA,GAAU,WAAW,MAAM;AACzB,QAAA,GAAA,CAAI,OAAA,EAAQ;AACZ,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,SAAS,IAAI,CAAC,CAAA;AAAA,MAC1D,GAAG,SAAS,CAAA;AAAA,IACd;AAEA,IAAA,IAAI,YAAA,GAAe,EAAA;AACnB,IAAA,IAAI,UAAA,GAAa,CAAA;AACjB,IAAA,IAAI,kBAA0C,EAAC;AAE/C,IAAA,GAAA,CAAI,EAAA,CAAG,UAAA,EAAY,CAACC,QAAAA,KAAY;AAC9B,MAAA,UAAA,GAAaA,SAAQ,SAAS,CAAA;AAC9B,MAAA,eAAA,GAAkBA,QAAAA;AAAA,IACpB,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,MAAA,EAAQ,CAAC,KAAA,KAAU;AACxB,MAAA,YAAA,IAAgB,KAAA;AAAA,IAClB,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,OAAO,MAAM;AAClB,MAAA,IAAI,OAAA,eAAsB,OAAO,CAAA;AACjC,MAAA,OAAA,CAAQ;AAAA,QACN,UAAA;AAAA,QACA,OAAA,EAAS,eAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACP,CAAA;AAAA,IACH,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,EAAA,CAAG,OAAA,EAAS,CAAC,KAAA,KAAU;AACzB,MAAA,IAAI,OAAA,eAAsB,OAAO,CAAA;AACjC,MAAA,MAAA,CAAO,KAAK,CAAA;AAAA,IACd,CAAC,CAAA;AAED,IAAA,GAAA,CAAI,MAAM,IAAI,CAAA;AACd,IAAA,GAAA,CAAI,GAAA,EAAI;AAAA,EACV,CAAC,CAAA;AACH;AAEO,SAAS,oBAAoB,MAAA,EAAwC;AAC1E,EAAA,OAAO,OAAO,EAAE,IAAA,EAAM,IAAA,EAAM,KAAI,KAAM;AACpC,IAAA,MAAM,UAAA,GAAa,OAAO,OAAA,IAAW,CAAA;AACrC,IAAA,IAAI,OAAA,GAAU,CAAA;AAEd,IAAA,IAAI,OAAO,KAAA,EAAO;AAChB,MAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,sCAAA,EAAyC,IAAI,CAAA,KAAA,EAAQ,IAAI,CAAA,UAAA,EAAa,MAAA,CAAO,OAAO,CAAA,EAAG,MAAA,CAAO,IAAI,CAAA,CAAE,CAAA;AAAA,IAClH;AAEA,IAAA,OAAO,WAAW,UAAA,EAAY;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,MAAA,CAAO,OAAA,EAAS,OAAO,KAAK,CAAA;AAC/D,QAAA,MAAM,OAAO,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AAE/C,QAAA,MAAM,WAAW,MAAM,gBAAA;AAAA,UACrB,OAAA;AAAA,UACA,MAAA,CAAO,IAAA;AAAA,UACP,MAAA,CAAO,WAAW,EAAC;AAAA,UACnB,IAAA;AAAA,UACA,MAAA,CAAO;AAAA,SACT;AAEA,QAAA,IAAI,QAAA,CAAS,UAAA,GAAa,GAAA,IAAO,QAAA,CAAS,cAAc,GAAA,EAAK;AAC3D,UAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,UAAU,CAAA,gBAAA,CAAkB,CAAA;AAAA,QAC/D;AAEA,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,QAAA,CAAS,IAAI,CAAA;AACvC,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,kDAAA,EAAqD,MAAA,CAAO,IAAA,IAAQ,IAAI,CAAA,CAAA,CAAG,CAAA;AAAA,QACzF;AACA,QAAA,OAAO,OAAO,IAAA,IAAQ,IAAA;AAAA,MACxB,SAAS,KAAA,EAAO;AACd,QAAA,OAAA,EAAA;AACA,QAAA,IAAI,OAAO,KAAA,EAAO;AAChB,UAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,iCAAA,EAAoC,OAAO,CAAA,QAAA,CAAA,EAAY,KAAA,YAAiB,QAAQ,KAAA,CAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,QAC7H;AACA,QAAA,IAAI,UAAU,UAAA,EAAY;AACxB,UAAA,MAAM,KAAA;AAAA,QACR;AAEA,QAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAO,CAAA,GAAI,GAAI,CAAC,CAAA;AAAA,MAC/E;AAAA,IACF;AAEA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AACF;;;ACvJO,IAAM,aAAN,MAAkC;AAAA,EAAlC,WAAA,GAAA;AACL,IAAA,IAAA,CAAQ,OAAA,uBAAc,GAAA,EAAoB;AAAA,EAAA;AAAA,EAE1C,IAAI,GAAA,EAA4B;AAC9B,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,IAAA;AAAA,EAClC;AAAA,EAEA,GAAA,CAAI,KAAa,KAAA,EAAqB;AACpC,IAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,EAC7B;AAAA,EAEA,WAAA,GAAuB;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AACF,CAAA;ACVO,IAAM,gBAAN,MAAoB;AAAA,EAMzB,YAAY,OAAA,EAA+B;AACzC,IAAA,MAAM;AAAA,MACJ,MAAA;AAAA,MACA,OAAA,GAAU,6BAAA;AAAA,MACV,IAAA,GAAO,eAAA;AAAA,MACP,SAAA,GAAY,GAAA;AAAA,MACZ,OAAA,GAAU,CAAA;AAAA,MACV,KAAA,GAAQ;AAAA,KACV,GAAI,OAAA;AAEJ,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AAGb,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAI,UAAA,EAAW;AAC5B,IAAA,IAAA,CAAK,gBAAA,GAAmB,IAAA,CAAK,KAAA,CAAM,WAAA,EAAY;AAE/C,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAI,6CAA6C,CAAA;AAAA,IAC3D;AAEA,IAAA,MAAM,WAAA,GAAc;AAAA,MAClB,eAAA,EAAiB,UAAU,MAAM,CAAA;AAAA,KACnC;AAEA,IAAA,IAAA,CAAK,YAAY,mBAAA,CAAoB;AAAA,MACnC,OAAA;AAAA,MACA,IAAA;AAAA,MACA,OAAA,EAAS,WAAA;AAAA,MACT,SAAA;AAAA,MACA,OAAA;AAAA,MACA,OAAO,IAAA,CAAK;AAAA,KACb,CAAA;AAED,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,OAAA,CAAQ,IAAI,sDAAA,EAAwD;AAAA,QAClE,OAAA;AAAA,QACA,IAAA;AAAA,QACA,SAAA;AAAA,QACA;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAM,CAAA,CAAE,IAAA,EAAc,IAAA,EAAY,GAAA,EAA2B;AAE3D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,gBAAA,CAAiB,IAAA,EAAM,MAAM,GAAG,CAAA;AAGtD,IAAA,IAAI,KAAK,gBAAA,EAAkB;AACzB,MAAA,MAAM,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AAC5C,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,IAAI,KAAK,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,GAAA,CAAI,kDAAkD,IAAI,CAAA;AAAA,QACpE;AACA,QAAA,OAAO,YAAA;AAAA,MACT;AAAA,IACF;AAGA,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,IAAA,EAAM,KAAK,CAAA;AAGvD,IAAA,IAAI,KAAK,gBAAA,EAAkB;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,CAAI,QAAA,EAAU,MAAM,CAAA;AAC/B,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,GAAA,CAAI,2DAA2D,IAAI,CAAA;AAAA,MAC7E;AAAA,IACF,CAAA,MAAO;AACL,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,GAAA,CAAI,qDAAqD,IAAI,CAAA;AAAA,MACvE;AAAA,IACF;AAEA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEQ,gBAAA,CAAiB,IAAA,EAAc,IAAA,EAAY,GAAA,EAAkB;AACnE,IAAA,MAAM,IAAA,GAAO;AAAA,MACX,IAAA;AAAA,MACA,IAAA;AAAA,MACA,KAAK,GAAA,IAAO;AAAA,KACd;AACA,IAAA,OAAO,GAAA,CAAI,IAAA,CAAK,SAAA,CAAU,IAAI,CAAC,CAAA;AAAA,EACjC;AACF","file":"node.mjs","sourcesContent":["import * as http2 from 'node:http2';\nimport { URL } from 'node:url';\nimport type { Transport } from '../core/types';\n\nexport interface NodeTransportConfig {\n baseUrl: string;\n path: 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('[H2] new session connected'));\n session.on('goaway', (code, lastStreamID, opaque) =>\n console.log('[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 function createNodeTransport(config: NodeTransportConfig): Transport {\n return async ({ text, lang, ctx }) => {\n const maxRetries = config.retries || 0;\n let attempt = 0;\n\n if (config.debug) {\n console.log(`[BeLocal Node Transport] Translating \"${text}\" to ${lang} with url ${config.baseUrl}${config.path}`);\n }\n\n while (attempt <= maxRetries) {\n try {\n const session = getOrCreateSession(config.baseUrl, config.debug);\n const body = JSON.stringify({ text, lang, ctx });\n \n const response = await makeHttp2Request(\n session,\n config.path,\n config.headers || {},\n body,\n config.timeoutMs\n );\n\n if (response.statusCode < 200 || response.statusCode >= 300) {\n throw new Error(`HTTP ${response.statusCode}: Request failed`);\n }\n\n const result = JSON.parse(response.body);\n if (config.debug) {\n console.log(`[BeLocal Node Transport] Translation successful: \"${result.text || text}\"`);\n }\n return result.text || text;\n } catch (error) {\n attempt++;\n if (config.debug) {\n console.error(`[BeLocal Node Transport] Attempt ${attempt} failed:`, error instanceof Error ? error.message : String(error));\n }\n if (attempt > maxRetries) {\n throw error;\n }\n\n await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));\n }\n }\n\n return text;\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 { createNodeTransport } from '../../transports/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 private isCacheAvailable: boolean;\n\n constructor(options: BelocalEngineOptions) {\n const {\n apiKey,\n baseUrl = 'https://dynamic.belocal.dev',\n path = '/v1/translate',\n timeoutMs = 10000,\n retries = 3,\n debug = false\n } = options;\n\n this.debug = debug;\n \n // Use local cache for Node.js\n this.cache = new LocalCache();\n this.isCacheAvailable = this.cache.isAvailable();\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 this.transport = createNodeTransport({\n baseUrl,\n path,\n headers: authHeaders,\n timeoutMs,\n retries,\n debug: this.debug\n });\n\n if (this.debug) {\n console.log('[BeLocal Engine] Node transport created with config:', {\n baseUrl,\n path,\n timeoutMs,\n retries\n });\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, lang, ctx);\n \n // Try to get from cache first\n if (this.isCacheAvailable) {\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\n // Cache miss, get translation from transport\n const result = await this.transport({ text, lang, ctx });\n \n // Store in cache\n if (this.isCacheAvailable) {\n this.cache.set(cacheKey, result);\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 (no cache):', text);\n }\n }\n\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\n };\n return md5(JSON.stringify(data));\n }\n}\n\n// Re-export types and transport\nexport type { BelocalEngineOptions, Lang, KV } from '../types';\nexport { createNodeTransport } from '../../transports/node';\n"]}
1
+ {"version":3,"sources":["../src/transports/batch.ts","../src/transports/single.ts","../src/transports/base/node.ts","../src/cache/local.ts","../src/core/engine/node.ts"],"names":["session","headers","md5"],"mappings":"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","file":"node.mjs","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; ctx?: Record<string, unknown> };\n}\n\ninterface BatchRequestItem {\n requestId: string;\n payload: { text: string; lang: string; ctx?: Record<string, unknown> };\n resolve: (value: string) => void;\n reject: (error: Error) => void;\n}\n\ninterface BatchResponse {\n results: Array<{\n requestId: string;\n data?: { text: 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, ctx?: Record<string, unknown>): string {\n const data = {\n text,\n lang,\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 });\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 }; 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 item.resolve(result.data.text);\n } else {\n // Фоллбэк: если нет ни data, ни error, возвращаем оригинальный текст\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(item.payload.text);\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, ctx }) => {\n return new Promise<string>((resolve, reject) => {\n const requestId = generateRequestId(text, 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, 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}\n\nexport function createSingleTransport(config: SingleTransportConfig): Transport {\n return async ({ text, 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, ctx });\n \n if (config.debug) {\n console.log(`[BeLocal Single Transport] Translation successful: \"${result.text || text}\"`);\n }\n \n return result.text || text;\n } catch (error) {\n if (config.debug) {\n console.error(`[BeLocal Single Transport] Request failed:`, error);\n }\n throw error;\n }\n };\n}\n","import * as http2 from 'node:http2';\nimport { URL } from 'node:url';\nimport type { BaseTransport } from '../../core/types';\n\nexport interface BaseNodeTransportConfig {\n baseUrl: string;\n path?: 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): Promise<any> {\n const maxRetries = this.config.retries || 0;\n let attempt = 0;\n const url = `${this.config.baseUrl}${this.config.path || ''}`;\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 const response = await makeHttp2Request(\n session,\n this.config.path || '/',\n this.config.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 path = '/v1/translate',\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 path,\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 path,\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 path,\n timeoutMs\n });\n }\n }\n }\n\n async t(text: string, lang: Lang, ctx?: KV): Promise<string> {\n // Generate cache key from parameters\n const cacheKey = this.generateCacheKey(text, 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, ctx });\n \n // Store in cache\n this.cache.set(cacheKey, result);\n if (this.debug) {\n console.log('[BeLocal Engine] Translation from API, cached in local:', text);\n }\n return result;\n }\n\n private generateCacheKey(text: string, lang: Lang, ctx?: KV): string {\n const data = {\n text,\n lang,\n ctx: ctx || null\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"]}
package/package.json CHANGED
@@ -1,16 +1,20 @@
1
1
  {
2
2
  "name": "@belocal/js-sdk",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "BeLocal runtime JS SDK for on-demand translation (browser + node)",
5
5
  "scripts": {
6
6
  "test": "vitest run",
7
7
  "test:watch": "vitest",
8
+ "test:unit": "docker compose run --rm unit-tests",
9
+ "test:browser": "docker compose run --rm browser-tests",
10
+ "test:node": "docker compose run --rm node-tests",
11
+ "test:all": "npm run test:unit && npm run test:browser && npm run test:node",
8
12
  "build": "tsup",
9
13
  "clean": "rimraf dist",
10
14
  "dev": "tsup --watch",
11
15
  "typecheck": "tsc --noEmit",
12
16
  "prepare": "npm run build",
13
- "prepublishOnly": "npm run test && npm run build"
17
+ "prepublishOnly": "npm run build"
14
18
  },
15
19
  "repository": {
16
20
  "type": "git",
@@ -28,6 +32,7 @@
28
32
  "@types/js-md5": "^0.8.0",
29
33
  "@types/node": "^24.5.2",
30
34
  "jsdom": "^27.0.0",
35
+ "rimraf": "^6.0.1",
31
36
  "tsup": "^8.5.0",
32
37
  "typescript": "^5.9.2",
33
38
  "vitest": "^3.2.4"