@belocal/js-sdk 0.2.1 → 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 +2 -2
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +25 -4
- package/dist/browser.mjs +2 -2
- package/dist/browser.mjs.map +1 -1
- package/dist/node.cjs +195 -49
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +26 -6
- package/dist/node.mjs +192 -49
- package/dist/node.mjs.map +1 -1
- package/package.json +13 -8
package/dist/browser.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var jsMd5=require('js-md5');function
|
|
2
|
-
exports.BelocalEngine=u;exports.
|
|
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
|
package/dist/browser.cjs.map
CHANGED
|
@@ -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
|
|
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
|
|
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,
|
|
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
|
|
2
|
-
export{
|
|
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
|
package/dist/browser.mjs.map
CHANGED
|
@@ -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/
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
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
|
-
|
|
103
|
-
|
|
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(
|
|
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
|
-
|
|
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(`[
|
|
251
|
+
if (this.config.debug) {
|
|
252
|
+
console.log(`[Base Node Transport] Request successful:`, result);
|
|
122
253
|
}
|
|
123
|
-
return result
|
|
254
|
+
return result;
|
|
124
255
|
} catch (error) {
|
|
125
256
|
attempt++;
|
|
126
|
-
if (config.debug) {
|
|
127
|
-
console.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
|
-
|
|
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
|
-
|
|
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 (
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
if (
|
|
195
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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.
|
|
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
|
|
20
|
+
interface BaseNodeTransportConfig {
|
|
18
21
|
baseUrl: string;
|
|
19
|
-
path
|
|
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
|
|
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,
|
|
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/
|
|
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
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
81
|
-
|
|
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(
|
|
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
|
-
|
|
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(`[
|
|
229
|
+
if (this.config.debug) {
|
|
230
|
+
console.log(`[Base Node Transport] Request successful:`, result);
|
|
100
231
|
}
|
|
101
|
-
return result
|
|
232
|
+
return result;
|
|
102
233
|
} catch (error) {
|
|
103
234
|
attempt++;
|
|
104
|
-
if (config.debug) {
|
|
105
|
-
console.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
|
-
|
|
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
|
-
|
|
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 (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
if (
|
|
173
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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,
|
|
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":"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","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.
|
|
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
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
14
18
|
},
|
|
15
19
|
"repository": {
|
|
16
20
|
"type": "git",
|
|
@@ -28,13 +32,14 @@
|
|
|
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"
|
|
34
39
|
},
|
|
35
|
-
"main": "./dist/
|
|
36
|
-
"module": "./dist/
|
|
37
|
-
"types": "./dist/
|
|
40
|
+
"main": "./dist/node.cjs",
|
|
41
|
+
"module": "./dist/node.mjs",
|
|
42
|
+
"types": "./dist/node.d.ts",
|
|
38
43
|
"exports": {
|
|
39
44
|
".": {
|
|
40
45
|
"browser": {
|
|
@@ -47,10 +52,10 @@
|
|
|
47
52
|
"import": "./dist/node.mjs",
|
|
48
53
|
"require": "./dist/node.cjs"
|
|
49
54
|
},
|
|
50
|
-
"types": "./dist/
|
|
51
|
-
"import": "./dist/
|
|
55
|
+
"types": "./dist/node.d.ts",
|
|
56
|
+
"import": "./dist/node.mjs",
|
|
52
57
|
"require": "./dist/node.cjs",
|
|
53
|
-
"default": "./dist/
|
|
58
|
+
"default": "./dist/node.mjs"
|
|
54
59
|
}
|
|
55
60
|
},
|
|
56
61
|
"sideEffects": false,
|