@smartcorehub/localization-sdk 1.0.5412 → 1.0.5484

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/index.d.mts CHANGED
@@ -52,6 +52,37 @@ interface LocalizationClientOptions {
52
52
  readonly enableLogs?: boolean;
53
53
  }
54
54
 
55
+ interface LocalizationKeyEntry {
56
+ resourceKey: string;
57
+ translations: Readonly<Record<string, string | LocalizationTranslationInput>>;
58
+ sourceFileName?: string;
59
+ valueFormat?: number;
60
+ }
61
+ interface LocalizationTranslationInput {
62
+ suggestedValue: string;
63
+ description?: string;
64
+ }
65
+ interface LocalizationKeySubmissionRequest {
66
+ authorName?: string;
67
+ authorEmail?: string;
68
+ keys: readonly LocalizationKeyEntry[];
69
+ }
70
+ interface SubmitKeysResult {
71
+ success: boolean;
72
+ statusCode: number;
73
+ acceptedCount: number;
74
+ versionId: number;
75
+ environment: number;
76
+ message?: string;
77
+ errors: readonly string[];
78
+ rejectedKeys: readonly RejectedSubmitKey[];
79
+ }
80
+ interface RejectedSubmitKey {
81
+ resourceKey: string;
82
+ languageKey: string;
83
+ reason: string;
84
+ }
85
+
55
86
  interface LocalizationListResource {
56
87
  readonly key: string;
57
88
  readonly value: string;
@@ -68,6 +99,9 @@ interface LocalizationClient {
68
99
  listResources(): Promise<readonly LocalizationListResource[]>;
69
100
  invalidateCache(key?: string): Promise<void>;
70
101
  clearCache(): Promise<void>;
102
+ submitKey(resourceKey: string, languageKey: string, suggestedValue: string, description?: string, sourceFileName?: string): Promise<SubmitKeysResult>;
103
+ submitKeyWithTranslations(resourceKey: string, translations: Readonly<Record<string, string | LocalizationTranslationInput>>, sourceFileName?: string): Promise<SubmitKeysResult>;
104
+ submitKeys(request: LocalizationKeySubmissionRequest): Promise<SubmitKeysResult>;
71
105
  }
72
106
 
73
107
  declare function createLocalizationClient(options: LocalizationClientOptions): LocalizationClient;
@@ -159,9 +193,12 @@ declare class LocalizationService {
159
193
  listResources(): Observable<readonly LocalizationListResource[]>;
160
194
  invalidateCache(key?: string): Observable<void>;
161
195
  clearCache(): Observable<void>;
196
+ submitKey(resourceKey: string, languageKey: string, suggestedValue: string, description?: string, sourceFileName?: string): Observable<SubmitKeysResult>;
197
+ submitKeyWithTranslations(resourceKey: string, translations: Readonly<Record<string, string | LocalizationTranslationInput>>, sourceFileName?: string): Observable<SubmitKeysResult>;
198
+ submitKeys(request: LocalizationKeySubmissionRequest): Observable<SubmitKeysResult>;
162
199
  }
163
200
 
164
201
  declare const LOCALIZATION_SDK_OPTIONS: InjectionToken<LocalizationClientOptions>;
165
202
  declare const LOCALIZATION_CLIENT: InjectionToken<LocalizationClient>;
166
203
 
167
- export { type AuthProvider, type CacheProvider, FetchHttpTransport, type HttpRequest, type HttpResponse, type HttpTransport, LOCALIZATION_CLIENT, LOCALIZATION_SDK_OPTIONS, LocalStorageCacheProvider, LocalizationAuthError, type LocalizationClient, type LocalizationClientOptions, LocalizationError, type LocalizationListResource, LocalizationNetworkError, LocalizationServerError, LocalizationService, LocalizationTimeoutError, MemoryCacheProvider, ResourceNotFoundError, type ResourceResponse, type SDKMiddleware, SessionStorageCacheProvider, StorageCacheProvider, XAuthTokenProvider, createLocalizationClient, provideLocalization };
204
+ export { type AuthProvider, type CacheProvider, FetchHttpTransport, type HttpRequest, type HttpResponse, type HttpTransport, LOCALIZATION_CLIENT, LOCALIZATION_SDK_OPTIONS, LocalStorageCacheProvider, LocalizationAuthError, type LocalizationClient, type LocalizationClientOptions, LocalizationError, type LocalizationKeyEntry, type LocalizationKeySubmissionRequest, type LocalizationListResource, LocalizationNetworkError, LocalizationServerError, LocalizationService, LocalizationTimeoutError, type LocalizationTranslationInput, MemoryCacheProvider, type RejectedSubmitKey, ResourceNotFoundError, type ResourceResponse, type SDKMiddleware, SessionStorageCacheProvider, StorageCacheProvider, type SubmitKeysResult, XAuthTokenProvider, createLocalizationClient, provideLocalization };
package/dist/index.d.ts CHANGED
@@ -52,6 +52,37 @@ interface LocalizationClientOptions {
52
52
  readonly enableLogs?: boolean;
53
53
  }
54
54
 
55
+ interface LocalizationKeyEntry {
56
+ resourceKey: string;
57
+ translations: Readonly<Record<string, string | LocalizationTranslationInput>>;
58
+ sourceFileName?: string;
59
+ valueFormat?: number;
60
+ }
61
+ interface LocalizationTranslationInput {
62
+ suggestedValue: string;
63
+ description?: string;
64
+ }
65
+ interface LocalizationKeySubmissionRequest {
66
+ authorName?: string;
67
+ authorEmail?: string;
68
+ keys: readonly LocalizationKeyEntry[];
69
+ }
70
+ interface SubmitKeysResult {
71
+ success: boolean;
72
+ statusCode: number;
73
+ acceptedCount: number;
74
+ versionId: number;
75
+ environment: number;
76
+ message?: string;
77
+ errors: readonly string[];
78
+ rejectedKeys: readonly RejectedSubmitKey[];
79
+ }
80
+ interface RejectedSubmitKey {
81
+ resourceKey: string;
82
+ languageKey: string;
83
+ reason: string;
84
+ }
85
+
55
86
  interface LocalizationListResource {
56
87
  readonly key: string;
57
88
  readonly value: string;
@@ -68,6 +99,9 @@ interface LocalizationClient {
68
99
  listResources(): Promise<readonly LocalizationListResource[]>;
69
100
  invalidateCache(key?: string): Promise<void>;
70
101
  clearCache(): Promise<void>;
102
+ submitKey(resourceKey: string, languageKey: string, suggestedValue: string, description?: string, sourceFileName?: string): Promise<SubmitKeysResult>;
103
+ submitKeyWithTranslations(resourceKey: string, translations: Readonly<Record<string, string | LocalizationTranslationInput>>, sourceFileName?: string): Promise<SubmitKeysResult>;
104
+ submitKeys(request: LocalizationKeySubmissionRequest): Promise<SubmitKeysResult>;
71
105
  }
72
106
 
73
107
  declare function createLocalizationClient(options: LocalizationClientOptions): LocalizationClient;
@@ -159,9 +193,12 @@ declare class LocalizationService {
159
193
  listResources(): Observable<readonly LocalizationListResource[]>;
160
194
  invalidateCache(key?: string): Observable<void>;
161
195
  clearCache(): Observable<void>;
196
+ submitKey(resourceKey: string, languageKey: string, suggestedValue: string, description?: string, sourceFileName?: string): Observable<SubmitKeysResult>;
197
+ submitKeyWithTranslations(resourceKey: string, translations: Readonly<Record<string, string | LocalizationTranslationInput>>, sourceFileName?: string): Observable<SubmitKeysResult>;
198
+ submitKeys(request: LocalizationKeySubmissionRequest): Observable<SubmitKeysResult>;
162
199
  }
163
200
 
164
201
  declare const LOCALIZATION_SDK_OPTIONS: InjectionToken<LocalizationClientOptions>;
165
202
  declare const LOCALIZATION_CLIENT: InjectionToken<LocalizationClient>;
166
203
 
167
- export { type AuthProvider, type CacheProvider, FetchHttpTransport, type HttpRequest, type HttpResponse, type HttpTransport, LOCALIZATION_CLIENT, LOCALIZATION_SDK_OPTIONS, LocalStorageCacheProvider, LocalizationAuthError, type LocalizationClient, type LocalizationClientOptions, LocalizationError, type LocalizationListResource, LocalizationNetworkError, LocalizationServerError, LocalizationService, LocalizationTimeoutError, MemoryCacheProvider, ResourceNotFoundError, type ResourceResponse, type SDKMiddleware, SessionStorageCacheProvider, StorageCacheProvider, XAuthTokenProvider, createLocalizationClient, provideLocalization };
204
+ export { type AuthProvider, type CacheProvider, FetchHttpTransport, type HttpRequest, type HttpResponse, type HttpTransport, LOCALIZATION_CLIENT, LOCALIZATION_SDK_OPTIONS, LocalStorageCacheProvider, LocalizationAuthError, type LocalizationClient, type LocalizationClientOptions, LocalizationError, type LocalizationKeyEntry, type LocalizationKeySubmissionRequest, type LocalizationListResource, LocalizationNetworkError, LocalizationServerError, LocalizationService, LocalizationTimeoutError, type LocalizationTranslationInput, MemoryCacheProvider, type RejectedSubmitKey, ResourceNotFoundError, type ResourceResponse, type SDKMiddleware, SessionStorageCacheProvider, StorageCacheProvider, type SubmitKeysResult, XAuthTokenProvider, createLocalizationClient, provideLocalization };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var core=require('@angular/core'),rxjs=require('rxjs');var S=(o,e,r,t)=>{for(var i=e,n=o.length-1,s;n>=0;n--)(s=o[n])&&(i=(s(i))||i);return i},k=(o,e)=>(r,t)=>e(r,t,o);var u=class{constructor(e){this.token=e;}getToken(){return Promise.resolve(this.token?.trim()?this.token:null)}};var d=class{constructor(){this.store=new Map;}get(e){let r=this.store.get(e);return r?r.expiresAt!==void 0&&Date.now()>r.expiresAt?(this.store.delete(e),Promise.resolve(null)):Promise.resolve(r.value):Promise.resolve(null)}set(e,r,t){let i=t&&t>0?Date.now()+t:void 0;return this.store.set(e,{value:r,expiresAt:i}),Promise.resolve()}delete(e){return this.store.delete(e),Promise.resolve()}clear(){return this.store.clear(),Promise.resolve()}};var a=class extends Error{constructor(r,t){super(r);this.metadata=t;this.name="LocalizationError";}},h=class extends a{constructor(e="Authentication failed",r){super(e,r),this.name="LocalizationAuthError";}},p=class extends a{constructor(e="Resource not found",r){super(e,r),this.name="ResourceNotFoundError";}},g=class extends a{constructor(e="Localization server error",r){super(e,r),this.name="LocalizationServerError";}},m=class extends a{constructor(e="Network error while contacting localization API",r){super(e,r),this.name="LocalizationNetworkError";}},f=class extends a{constructor(e="Localization request timeout",r){super(e,r),this.name="LocalizationTimeoutError";}};var v=class extends Error{constructor(r,t,i){super(`Request failed with status ${r}`);this.statusCode=r;this.responseBody=t;this.responseHeaders=i;this.name="HttpStatusError";}},L=class extends Error{constructor(r){super(`Request timed out after ${r}ms`);this.timeoutMs=r;this.name="HttpTimeoutError";}},c=class extends Error{constructor(r){super("Network error while sending request");this.causeError=r;this.name="HttpNetworkError";}},y=class{constructor(e){this.options=e;this.fetchFn=e.fetchFn??globalThis.fetch.bind(globalThis);}async request(e){let r=e.timeoutMs??this.options.timeoutMs,t=new AbortController,i=setTimeout(()=>t.abort(),r),n=new Request(this.resolveUrl(e),{method:e.method,headers:{"Content-Type":"application/json",...this.options.defaultHeaders,...e.headers},body:e.body===void 0?void 0:JSON.stringify(e.body),signal:t.signal});try{let s=await this.runRequestMiddleware(n),$;try{$=await this.fetchFn(s);}catch(P){throw this.isAbortError(P)?new L(r):new c(P)}let l=await this.runResponseMiddleware($);if(!l.ok){let P=await l.text();throw new v(l.status,P,l.headers)}let D=await this.parseResponse(l);return {status:l.status,headers:l.headers,data:D}}catch(s){throw await this.runErrorMiddleware(this.toError(s)),s}finally{clearTimeout(i);}}resolveUrl(e){let r=new URL(e.path,this.options.baseUrl);return e.query&&Object.entries(e.query).forEach(([t,i])=>{i!==void 0&&r.searchParams.set(t,String(i));}),r.toString()}runRequestMiddleware(e){return (this.options.middleware??[]).reduce(async(t,i)=>{let n=await t;return i.onRequest?i.onRequest(n):n},Promise.resolve(e))}runResponseMiddleware(e){return (this.options.middleware??[]).reduce(async(t,i)=>{let n=await t;return i.onResponse?i.onResponse(n):n},Promise.resolve(e))}async runErrorMiddleware(e){let r=(this.options.middleware??[]).map(t=>t.onError).filter(t=>!!t);await Promise.all(r.map(t=>t(e)));}async parseResponse(e){return e.status===204?null:(e.headers.get("content-type")??"").includes("application/json")?await e.json():await e.text()}toError(e){return e instanceof Error?e:new Error("Unknown request error")}isAbortError(e){return e instanceof DOMException&&e.name==="AbortError"}};var M="localization:listResources",T=class{constructor(e,r,t){this.cacheProvider=e;this.cacheTtlMs=r;this.logger=t;}async getListResources(){this.logger.debug(`listResources:start cacheEnabled=${!!this.cacheProvider}`);let e=await this.cacheProvider?.get(M);return e?this.logger.info(`listResources:cache-hit count=${e.length}`):this.logger.debug("listResources:cache-miss"),e}async storeListResources(e){await this.cacheProvider?.set(M,e,this.cacheTtlMs),this.logger.debug(`listResources:cache-store ttlMs=${this.cacheTtlMs??0} count=${e.length}`);}async invalidate(e){if(this.logger.debug(`invalidateCache:start scope=${e??"all"}`),!this.cacheProvider){this.logger.debug("invalidateCache:skipped no-cache-provider");return}if(e){await this.cacheProvider.delete(e),this.logger.info(`invalidateCache:deleted key=${e}`);return}await this.cacheProvider.clear(),this.logger.info("invalidateCache:cleared-all");}};var R=class{constructor(e){this.logger=e;}async run(e,r){try{return await r()}catch(t){let i=this.map(t);throw this.logger.errorForOperation(e,i,t),i}}validateRequired(e,r){if(!e?.trim())throw new a(`${r} is required`)}map(e){return e instanceof a?e:e instanceof L?new f(e.message):e instanceof c?new m(e.message):e instanceof v?this.mapStatusError(e):new a("Unexpected localization SDK error")}preserveCause(e){let r=this.map(e);return r.cause??(r.cause=e),r}mapStatusError(e){return e.statusCode===401||e.statusCode===403?new h("Invalid token for localization endpoint",{statusCode:e.statusCode}):e.statusCode===404?new p("Localization resource was not found",{statusCode:e.statusCode}):e.statusCode>=500?new g("Localization API is unavailable",{statusCode:e.statusCode}):new a(e.message,{statusCode:e.statusCode})}};var K="[LocalizationSdk]",z=class{constructor(e=false){this.enabled=e;}debug(e){this.write("debug",e);}info(e){this.write("info",e);}errorForOperation(e,r,t){this.write("error",`${e}:error ${this.formatErrorDetails(r,t)}`);}formatErrorDetails(e,r){let t=this.getOriginalCause(e,r),i=this.getErrorMessage(t),n=[`type=${e.name}`,`message=${e.message}`];return i&&i!==e.message&&n.push(`original=${i}`),e instanceof a&&e.metadata?.statusCode&&n.push(`statusCode=${e.metadata.statusCode}`),n.join(" ")}getOriginalCause(e,r){let i=e.cause??r;return i instanceof c?i.causeError:i}getErrorMessage(e){return e instanceof Error?e.message:typeof e=="string"?e:"unknown-error"}write(e,r){if(!this.enabled)return;let t=this.resolveIcon(e,r),i=`${K} ${t} ${r}`;switch(e){case "debug":console.debug(i);break;case "info":console.info(i);break;case "error":console.error(i);break}}resolveIcon(e,r){return e==="error"||r.includes(":error")?"\u274C":r.includes("request:start")||r.includes(":api-call")?"\u{1F310}":r.includes("request:success")?"\u{1F4E1}":r.includes(":cache-hit")||r.includes("cache-hit")?"\u{1F5C4}\uFE0F":r.includes("cache-miss")?"\u{1F4ED}":r.includes("cache-store")?"\u{1F4BE}":r.includes("invalidateCache")?"\u{1F9F9}":r.includes("listResources")?"\u{1F4DA}":r.includes("getByLanguage")?"\u{1F30D}":r.includes("getCurrentLanguage")?"\u{1F22F}":r.includes(":start")?"\u{1F680}":r.includes(":success")?"\u2705":e==="info"?"\u2139\uFE0F":"\u{1F50E}"}};var x=class{constructor(e){this.dependencies=e;this.logger=new z(e.enableLogs),this.cacheHelper=new T(e.cacheProvider,e.cacheTtlMs,this.logger),this.errorHandler=new R(this.logger);}async getCurrentLanguage(e,r){return this.errorHandler.run("getCurrentLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.logger.debug(`getCurrentLanguage:start resourceKey=${e}`),this.isCacheEnabled()){let i=await this.resolveFromCachedResources(e);return this.logger.info(`getCurrentLanguage:cache-${i?"hit":"miss"} resourceKey=${e} hasValue=${!!i}`),i}this.logger.info(`getCurrentLanguage:api-call path=api/localization/client/currentlanguage resourceKey=${e}`);let t=await this.send({method:"GET",path:"api/localization/client/currentlanguage",query:{resourceKey:e},headers:this.resolveLocaleHeader(r)});return this.logger.info(`getCurrentLanguage:success resourceKey=${e} hasValue=${!!t}`),t??""})}async getByLanguage(e,r,t){return this.errorHandler.run("getByLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.errorHandler.validateRequired(r,"languageKey"),this.logger.debug(`getByLanguage:start resourceKey=${e} languageKey=${r}`),this.isCacheEnabled()){let n=await this.resolveFromCachedResources(e,r);return this.logger.info(`getByLanguage:cache-${n?"hit":"miss"} resourceKey=${e} languageKey=${r} hasValue=${!!n}`),n}this.logger.info(`getByLanguage:api-call path=api/localization/client/bylanguage resourceKey=${e} languageKey=${r}`);let i=await this.send({method:"GET",path:"api/localization/client/bylanguage",query:{resourceKey:e,languageKey:r},headers:this.resolveLocaleHeader(t)});return this.logger.info(`getByLanguage:success resourceKey=${e} languageKey=${r} hasValue=${!!i}`),i??""})}async listResources(){return this.errorHandler.run("listResources",async()=>{if(this.isCacheEnabled()){let t=await this.cacheHelper.getListResources();if(t)return this.logger.info(`listResources:cache-hit-return count=${t.length}`),t}else this.logger.debug("listResources:cache-disabled");this.logger.info("listResources:api-call path=api/localization/client/list");let r=(await this.send({method:"GET",path:"api/localization/client/list"})??[]).map(t=>({key:t.resourceKey,value:t.value,language:t.languageKey}));return this.isCacheEnabled()&&await this.cacheHelper.storeListResources(r),this.logger.info(`listResources:success count=${r.length}`),r})}async invalidateCache(e){return this.errorHandler.run("invalidateCache",async()=>this.cacheHelper.invalidate(e))}async clearCache(){return this.errorHandler.run("clearCache",async()=>this.cacheHelper.invalidate())}async resolveFromCachedResources(e,r){return (await this.listResources()).find(n=>n.key!==e?false:r===void 0?true:n.language===r)?.value??""}async send(e){try{let r=await this.dependencies.authProvider?.getToken(),t=r?{...e.headers,"X-Auth-Token":r}:e.headers;this.logger.debug(`request:start method=${e.method} path=${e.path} hasAuth=${!!r}`);let i=await this.dependencies.httpTransport.request({...e,headers:t});return this.logger.debug(`request:success method=${e.method} path=${e.path} status=${i.status}`),i.data}catch(r){throw this.errorHandler.preserveCause(r)}}resolveLocaleHeader(e){let r=e?.locale?.trim()||this.dependencies.locale?.trim()||this.resolveBrowserLocale();if(r)return {"Accept-Language":r}}resolveBrowserLocale(){return globalThis.navigator?.language?.trim()||void 0}isCacheEnabled(){if(this.dependencies.cacheEnabled!==void 0)return this.logger.debug(`isCacheEnabled: enabled=${this.dependencies.cacheEnabled} source=cacheEnabled-flag`),this.dependencies.cacheEnabled;let e=!!this.dependencies.cacheProvider;return this.logger.debug(`isCacheEnabled: enabled=${e} source=cacheProvider`),e}};function O(o){_(o);let e=o.cache?.enabled??false,r=e?o.cache?.provider??new d:void 0,t=new y({baseUrl:o.baseUrl,fetchFn:o.fetchFn,timeoutMs:o.timeoutMs??1e4,defaultHeaders:o.headers,middleware:o.middleware});return new x({httpTransport:t,authProvider:o.authProvider??(o.token?new u(o.token):void 0),locale:o.locale,cacheEnabled:e,cacheProvider:r,cacheTtlMs:o.cache?.ttlMs,enableLogs:o.enableLogs??false})}function _(o){if(!o?.baseUrl?.trim())throw new a("baseUrl is required to create localization client")}var w=class{constructor(e){this.storage=e;}get(e){let r=this.storage.getItem(e);if(!r)return Promise.resolve(null);let t=this.safeParse(r);return t?t.expiresAt!==void 0&&Date.now()>t.expiresAt?(this.storage.removeItem(e),Promise.resolve(null)):Promise.resolve(t.value):(this.storage.removeItem(e),Promise.resolve(null))}set(e,r,t){let i=t&&t>0?Date.now()+t:void 0,n={value:r,expiresAt:i};return this.storage.setItem(e,JSON.stringify(n)),Promise.resolve()}delete(e){return this.storage.removeItem(e),Promise.resolve()}clear(){return this.storage.clear(),Promise.resolve()}safeParse(e){try{return JSON.parse(e)}catch{return null}}},A=class extends w{constructor(){super(N("localStorage"));}},H=class extends w{constructor(){super(N("sessionStorage"));}};function N(o){let e=globalThis.window===void 0?void 0:globalThis.window[o];return e||U()}function U(){let o=new Map;return {get length(){return o.size},clear:()=>{o.clear();},getItem:e=>o.get(e)??null,key:e=>Array.from(o.keys())[e]??null,removeItem:e=>{o.delete(e);},setItem:(e,r)=>{o.set(e,r);}}}var I=new core.InjectionToken("LOCALIZATION_SDK_OPTIONS"),C=new core.InjectionToken("LOCALIZATION_CLIENT");function Z(o){return core.makeEnvironmentProviders([{provide:I,useValue:o},{provide:C,useFactory:()=>O(o)}])}exports.LocalizationService=class E{constructor(e){this.client=e;}getCurrentLanguage(e){return rxjs.from(this.client.getCurrentLanguage(e))}getByLanguage(e,r){return rxjs.from(this.client.getByLanguage(e,r))}listResources(){return rxjs.from(this.client.listResources())}invalidateCache(e){return rxjs.from(this.client.invalidateCache(e))}clearCache(){return rxjs.from(this.client.clearCache())}};exports.LocalizationService=S([core.Injectable({providedIn:"root"}),k(0,core.Inject(C))],exports.LocalizationService);exports.FetchHttpTransport=y;exports.LOCALIZATION_CLIENT=C;exports.LOCALIZATION_SDK_OPTIONS=I;exports.LocalStorageCacheProvider=A;exports.LocalizationAuthError=h;exports.LocalizationError=a;exports.LocalizationNetworkError=m;exports.LocalizationServerError=g;exports.LocalizationTimeoutError=f;exports.MemoryCacheProvider=d;exports.ResourceNotFoundError=p;exports.SessionStorageCacheProvider=H;exports.StorageCacheProvider=w;exports.XAuthTokenProvider=u;exports.createLocalizationClient=O;exports.provideLocalization=Z;
1
+ 'use strict';var core=require('@angular/core'),rxjs=require('rxjs');var H=(i,e,r,t)=>{for(var o=e,n=i.length-1,a;n>=0;n--)(a=i[n])&&(o=(a(o))||o);return o},k=(i,e)=>(r,t)=>e(r,t,i);var h=class{constructor(e){this.token=e;}getToken(){return Promise.resolve(this.token?.trim()?this.token:null)}};var g=class{constructor(){this.store=new Map;}get(e){let r=this.store.get(e);return r?r.expiresAt!==void 0&&Date.now()>r.expiresAt?(this.store.delete(e),Promise.resolve(null)):Promise.resolve(r.value):Promise.resolve(null)}set(e,r,t){let o=t&&t>0?Date.now()+t:void 0;return this.store.set(e,{value:r,expiresAt:o}),Promise.resolve()}delete(e){return this.store.delete(e),Promise.resolve()}clear(){return this.store.clear(),Promise.resolve()}};var s=class extends Error{constructor(r,t){super(r);this.metadata=t;this.name="LocalizationError";}},m=class extends s{constructor(e="Authentication failed",r){super(e,r),this.name="LocalizationAuthError";}},p=class extends s{constructor(e="Resource not found",r){super(e,r),this.name="ResourceNotFoundError";}},f=class extends s{constructor(e="Localization server error",r){super(e,r),this.name="LocalizationServerError";}},y=class extends s{constructor(e="Network error while contacting localization API",r){super(e,r),this.name="LocalizationNetworkError";}},v=class extends s{constructor(e="Localization request timeout",r){super(e,r),this.name="LocalizationTimeoutError";}};var b=class extends Error{constructor(r,t,o){super(`Request failed with status ${r}`);this.statusCode=r;this.responseBody=t;this.responseHeaders=o;this.name="HttpStatusError";}},L=class extends Error{constructor(r){super(`Request timed out after ${r}ms`);this.timeoutMs=r;this.name="HttpTimeoutError";}},u=class extends Error{constructor(r){super("Network error while sending request");this.causeError=r;this.name="HttpNetworkError";}},w=class{constructor(e){this.options=e;this.fetchFn=e.fetchFn??globalThis.fetch.bind(globalThis);}async request(e){let r=e.timeoutMs??this.options.timeoutMs,t=new AbortController,o=setTimeout(()=>t.abort(),r),n=new Request(this.resolveUrl(e),{method:e.method,headers:{"Content-Type":"application/json",...this.options.defaultHeaders,...e.headers},body:e.body===void 0?void 0:JSON.stringify(e.body),signal:t.signal});try{let a=await this.runRequestMiddleware(n),d;try{d=await this.fetchFn(a);}catch(E){throw this.isAbortError(E)?new L(r):new u(E)}let c=await this.runResponseMiddleware(d);if(!c.ok){let E=await c.text();throw new b(c.status,E,c.headers)}let N=await this.parseResponse(c);return {status:c.status,headers:c.headers,data:N}}catch(a){throw await this.runErrorMiddleware(this.toError(a)),a}finally{clearTimeout(o);}}resolveUrl(e){let r=new URL(e.path,this.options.baseUrl);return e.query&&Object.entries(e.query).forEach(([t,o])=>{o!==void 0&&r.searchParams.set(t,String(o));}),r.toString()}runRequestMiddleware(e){return (this.options.middleware??[]).reduce(async(t,o)=>{let n=await t;return o.onRequest?o.onRequest(n):n},Promise.resolve(e))}runResponseMiddleware(e){return (this.options.middleware??[]).reduce(async(t,o)=>{let n=await t;return o.onResponse?o.onResponse(n):n},Promise.resolve(e))}async runErrorMiddleware(e){let r=(this.options.middleware??[]).map(t=>t.onError).filter(t=>!!t);await Promise.all(r.map(t=>t(e)));}async parseResponse(e){return e.status===204?null:(e.headers.get("content-type")??"").includes("application/json")?await e.json():await e.text()}toError(e){return e instanceof Error?e:new Error("Unknown request error")}isAbortError(e){return e instanceof DOMException&&e.name==="AbortError"}};var $="localization:listResources",P=class{constructor(e,r,t){this.cacheProvider=e;this.cacheTtlMs=r;this.logger=t;}async getListResources(){this.logger.debug(`listResources:start cacheEnabled=${!!this.cacheProvider}`);let e=await this.cacheProvider?.get($);return e?this.logger.info(`listResources:cache-hit count=${e.length}`):this.logger.debug("listResources:cache-miss"),e}async storeListResources(e){await this.cacheProvider?.set($,e,this.cacheTtlMs),this.logger.debug(`listResources:cache-store ttlMs=${this.cacheTtlMs??0} count=${e.length}`);}async invalidate(e){if(this.logger.debug(`invalidateCache:start scope=${e??"all"}`),!this.cacheProvider){this.logger.debug("invalidateCache:skipped no-cache-provider");return}if(e){await this.cacheProvider.delete(e),this.logger.info(`invalidateCache:deleted key=${e}`);return}await this.cacheProvider.clear(),this.logger.info("invalidateCache:cleared-all");}};var z=class{constructor(e){this.logger=e;}async run(e,r){try{return await r()}catch(t){let o=this.map(t);throw this.logger.errorForOperation(e,o,t),o}}validateRequired(e,r){if(!e?.trim())throw new s(`${r} is required`)}map(e){return e instanceof s?e:e instanceof L?new v(e.message):e instanceof u?new y(e.message):e instanceof b?this.mapStatusError(e):new s("Unexpected localization SDK error")}preserveCause(e){let r=this.map(e);return r.cause??(r.cause=e),r}mapStatusError(e){return e.statusCode===401||e.statusCode===403?new m("Invalid token for localization endpoint",{statusCode:e.statusCode}):e.statusCode===404?new p("Localization resource was not found",{statusCode:e.statusCode}):e.statusCode>=500?new f("Localization API is unavailable",{statusCode:e.statusCode}):new s(e.message,{statusCode:e.statusCode})}};var F="[LocalizationSdk]",S=class{constructor(e=false){this.enabled=e;}debug(e){this.write("debug",e);}info(e){this.write("info",e);}errorForOperation(e,r,t){this.write("error",`${e}:error ${this.formatErrorDetails(r,t)}`);}formatErrorDetails(e,r){let t=this.getOriginalCause(e,r),o=this.getErrorMessage(t),n=[`type=${e.name}`,`message=${e.message}`];return o&&o!==e.message&&n.push(`original=${o}`),e instanceof s&&e.metadata?.statusCode&&n.push(`statusCode=${e.metadata.statusCode}`),n.join(" ")}getOriginalCause(e,r){let o=e.cause??r;return o instanceof u?o.causeError:o}getErrorMessage(e){return e instanceof Error?e.message:typeof e=="string"?e:"unknown-error"}write(e,r){if(!this.enabled)return;let t=this.resolveIcon(e,r),o=`${F} ${t} ${r}`;switch(e){case "debug":console.debug(o);break;case "info":console.info(o);break;case "error":console.error(o);break}}resolveIcon(e,r){return e==="error"||r.includes(":error")?"\u274C":r.includes("request:start")||r.includes(":api-call")?"\u{1F310}":r.includes("request:success")?"\u{1F4E1}":r.includes(":cache-hit")||r.includes("cache-hit")?"\u{1F5C4}\uFE0F":r.includes("cache-miss")?"\u{1F4ED}":r.includes("cache-store")?"\u{1F4BE}":r.includes("invalidateCache")?"\u{1F9F9}":r.includes("listResources")?"\u{1F4DA}":r.includes("getByLanguage")?"\u{1F30D}":r.includes("getCurrentLanguage")?"\u{1F22F}":r.includes(":start")?"\u{1F680}":r.includes(":success")?"\u2705":e==="info"?"\u2139\uFE0F":"\u{1F50E}"}};var O=class{constructor(e){this.dependencies=e;this.logger=new S(e.enableLogs),this.cacheHelper=new P(e.cacheProvider,e.cacheTtlMs,this.logger),this.errorHandler=new z(this.logger);}async getCurrentLanguage(e,r){return this.errorHandler.run("getCurrentLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.logger.debug(`getCurrentLanguage:start resourceKey=${e}`),this.isCacheEnabled()){let o=await this.resolveFromCachedResources(e);return this.logger.info(`getCurrentLanguage:cache-${o?"hit":"miss"} resourceKey=${e} hasValue=${!!o}`),o}this.logger.info(`getCurrentLanguage:api-call path=api/localization/client/currentlanguage resourceKey=${e}`);let t=await this.send({method:"GET",path:"api/localization/client/currentlanguage",query:{resourceKey:e},headers:this.resolveLocaleHeader(r)});return this.logger.info(`getCurrentLanguage:success resourceKey=${e} hasValue=${!!t}`),t??""})}async getByLanguage(e,r,t){return this.errorHandler.run("getByLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.errorHandler.validateRequired(r,"languageKey"),this.logger.debug(`getByLanguage:start resourceKey=${e} languageKey=${r}`),this.isCacheEnabled()){let n=await this.resolveFromCachedResources(e,r);return this.logger.info(`getByLanguage:cache-${n?"hit":"miss"} resourceKey=${e} languageKey=${r} hasValue=${!!n}`),n}this.logger.info(`getByLanguage:api-call path=api/localization/client/bylanguage resourceKey=${e} languageKey=${r}`);let o=await this.send({method:"GET",path:"api/localization/client/bylanguage",query:{resourceKey:e,languageKey:r},headers:this.resolveLocaleHeader(t)});return this.logger.info(`getByLanguage:success resourceKey=${e} languageKey=${r} hasValue=${!!o}`),o??""})}async listResources(){return this.errorHandler.run("listResources",async()=>{if(this.isCacheEnabled()){let t=await this.cacheHelper.getListResources();if(t)return this.logger.info(`listResources:cache-hit-return count=${t.length}`),t}else this.logger.debug("listResources:cache-disabled");this.logger.info("listResources:api-call path=api/localization/client/list");let r=(await this.send({method:"GET",path:"api/localization/client/list"})??[]).map(t=>({key:t.resourceKey,value:t.value,language:t.languageKey}));return this.isCacheEnabled()&&await this.cacheHelper.storeListResources(r),this.logger.info(`listResources:success count=${r.length}`),r})}async invalidateCache(e){return this.errorHandler.run("invalidateCache",async()=>this.cacheHelper.invalidate(e))}async clearCache(){return this.errorHandler.run("clearCache",async()=>this.cacheHelper.invalidate())}async submitKey(e,r,t,o,n){return this.submitKeys({keys:[{resourceKey:e,sourceFileName:n,translations:{[r]:o?{suggestedValue:t,description:o}:t}}]})}async submitKeyWithTranslations(e,r,t){return this.submitKeys({keys:[{resourceKey:e,translations:r,sourceFileName:t}]})}async submitKeys(e){return this.errorHandler.run("submitKeys",async()=>{let r=this.buildSubmitPayload(e);this.logger.info(`submitKeys:api-call path=api/localization/client/submit-keys count=${r.keys.length}`);let t=await this.send({method:"POST",path:"api/localization/client/submit-keys",body:r});return this.mapSubmitResult(t)})}async resolveFromCachedResources(e,r){return (await this.listResources()).find(n=>n.key!==e?false:r===void 0?true:n.language===r)?.value??""}async send(e){try{let r=await this.dependencies.authProvider?.getToken(),t=r?{...e.headers,"X-Auth-Token":r}:e.headers;this.logger.debug(`request:start method=${e.method} path=${e.path} hasAuth=${!!r}`);let o=await this.dependencies.httpTransport.request({...e,headers:t});return this.logger.debug(`request:success method=${e.method} path=${e.path} status=${o.status}`),o.data}catch(r){throw this.errorHandler.preserveCause(r)}}resolveLocaleHeader(e){let r=e?.locale?.trim()||this.dependencies.locale?.trim()||this.resolveBrowserLocale();if(r)return {"Accept-Language":r}}resolveBrowserLocale(){return globalThis.navigator?.language?.trim()||void 0}buildSubmitPayload(e){if(!e?.keys?.length)throw new s("At least one key is required.");return {keys:e.keys.map(t=>{this.errorHandler.validateRequired(t.resourceKey,"resourceKey");let o=Object.entries(t.translations??{});if(o.length===0)throw new s(`Translations are required for '${t.resourceKey}'.`);return {resourceKey:t.resourceKey.trim(),sourceFileName:U(t.sourceFileName),valueFormat:t.valueFormat??0,submittedByUserName:e.authorName,submittedByUserEmail:e.authorEmail,translations:o.map(([n,a])=>{let d=_(a);return this.errorHandler.validateRequired(n,"languageKey"),this.errorHandler.validateRequired(d.suggestedValue,"suggestedValue"),{languageKey:n.trim(),suggestedValue:d.suggestedValue.trim(),description:d.description?.trim()||void 0}})}})}}mapSubmitResult(e){let r=(e?.errors??[]).map(t=>t.description||t.code||"").filter(t=>t.length>0);return {success:!!e?.success&&r.length===0,statusCode:e?.statusCode??202,acceptedCount:e?.data?.acceptedCount??0,versionId:e?.data?.versionId??0,environment:e?.data?.environment??0,message:e?.message,errors:r,rejectedKeys:e?.data?.rejectedKeys??[]}}isCacheEnabled(){if(this.dependencies.cacheEnabled!==void 0)return this.logger.debug(`isCacheEnabled: enabled=${this.dependencies.cacheEnabled} source=cacheEnabled-flag`),this.dependencies.cacheEnabled;let e=!!this.dependencies.cacheProvider;return this.logger.debug(`isCacheEnabled: enabled=${e} source=cacheProvider`),e}};function _(i){return typeof i=="string"?{suggestedValue:i}:i}function U(i){let e=i?.trim();if(!e)return;let r=e.split(/[/\\]/);return r[r.length-1]||void 0}function x(i){V(i);let e=i.cache?.enabled??false,r=e?i.cache?.provider??new g:void 0,t=new w({baseUrl:i.baseUrl,fetchFn:i.fetchFn,timeoutMs:i.timeoutMs??1e4,defaultHeaders:i.headers,middleware:i.middleware});return new O({httpTransport:t,authProvider:i.authProvider??(i.token?new h(i.token):void 0),locale:i.locale,cacheEnabled:e,cacheProvider:r,cacheTtlMs:i.cache?.ttlMs,enableLogs:i.enableLogs??false})}function V(i){if(!i?.baseUrl?.trim())throw new s("baseUrl is required to create localization client")}var C=class{constructor(e){this.storage=e;}get(e){let r=this.storage.getItem(e);if(!r)return Promise.resolve(null);let t=this.safeParse(r);return t?t.expiresAt!==void 0&&Date.now()>t.expiresAt?(this.storage.removeItem(e),Promise.resolve(null)):Promise.resolve(t.value):(this.storage.removeItem(e),Promise.resolve(null))}set(e,r,t){let o=t&&t>0?Date.now()+t:void 0,n={value:r,expiresAt:o};return this.storage.setItem(e,JSON.stringify(n)),Promise.resolve()}delete(e){return this.storage.removeItem(e),Promise.resolve()}clear(){return this.storage.clear(),Promise.resolve()}safeParse(e){try{return JSON.parse(e)}catch{return null}}},K=class extends C{constructor(){super(M("localStorage"));}},A=class extends C{constructor(){super(M("sessionStorage"));}};function M(i){let e=globalThis.window===void 0?void 0:globalThis.window[i];return e||j()}function j(){let i=new Map;return {get length(){return i.size},clear:()=>{i.clear();},getItem:e=>i.get(e)??null,key:e=>Array.from(i.keys())[e]??null,removeItem:e=>{i.delete(e);},setItem:(e,r)=>{i.set(e,r);}}}var I=new core.InjectionToken("LOCALIZATION_SDK_OPTIONS"),R=new core.InjectionToken("LOCALIZATION_CLIENT");function W(i){return core.makeEnvironmentProviders([{provide:I,useValue:i},{provide:R,useFactory:()=>x(i)}])}exports.LocalizationService=class T{constructor(e){this.client=e;}getCurrentLanguage(e){return rxjs.from(this.client.getCurrentLanguage(e))}getByLanguage(e,r){return rxjs.from(this.client.getByLanguage(e,r))}listResources(){return rxjs.from(this.client.listResources())}invalidateCache(e){return rxjs.from(this.client.invalidateCache(e))}clearCache(){return rxjs.from(this.client.clearCache())}submitKey(e,r,t,o,n){return rxjs.from(this.client.submitKey(e,r,t,o,n))}submitKeyWithTranslations(e,r,t){return rxjs.from(this.client.submitKeyWithTranslations(e,r,t))}submitKeys(e){return rxjs.from(this.client.submitKeys(e))}};exports.LocalizationService=H([core.Injectable({providedIn:"root"}),k(0,core.Inject(R))],exports.LocalizationService);exports.FetchHttpTransport=w;exports.LOCALIZATION_CLIENT=R;exports.LOCALIZATION_SDK_OPTIONS=I;exports.LocalStorageCacheProvider=K;exports.LocalizationAuthError=m;exports.LocalizationError=s;exports.LocalizationNetworkError=y;exports.LocalizationServerError=f;exports.LocalizationTimeoutError=v;exports.MemoryCacheProvider=g;exports.ResourceNotFoundError=p;exports.SessionStorageCacheProvider=A;exports.StorageCacheProvider=C;exports.XAuthTokenProvider=h;exports.createLocalizationClient=x;exports.provideLocalization=W;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {InjectionToken,Injectable,Inject,makeEnvironmentProviders}from'@angular/core';import {from}from'rxjs';var S=(o,e,r,t)=>{for(var i=e,n=o.length-1,s;n>=0;n--)(s=o[n])&&(i=(s(i))||i);return i},k=(o,e)=>(r,t)=>e(r,t,o);var u=class{constructor(e){this.token=e;}getToken(){return Promise.resolve(this.token?.trim()?this.token:null)}};var d=class{constructor(){this.store=new Map;}get(e){let r=this.store.get(e);return r?r.expiresAt!==void 0&&Date.now()>r.expiresAt?(this.store.delete(e),Promise.resolve(null)):Promise.resolve(r.value):Promise.resolve(null)}set(e,r,t){let i=t&&t>0?Date.now()+t:void 0;return this.store.set(e,{value:r,expiresAt:i}),Promise.resolve()}delete(e){return this.store.delete(e),Promise.resolve()}clear(){return this.store.clear(),Promise.resolve()}};var a=class extends Error{constructor(r,t){super(r);this.metadata=t;this.name="LocalizationError";}},h=class extends a{constructor(e="Authentication failed",r){super(e,r),this.name="LocalizationAuthError";}},p=class extends a{constructor(e="Resource not found",r){super(e,r),this.name="ResourceNotFoundError";}},g=class extends a{constructor(e="Localization server error",r){super(e,r),this.name="LocalizationServerError";}},m=class extends a{constructor(e="Network error while contacting localization API",r){super(e,r),this.name="LocalizationNetworkError";}},f=class extends a{constructor(e="Localization request timeout",r){super(e,r),this.name="LocalizationTimeoutError";}};var v=class extends Error{constructor(r,t,i){super(`Request failed with status ${r}`);this.statusCode=r;this.responseBody=t;this.responseHeaders=i;this.name="HttpStatusError";}},L=class extends Error{constructor(r){super(`Request timed out after ${r}ms`);this.timeoutMs=r;this.name="HttpTimeoutError";}},c=class extends Error{constructor(r){super("Network error while sending request");this.causeError=r;this.name="HttpNetworkError";}},y=class{constructor(e){this.options=e;this.fetchFn=e.fetchFn??globalThis.fetch.bind(globalThis);}async request(e){let r=e.timeoutMs??this.options.timeoutMs,t=new AbortController,i=setTimeout(()=>t.abort(),r),n=new Request(this.resolveUrl(e),{method:e.method,headers:{"Content-Type":"application/json",...this.options.defaultHeaders,...e.headers},body:e.body===void 0?void 0:JSON.stringify(e.body),signal:t.signal});try{let s=await this.runRequestMiddleware(n),$;try{$=await this.fetchFn(s);}catch(P){throw this.isAbortError(P)?new L(r):new c(P)}let l=await this.runResponseMiddleware($);if(!l.ok){let P=await l.text();throw new v(l.status,P,l.headers)}let D=await this.parseResponse(l);return {status:l.status,headers:l.headers,data:D}}catch(s){throw await this.runErrorMiddleware(this.toError(s)),s}finally{clearTimeout(i);}}resolveUrl(e){let r=new URL(e.path,this.options.baseUrl);return e.query&&Object.entries(e.query).forEach(([t,i])=>{i!==void 0&&r.searchParams.set(t,String(i));}),r.toString()}runRequestMiddleware(e){return (this.options.middleware??[]).reduce(async(t,i)=>{let n=await t;return i.onRequest?i.onRequest(n):n},Promise.resolve(e))}runResponseMiddleware(e){return (this.options.middleware??[]).reduce(async(t,i)=>{let n=await t;return i.onResponse?i.onResponse(n):n},Promise.resolve(e))}async runErrorMiddleware(e){let r=(this.options.middleware??[]).map(t=>t.onError).filter(t=>!!t);await Promise.all(r.map(t=>t(e)));}async parseResponse(e){return e.status===204?null:(e.headers.get("content-type")??"").includes("application/json")?await e.json():await e.text()}toError(e){return e instanceof Error?e:new Error("Unknown request error")}isAbortError(e){return e instanceof DOMException&&e.name==="AbortError"}};var M="localization:listResources",T=class{constructor(e,r,t){this.cacheProvider=e;this.cacheTtlMs=r;this.logger=t;}async getListResources(){this.logger.debug(`listResources:start cacheEnabled=${!!this.cacheProvider}`);let e=await this.cacheProvider?.get(M);return e?this.logger.info(`listResources:cache-hit count=${e.length}`):this.logger.debug("listResources:cache-miss"),e}async storeListResources(e){await this.cacheProvider?.set(M,e,this.cacheTtlMs),this.logger.debug(`listResources:cache-store ttlMs=${this.cacheTtlMs??0} count=${e.length}`);}async invalidate(e){if(this.logger.debug(`invalidateCache:start scope=${e??"all"}`),!this.cacheProvider){this.logger.debug("invalidateCache:skipped no-cache-provider");return}if(e){await this.cacheProvider.delete(e),this.logger.info(`invalidateCache:deleted key=${e}`);return}await this.cacheProvider.clear(),this.logger.info("invalidateCache:cleared-all");}};var R=class{constructor(e){this.logger=e;}async run(e,r){try{return await r()}catch(t){let i=this.map(t);throw this.logger.errorForOperation(e,i,t),i}}validateRequired(e,r){if(!e?.trim())throw new a(`${r} is required`)}map(e){return e instanceof a?e:e instanceof L?new f(e.message):e instanceof c?new m(e.message):e instanceof v?this.mapStatusError(e):new a("Unexpected localization SDK error")}preserveCause(e){let r=this.map(e);return r.cause??(r.cause=e),r}mapStatusError(e){return e.statusCode===401||e.statusCode===403?new h("Invalid token for localization endpoint",{statusCode:e.statusCode}):e.statusCode===404?new p("Localization resource was not found",{statusCode:e.statusCode}):e.statusCode>=500?new g("Localization API is unavailable",{statusCode:e.statusCode}):new a(e.message,{statusCode:e.statusCode})}};var K="[LocalizationSdk]",z=class{constructor(e=false){this.enabled=e;}debug(e){this.write("debug",e);}info(e){this.write("info",e);}errorForOperation(e,r,t){this.write("error",`${e}:error ${this.formatErrorDetails(r,t)}`);}formatErrorDetails(e,r){let t=this.getOriginalCause(e,r),i=this.getErrorMessage(t),n=[`type=${e.name}`,`message=${e.message}`];return i&&i!==e.message&&n.push(`original=${i}`),e instanceof a&&e.metadata?.statusCode&&n.push(`statusCode=${e.metadata.statusCode}`),n.join(" ")}getOriginalCause(e,r){let i=e.cause??r;return i instanceof c?i.causeError:i}getErrorMessage(e){return e instanceof Error?e.message:typeof e=="string"?e:"unknown-error"}write(e,r){if(!this.enabled)return;let t=this.resolveIcon(e,r),i=`${K} ${t} ${r}`;switch(e){case "debug":console.debug(i);break;case "info":console.info(i);break;case "error":console.error(i);break}}resolveIcon(e,r){return e==="error"||r.includes(":error")?"\u274C":r.includes("request:start")||r.includes(":api-call")?"\u{1F310}":r.includes("request:success")?"\u{1F4E1}":r.includes(":cache-hit")||r.includes("cache-hit")?"\u{1F5C4}\uFE0F":r.includes("cache-miss")?"\u{1F4ED}":r.includes("cache-store")?"\u{1F4BE}":r.includes("invalidateCache")?"\u{1F9F9}":r.includes("listResources")?"\u{1F4DA}":r.includes("getByLanguage")?"\u{1F30D}":r.includes("getCurrentLanguage")?"\u{1F22F}":r.includes(":start")?"\u{1F680}":r.includes(":success")?"\u2705":e==="info"?"\u2139\uFE0F":"\u{1F50E}"}};var x=class{constructor(e){this.dependencies=e;this.logger=new z(e.enableLogs),this.cacheHelper=new T(e.cacheProvider,e.cacheTtlMs,this.logger),this.errorHandler=new R(this.logger);}async getCurrentLanguage(e,r){return this.errorHandler.run("getCurrentLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.logger.debug(`getCurrentLanguage:start resourceKey=${e}`),this.isCacheEnabled()){let i=await this.resolveFromCachedResources(e);return this.logger.info(`getCurrentLanguage:cache-${i?"hit":"miss"} resourceKey=${e} hasValue=${!!i}`),i}this.logger.info(`getCurrentLanguage:api-call path=api/localization/client/currentlanguage resourceKey=${e}`);let t=await this.send({method:"GET",path:"api/localization/client/currentlanguage",query:{resourceKey:e},headers:this.resolveLocaleHeader(r)});return this.logger.info(`getCurrentLanguage:success resourceKey=${e} hasValue=${!!t}`),t??""})}async getByLanguage(e,r,t){return this.errorHandler.run("getByLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.errorHandler.validateRequired(r,"languageKey"),this.logger.debug(`getByLanguage:start resourceKey=${e} languageKey=${r}`),this.isCacheEnabled()){let n=await this.resolveFromCachedResources(e,r);return this.logger.info(`getByLanguage:cache-${n?"hit":"miss"} resourceKey=${e} languageKey=${r} hasValue=${!!n}`),n}this.logger.info(`getByLanguage:api-call path=api/localization/client/bylanguage resourceKey=${e} languageKey=${r}`);let i=await this.send({method:"GET",path:"api/localization/client/bylanguage",query:{resourceKey:e,languageKey:r},headers:this.resolveLocaleHeader(t)});return this.logger.info(`getByLanguage:success resourceKey=${e} languageKey=${r} hasValue=${!!i}`),i??""})}async listResources(){return this.errorHandler.run("listResources",async()=>{if(this.isCacheEnabled()){let t=await this.cacheHelper.getListResources();if(t)return this.logger.info(`listResources:cache-hit-return count=${t.length}`),t}else this.logger.debug("listResources:cache-disabled");this.logger.info("listResources:api-call path=api/localization/client/list");let r=(await this.send({method:"GET",path:"api/localization/client/list"})??[]).map(t=>({key:t.resourceKey,value:t.value,language:t.languageKey}));return this.isCacheEnabled()&&await this.cacheHelper.storeListResources(r),this.logger.info(`listResources:success count=${r.length}`),r})}async invalidateCache(e){return this.errorHandler.run("invalidateCache",async()=>this.cacheHelper.invalidate(e))}async clearCache(){return this.errorHandler.run("clearCache",async()=>this.cacheHelper.invalidate())}async resolveFromCachedResources(e,r){return (await this.listResources()).find(n=>n.key!==e?false:r===void 0?true:n.language===r)?.value??""}async send(e){try{let r=await this.dependencies.authProvider?.getToken(),t=r?{...e.headers,"X-Auth-Token":r}:e.headers;this.logger.debug(`request:start method=${e.method} path=${e.path} hasAuth=${!!r}`);let i=await this.dependencies.httpTransport.request({...e,headers:t});return this.logger.debug(`request:success method=${e.method} path=${e.path} status=${i.status}`),i.data}catch(r){throw this.errorHandler.preserveCause(r)}}resolveLocaleHeader(e){let r=e?.locale?.trim()||this.dependencies.locale?.trim()||this.resolveBrowserLocale();if(r)return {"Accept-Language":r}}resolveBrowserLocale(){return globalThis.navigator?.language?.trim()||void 0}isCacheEnabled(){if(this.dependencies.cacheEnabled!==void 0)return this.logger.debug(`isCacheEnabled: enabled=${this.dependencies.cacheEnabled} source=cacheEnabled-flag`),this.dependencies.cacheEnabled;let e=!!this.dependencies.cacheProvider;return this.logger.debug(`isCacheEnabled: enabled=${e} source=cacheProvider`),e}};function O(o){_(o);let e=o.cache?.enabled??false,r=e?o.cache?.provider??new d:void 0,t=new y({baseUrl:o.baseUrl,fetchFn:o.fetchFn,timeoutMs:o.timeoutMs??1e4,defaultHeaders:o.headers,middleware:o.middleware});return new x({httpTransport:t,authProvider:o.authProvider??(o.token?new u(o.token):void 0),locale:o.locale,cacheEnabled:e,cacheProvider:r,cacheTtlMs:o.cache?.ttlMs,enableLogs:o.enableLogs??false})}function _(o){if(!o?.baseUrl?.trim())throw new a("baseUrl is required to create localization client")}var w=class{constructor(e){this.storage=e;}get(e){let r=this.storage.getItem(e);if(!r)return Promise.resolve(null);let t=this.safeParse(r);return t?t.expiresAt!==void 0&&Date.now()>t.expiresAt?(this.storage.removeItem(e),Promise.resolve(null)):Promise.resolve(t.value):(this.storage.removeItem(e),Promise.resolve(null))}set(e,r,t){let i=t&&t>0?Date.now()+t:void 0,n={value:r,expiresAt:i};return this.storage.setItem(e,JSON.stringify(n)),Promise.resolve()}delete(e){return this.storage.removeItem(e),Promise.resolve()}clear(){return this.storage.clear(),Promise.resolve()}safeParse(e){try{return JSON.parse(e)}catch{return null}}},A=class extends w{constructor(){super(N("localStorage"));}},H=class extends w{constructor(){super(N("sessionStorage"));}};function N(o){let e=globalThis.window===void 0?void 0:globalThis.window[o];return e||U()}function U(){let o=new Map;return {get length(){return o.size},clear:()=>{o.clear();},getItem:e=>o.get(e)??null,key:e=>Array.from(o.keys())[e]??null,removeItem:e=>{o.delete(e);},setItem:(e,r)=>{o.set(e,r);}}}var I=new InjectionToken("LOCALIZATION_SDK_OPTIONS"),C=new InjectionToken("LOCALIZATION_CLIENT");function Z(o){return makeEnvironmentProviders([{provide:I,useValue:o},{provide:C,useFactory:()=>O(o)}])}var E=class{constructor(e){this.client=e;}getCurrentLanguage(e){return from(this.client.getCurrentLanguage(e))}getByLanguage(e,r){return from(this.client.getByLanguage(e,r))}listResources(){return from(this.client.listResources())}invalidateCache(e){return from(this.client.invalidateCache(e))}clearCache(){return from(this.client.clearCache())}};E=S([Injectable({providedIn:"root"}),k(0,Inject(C))],E);export{y as FetchHttpTransport,C as LOCALIZATION_CLIENT,I as LOCALIZATION_SDK_OPTIONS,A as LocalStorageCacheProvider,h as LocalizationAuthError,a as LocalizationError,m as LocalizationNetworkError,g as LocalizationServerError,E as LocalizationService,f as LocalizationTimeoutError,d as MemoryCacheProvider,p as ResourceNotFoundError,H as SessionStorageCacheProvider,w as StorageCacheProvider,u as XAuthTokenProvider,O as createLocalizationClient,Z as provideLocalization};
1
+ import {InjectionToken,Injectable,Inject,makeEnvironmentProviders}from'@angular/core';import {from}from'rxjs';var H=(i,e,r,t)=>{for(var o=e,n=i.length-1,a;n>=0;n--)(a=i[n])&&(o=(a(o))||o);return o},k=(i,e)=>(r,t)=>e(r,t,i);var h=class{constructor(e){this.token=e;}getToken(){return Promise.resolve(this.token?.trim()?this.token:null)}};var g=class{constructor(){this.store=new Map;}get(e){let r=this.store.get(e);return r?r.expiresAt!==void 0&&Date.now()>r.expiresAt?(this.store.delete(e),Promise.resolve(null)):Promise.resolve(r.value):Promise.resolve(null)}set(e,r,t){let o=t&&t>0?Date.now()+t:void 0;return this.store.set(e,{value:r,expiresAt:o}),Promise.resolve()}delete(e){return this.store.delete(e),Promise.resolve()}clear(){return this.store.clear(),Promise.resolve()}};var s=class extends Error{constructor(r,t){super(r);this.metadata=t;this.name="LocalizationError";}},m=class extends s{constructor(e="Authentication failed",r){super(e,r),this.name="LocalizationAuthError";}},p=class extends s{constructor(e="Resource not found",r){super(e,r),this.name="ResourceNotFoundError";}},f=class extends s{constructor(e="Localization server error",r){super(e,r),this.name="LocalizationServerError";}},y=class extends s{constructor(e="Network error while contacting localization API",r){super(e,r),this.name="LocalizationNetworkError";}},v=class extends s{constructor(e="Localization request timeout",r){super(e,r),this.name="LocalizationTimeoutError";}};var b=class extends Error{constructor(r,t,o){super(`Request failed with status ${r}`);this.statusCode=r;this.responseBody=t;this.responseHeaders=o;this.name="HttpStatusError";}},L=class extends Error{constructor(r){super(`Request timed out after ${r}ms`);this.timeoutMs=r;this.name="HttpTimeoutError";}},u=class extends Error{constructor(r){super("Network error while sending request");this.causeError=r;this.name="HttpNetworkError";}},w=class{constructor(e){this.options=e;this.fetchFn=e.fetchFn??globalThis.fetch.bind(globalThis);}async request(e){let r=e.timeoutMs??this.options.timeoutMs,t=new AbortController,o=setTimeout(()=>t.abort(),r),n=new Request(this.resolveUrl(e),{method:e.method,headers:{"Content-Type":"application/json",...this.options.defaultHeaders,...e.headers},body:e.body===void 0?void 0:JSON.stringify(e.body),signal:t.signal});try{let a=await this.runRequestMiddleware(n),d;try{d=await this.fetchFn(a);}catch(E){throw this.isAbortError(E)?new L(r):new u(E)}let c=await this.runResponseMiddleware(d);if(!c.ok){let E=await c.text();throw new b(c.status,E,c.headers)}let N=await this.parseResponse(c);return {status:c.status,headers:c.headers,data:N}}catch(a){throw await this.runErrorMiddleware(this.toError(a)),a}finally{clearTimeout(o);}}resolveUrl(e){let r=new URL(e.path,this.options.baseUrl);return e.query&&Object.entries(e.query).forEach(([t,o])=>{o!==void 0&&r.searchParams.set(t,String(o));}),r.toString()}runRequestMiddleware(e){return (this.options.middleware??[]).reduce(async(t,o)=>{let n=await t;return o.onRequest?o.onRequest(n):n},Promise.resolve(e))}runResponseMiddleware(e){return (this.options.middleware??[]).reduce(async(t,o)=>{let n=await t;return o.onResponse?o.onResponse(n):n},Promise.resolve(e))}async runErrorMiddleware(e){let r=(this.options.middleware??[]).map(t=>t.onError).filter(t=>!!t);await Promise.all(r.map(t=>t(e)));}async parseResponse(e){return e.status===204?null:(e.headers.get("content-type")??"").includes("application/json")?await e.json():await e.text()}toError(e){return e instanceof Error?e:new Error("Unknown request error")}isAbortError(e){return e instanceof DOMException&&e.name==="AbortError"}};var $="localization:listResources",P=class{constructor(e,r,t){this.cacheProvider=e;this.cacheTtlMs=r;this.logger=t;}async getListResources(){this.logger.debug(`listResources:start cacheEnabled=${!!this.cacheProvider}`);let e=await this.cacheProvider?.get($);return e?this.logger.info(`listResources:cache-hit count=${e.length}`):this.logger.debug("listResources:cache-miss"),e}async storeListResources(e){await this.cacheProvider?.set($,e,this.cacheTtlMs),this.logger.debug(`listResources:cache-store ttlMs=${this.cacheTtlMs??0} count=${e.length}`);}async invalidate(e){if(this.logger.debug(`invalidateCache:start scope=${e??"all"}`),!this.cacheProvider){this.logger.debug("invalidateCache:skipped no-cache-provider");return}if(e){await this.cacheProvider.delete(e),this.logger.info(`invalidateCache:deleted key=${e}`);return}await this.cacheProvider.clear(),this.logger.info("invalidateCache:cleared-all");}};var z=class{constructor(e){this.logger=e;}async run(e,r){try{return await r()}catch(t){let o=this.map(t);throw this.logger.errorForOperation(e,o,t),o}}validateRequired(e,r){if(!e?.trim())throw new s(`${r} is required`)}map(e){return e instanceof s?e:e instanceof L?new v(e.message):e instanceof u?new y(e.message):e instanceof b?this.mapStatusError(e):new s("Unexpected localization SDK error")}preserveCause(e){let r=this.map(e);return r.cause??(r.cause=e),r}mapStatusError(e){return e.statusCode===401||e.statusCode===403?new m("Invalid token for localization endpoint",{statusCode:e.statusCode}):e.statusCode===404?new p("Localization resource was not found",{statusCode:e.statusCode}):e.statusCode>=500?new f("Localization API is unavailable",{statusCode:e.statusCode}):new s(e.message,{statusCode:e.statusCode})}};var F="[LocalizationSdk]",S=class{constructor(e=false){this.enabled=e;}debug(e){this.write("debug",e);}info(e){this.write("info",e);}errorForOperation(e,r,t){this.write("error",`${e}:error ${this.formatErrorDetails(r,t)}`);}formatErrorDetails(e,r){let t=this.getOriginalCause(e,r),o=this.getErrorMessage(t),n=[`type=${e.name}`,`message=${e.message}`];return o&&o!==e.message&&n.push(`original=${o}`),e instanceof s&&e.metadata?.statusCode&&n.push(`statusCode=${e.metadata.statusCode}`),n.join(" ")}getOriginalCause(e,r){let o=e.cause??r;return o instanceof u?o.causeError:o}getErrorMessage(e){return e instanceof Error?e.message:typeof e=="string"?e:"unknown-error"}write(e,r){if(!this.enabled)return;let t=this.resolveIcon(e,r),o=`${F} ${t} ${r}`;switch(e){case "debug":console.debug(o);break;case "info":console.info(o);break;case "error":console.error(o);break}}resolveIcon(e,r){return e==="error"||r.includes(":error")?"\u274C":r.includes("request:start")||r.includes(":api-call")?"\u{1F310}":r.includes("request:success")?"\u{1F4E1}":r.includes(":cache-hit")||r.includes("cache-hit")?"\u{1F5C4}\uFE0F":r.includes("cache-miss")?"\u{1F4ED}":r.includes("cache-store")?"\u{1F4BE}":r.includes("invalidateCache")?"\u{1F9F9}":r.includes("listResources")?"\u{1F4DA}":r.includes("getByLanguage")?"\u{1F30D}":r.includes("getCurrentLanguage")?"\u{1F22F}":r.includes(":start")?"\u{1F680}":r.includes(":success")?"\u2705":e==="info"?"\u2139\uFE0F":"\u{1F50E}"}};var O=class{constructor(e){this.dependencies=e;this.logger=new S(e.enableLogs),this.cacheHelper=new P(e.cacheProvider,e.cacheTtlMs,this.logger),this.errorHandler=new z(this.logger);}async getCurrentLanguage(e,r){return this.errorHandler.run("getCurrentLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.logger.debug(`getCurrentLanguage:start resourceKey=${e}`),this.isCacheEnabled()){let o=await this.resolveFromCachedResources(e);return this.logger.info(`getCurrentLanguage:cache-${o?"hit":"miss"} resourceKey=${e} hasValue=${!!o}`),o}this.logger.info(`getCurrentLanguage:api-call path=api/localization/client/currentlanguage resourceKey=${e}`);let t=await this.send({method:"GET",path:"api/localization/client/currentlanguage",query:{resourceKey:e},headers:this.resolveLocaleHeader(r)});return this.logger.info(`getCurrentLanguage:success resourceKey=${e} hasValue=${!!t}`),t??""})}async getByLanguage(e,r,t){return this.errorHandler.run("getByLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.errorHandler.validateRequired(r,"languageKey"),this.logger.debug(`getByLanguage:start resourceKey=${e} languageKey=${r}`),this.isCacheEnabled()){let n=await this.resolveFromCachedResources(e,r);return this.logger.info(`getByLanguage:cache-${n?"hit":"miss"} resourceKey=${e} languageKey=${r} hasValue=${!!n}`),n}this.logger.info(`getByLanguage:api-call path=api/localization/client/bylanguage resourceKey=${e} languageKey=${r}`);let o=await this.send({method:"GET",path:"api/localization/client/bylanguage",query:{resourceKey:e,languageKey:r},headers:this.resolveLocaleHeader(t)});return this.logger.info(`getByLanguage:success resourceKey=${e} languageKey=${r} hasValue=${!!o}`),o??""})}async listResources(){return this.errorHandler.run("listResources",async()=>{if(this.isCacheEnabled()){let t=await this.cacheHelper.getListResources();if(t)return this.logger.info(`listResources:cache-hit-return count=${t.length}`),t}else this.logger.debug("listResources:cache-disabled");this.logger.info("listResources:api-call path=api/localization/client/list");let r=(await this.send({method:"GET",path:"api/localization/client/list"})??[]).map(t=>({key:t.resourceKey,value:t.value,language:t.languageKey}));return this.isCacheEnabled()&&await this.cacheHelper.storeListResources(r),this.logger.info(`listResources:success count=${r.length}`),r})}async invalidateCache(e){return this.errorHandler.run("invalidateCache",async()=>this.cacheHelper.invalidate(e))}async clearCache(){return this.errorHandler.run("clearCache",async()=>this.cacheHelper.invalidate())}async submitKey(e,r,t,o,n){return this.submitKeys({keys:[{resourceKey:e,sourceFileName:n,translations:{[r]:o?{suggestedValue:t,description:o}:t}}]})}async submitKeyWithTranslations(e,r,t){return this.submitKeys({keys:[{resourceKey:e,translations:r,sourceFileName:t}]})}async submitKeys(e){return this.errorHandler.run("submitKeys",async()=>{let r=this.buildSubmitPayload(e);this.logger.info(`submitKeys:api-call path=api/localization/client/submit-keys count=${r.keys.length}`);let t=await this.send({method:"POST",path:"api/localization/client/submit-keys",body:r});return this.mapSubmitResult(t)})}async resolveFromCachedResources(e,r){return (await this.listResources()).find(n=>n.key!==e?false:r===void 0?true:n.language===r)?.value??""}async send(e){try{let r=await this.dependencies.authProvider?.getToken(),t=r?{...e.headers,"X-Auth-Token":r}:e.headers;this.logger.debug(`request:start method=${e.method} path=${e.path} hasAuth=${!!r}`);let o=await this.dependencies.httpTransport.request({...e,headers:t});return this.logger.debug(`request:success method=${e.method} path=${e.path} status=${o.status}`),o.data}catch(r){throw this.errorHandler.preserveCause(r)}}resolveLocaleHeader(e){let r=e?.locale?.trim()||this.dependencies.locale?.trim()||this.resolveBrowserLocale();if(r)return {"Accept-Language":r}}resolveBrowserLocale(){return globalThis.navigator?.language?.trim()||void 0}buildSubmitPayload(e){if(!e?.keys?.length)throw new s("At least one key is required.");return {keys:e.keys.map(t=>{this.errorHandler.validateRequired(t.resourceKey,"resourceKey");let o=Object.entries(t.translations??{});if(o.length===0)throw new s(`Translations are required for '${t.resourceKey}'.`);return {resourceKey:t.resourceKey.trim(),sourceFileName:U(t.sourceFileName),valueFormat:t.valueFormat??0,submittedByUserName:e.authorName,submittedByUserEmail:e.authorEmail,translations:o.map(([n,a])=>{let d=_(a);return this.errorHandler.validateRequired(n,"languageKey"),this.errorHandler.validateRequired(d.suggestedValue,"suggestedValue"),{languageKey:n.trim(),suggestedValue:d.suggestedValue.trim(),description:d.description?.trim()||void 0}})}})}}mapSubmitResult(e){let r=(e?.errors??[]).map(t=>t.description||t.code||"").filter(t=>t.length>0);return {success:!!e?.success&&r.length===0,statusCode:e?.statusCode??202,acceptedCount:e?.data?.acceptedCount??0,versionId:e?.data?.versionId??0,environment:e?.data?.environment??0,message:e?.message,errors:r,rejectedKeys:e?.data?.rejectedKeys??[]}}isCacheEnabled(){if(this.dependencies.cacheEnabled!==void 0)return this.logger.debug(`isCacheEnabled: enabled=${this.dependencies.cacheEnabled} source=cacheEnabled-flag`),this.dependencies.cacheEnabled;let e=!!this.dependencies.cacheProvider;return this.logger.debug(`isCacheEnabled: enabled=${e} source=cacheProvider`),e}};function _(i){return typeof i=="string"?{suggestedValue:i}:i}function U(i){let e=i?.trim();if(!e)return;let r=e.split(/[/\\]/);return r[r.length-1]||void 0}function x(i){V(i);let e=i.cache?.enabled??false,r=e?i.cache?.provider??new g:void 0,t=new w({baseUrl:i.baseUrl,fetchFn:i.fetchFn,timeoutMs:i.timeoutMs??1e4,defaultHeaders:i.headers,middleware:i.middleware});return new O({httpTransport:t,authProvider:i.authProvider??(i.token?new h(i.token):void 0),locale:i.locale,cacheEnabled:e,cacheProvider:r,cacheTtlMs:i.cache?.ttlMs,enableLogs:i.enableLogs??false})}function V(i){if(!i?.baseUrl?.trim())throw new s("baseUrl is required to create localization client")}var C=class{constructor(e){this.storage=e;}get(e){let r=this.storage.getItem(e);if(!r)return Promise.resolve(null);let t=this.safeParse(r);return t?t.expiresAt!==void 0&&Date.now()>t.expiresAt?(this.storage.removeItem(e),Promise.resolve(null)):Promise.resolve(t.value):(this.storage.removeItem(e),Promise.resolve(null))}set(e,r,t){let o=t&&t>0?Date.now()+t:void 0,n={value:r,expiresAt:o};return this.storage.setItem(e,JSON.stringify(n)),Promise.resolve()}delete(e){return this.storage.removeItem(e),Promise.resolve()}clear(){return this.storage.clear(),Promise.resolve()}safeParse(e){try{return JSON.parse(e)}catch{return null}}},K=class extends C{constructor(){super(M("localStorage"));}},A=class extends C{constructor(){super(M("sessionStorage"));}};function M(i){let e=globalThis.window===void 0?void 0:globalThis.window[i];return e||j()}function j(){let i=new Map;return {get length(){return i.size},clear:()=>{i.clear();},getItem:e=>i.get(e)??null,key:e=>Array.from(i.keys())[e]??null,removeItem:e=>{i.delete(e);},setItem:(e,r)=>{i.set(e,r);}}}var I=new InjectionToken("LOCALIZATION_SDK_OPTIONS"),R=new InjectionToken("LOCALIZATION_CLIENT");function W(i){return makeEnvironmentProviders([{provide:I,useValue:i},{provide:R,useFactory:()=>x(i)}])}var T=class{constructor(e){this.client=e;}getCurrentLanguage(e){return from(this.client.getCurrentLanguage(e))}getByLanguage(e,r){return from(this.client.getByLanguage(e,r))}listResources(){return from(this.client.listResources())}invalidateCache(e){return from(this.client.invalidateCache(e))}clearCache(){return from(this.client.clearCache())}submitKey(e,r,t,o,n){return from(this.client.submitKey(e,r,t,o,n))}submitKeyWithTranslations(e,r,t){return from(this.client.submitKeyWithTranslations(e,r,t))}submitKeys(e){return from(this.client.submitKeys(e))}};T=H([Injectable({providedIn:"root"}),k(0,Inject(R))],T);export{w as FetchHttpTransport,R as LOCALIZATION_CLIENT,I as LOCALIZATION_SDK_OPTIONS,K as LocalStorageCacheProvider,m as LocalizationAuthError,s as LocalizationError,y as LocalizationNetworkError,f as LocalizationServerError,T as LocalizationService,v as LocalizationTimeoutError,g as MemoryCacheProvider,p as ResourceNotFoundError,A as SessionStorageCacheProvider,C as StorageCacheProvider,h as XAuthTokenProvider,x as createLocalizationClient,W as provideLocalization};
@@ -1 +1 @@
1
- var LocalizationSDK=(function(exports){'use strict';var c=class{constructor(e){this.token=e;}getToken(){return Promise.resolve(this.token?.trim()?this.token:null)}};var u=class{constructor(){this.store=new Map;}get(e){let r=this.store.get(e);return r?r.expiresAt!==void 0&&Date.now()>r.expiresAt?(this.store.delete(e),Promise.resolve(null)):Promise.resolve(r.value):Promise.resolve(null)}set(e,r,t){let n=t&&t>0?Date.now()+t:void 0;return this.store.set(e,{value:r,expiresAt:n}),Promise.resolve()}delete(e){return this.store.delete(e),Promise.resolve()}clear(){return this.store.clear(),Promise.resolve()}};var a=class extends Error{constructor(r,t){super(r);this.metadata=t;this.name="LocalizationError";}},d=class extends a{constructor(e="Authentication failed",r){super(e,r),this.name="LocalizationAuthError";}},h=class extends a{constructor(e="Resource not found",r){super(e,r),this.name="ResourceNotFoundError";}},g=class extends a{constructor(e="Localization server error",r){super(e,r),this.name="LocalizationServerError";}},p=class extends a{constructor(e="Network error while contacting localization API",r){super(e,r),this.name="LocalizationNetworkError";}},m=class extends a{constructor(e="Localization request timeout",r){super(e,r),this.name="LocalizationTimeoutError";}};var f=class extends Error{constructor(r,t,n){super(`Request failed with status ${r}`);this.statusCode=r;this.responseBody=t;this.responseHeaders=n;this.name="HttpStatusError";}},v=class extends Error{constructor(r){super(`Request timed out after ${r}ms`);this.timeoutMs=r;this.name="HttpTimeoutError";}},l=class extends Error{constructor(r){super("Network error while sending request");this.causeError=r;this.name="HttpNetworkError";}},L=class{constructor(e){this.options=e;this.fetchFn=e.fetchFn??globalThis.fetch.bind(globalThis);}async request(e){let r=e.timeoutMs??this.options.timeoutMs,t=new AbortController,n=setTimeout(()=>t.abort(),r),i=new Request(this.resolveUrl(e),{method:e.method,headers:{"Content-Type":"application/json",...this.options.defaultHeaders,...e.headers},body:e.body===void 0?void 0:JSON.stringify(e.body),signal:t.signal});try{let w=await this.runRequestMiddleware(i),x;try{x=await this.fetchFn(w);}catch(y){throw this.isAbortError(y)?new v(r):new l(y)}let s=await this.runResponseMiddleware(x);if(!s.ok){let y=await s.text();throw new f(s.status,y,s.headers)}let A=await this.parseResponse(s);return {status:s.status,headers:s.headers,data:A}}catch(w){throw await this.runErrorMiddleware(this.toError(w)),w}finally{clearTimeout(n);}}resolveUrl(e){let r=new URL(e.path,this.options.baseUrl);return e.query&&Object.entries(e.query).forEach(([t,n])=>{n!==void 0&&r.searchParams.set(t,String(n));}),r.toString()}runRequestMiddleware(e){return (this.options.middleware??[]).reduce(async(t,n)=>{let i=await t;return n.onRequest?n.onRequest(i):i},Promise.resolve(e))}runResponseMiddleware(e){return (this.options.middleware??[]).reduce(async(t,n)=>{let i=await t;return n.onResponse?n.onResponse(i):i},Promise.resolve(e))}async runErrorMiddleware(e){let r=(this.options.middleware??[]).map(t=>t.onError).filter(t=>!!t);await Promise.all(r.map(t=>t(e)));}async parseResponse(e){return e.status===204?null:(e.headers.get("content-type")??"").includes("application/json")?await e.json():await e.text()}toError(e){return e instanceof Error?e:new Error("Unknown request error")}isAbortError(e){return e instanceof DOMException&&e.name==="AbortError"}};var H="localization:listResources",b=class{constructor(e,r,t){this.cacheProvider=e;this.cacheTtlMs=r;this.logger=t;}async getListResources(){this.logger.debug(`listResources:start cacheEnabled=${!!this.cacheProvider}`);let e=await this.cacheProvider?.get(H);return e?this.logger.info(`listResources:cache-hit count=${e.length}`):this.logger.debug("listResources:cache-miss"),e}async storeListResources(e){await this.cacheProvider?.set(H,e,this.cacheTtlMs),this.logger.debug(`listResources:cache-store ttlMs=${this.cacheTtlMs??0} count=${e.length}`);}async invalidate(e){if(this.logger.debug(`invalidateCache:start scope=${e??"all"}`),!this.cacheProvider){this.logger.debug("invalidateCache:skipped no-cache-provider");return}if(e){await this.cacheProvider.delete(e),this.logger.info(`invalidateCache:deleted key=${e}`);return}await this.cacheProvider.clear(),this.logger.info("invalidateCache:cleared-all");}};var C=class{constructor(e){this.logger=e;}async run(e,r){try{return await r()}catch(t){let n=this.map(t);throw this.logger.errorForOperation(e,n,t),n}}validateRequired(e,r){if(!e?.trim())throw new a(`${r} is required`)}map(e){return e instanceof a?e:e instanceof v?new m(e.message):e instanceof l?new p(e.message):e instanceof f?this.mapStatusError(e):new a("Unexpected localization SDK error")}preserveCause(e){let r=this.map(e);return r.cause??(r.cause=e),r}mapStatusError(e){return e.statusCode===401||e.statusCode===403?new d("Invalid token for localization endpoint",{statusCode:e.statusCode}):e.statusCode===404?new h("Localization resource was not found",{statusCode:e.statusCode}):e.statusCode>=500?new g("Localization API is unavailable",{statusCode:e.statusCode}):new a(e.message,{statusCode:e.statusCode})}};var S="[LocalizationSdk]",E=class{constructor(e=false){this.enabled=e;}debug(e){this.write("debug",e);}info(e){this.write("info",e);}errorForOperation(e,r,t){this.write("error",`${e}:error ${this.formatErrorDetails(r,t)}`);}formatErrorDetails(e,r){let t=this.getOriginalCause(e,r),n=this.getErrorMessage(t),i=[`type=${e.name}`,`message=${e.message}`];return n&&n!==e.message&&i.push(`original=${n}`),e instanceof a&&e.metadata?.statusCode&&i.push(`statusCode=${e.metadata.statusCode}`),i.join(" ")}getOriginalCause(e,r){let n=e.cause??r;return n instanceof l?n.causeError:n}getErrorMessage(e){return e instanceof Error?e.message:typeof e=="string"?e:"unknown-error"}write(e,r){if(!this.enabled)return;let t=this.resolveIcon(e,r),n=`${S} ${t} ${r}`;switch(e){case "debug":console.debug(n);break;case "info":console.info(n);break;case "error":console.error(n);break}}resolveIcon(e,r){return e==="error"||r.includes(":error")?"\u274C":r.includes("request:start")||r.includes(":api-call")?"\u{1F310}":r.includes("request:success")?"\u{1F4E1}":r.includes(":cache-hit")||r.includes("cache-hit")?"\u{1F5C4}\uFE0F":r.includes("cache-miss")?"\u{1F4ED}":r.includes("cache-store")?"\u{1F4BE}":r.includes("invalidateCache")?"\u{1F9F9}":r.includes("listResources")?"\u{1F4DA}":r.includes("getByLanguage")?"\u{1F30D}":r.includes("getCurrentLanguage")?"\u{1F22F}":r.includes(":start")?"\u{1F680}":r.includes(":success")?"\u2705":e==="info"?"\u2139\uFE0F":"\u{1F50E}"}};var P=class{constructor(e){this.dependencies=e;this.logger=new E(e.enableLogs),this.cacheHelper=new b(e.cacheProvider,e.cacheTtlMs,this.logger),this.errorHandler=new C(this.logger);}async getCurrentLanguage(e,r){return this.errorHandler.run("getCurrentLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.logger.debug(`getCurrentLanguage:start resourceKey=${e}`),this.isCacheEnabled()){let n=await this.resolveFromCachedResources(e);return this.logger.info(`getCurrentLanguage:cache-${n?"hit":"miss"} resourceKey=${e} hasValue=${!!n}`),n}this.logger.info(`getCurrentLanguage:api-call path=api/localization/client/currentlanguage resourceKey=${e}`);let t=await this.send({method:"GET",path:"api/localization/client/currentlanguage",query:{resourceKey:e},headers:this.resolveLocaleHeader(r)});return this.logger.info(`getCurrentLanguage:success resourceKey=${e} hasValue=${!!t}`),t??""})}async getByLanguage(e,r,t){return this.errorHandler.run("getByLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.errorHandler.validateRequired(r,"languageKey"),this.logger.debug(`getByLanguage:start resourceKey=${e} languageKey=${r}`),this.isCacheEnabled()){let i=await this.resolveFromCachedResources(e,r);return this.logger.info(`getByLanguage:cache-${i?"hit":"miss"} resourceKey=${e} languageKey=${r} hasValue=${!!i}`),i}this.logger.info(`getByLanguage:api-call path=api/localization/client/bylanguage resourceKey=${e} languageKey=${r}`);let n=await this.send({method:"GET",path:"api/localization/client/bylanguage",query:{resourceKey:e,languageKey:r},headers:this.resolveLocaleHeader(t)});return this.logger.info(`getByLanguage:success resourceKey=${e} languageKey=${r} hasValue=${!!n}`),n??""})}async listResources(){return this.errorHandler.run("listResources",async()=>{if(this.isCacheEnabled()){let t=await this.cacheHelper.getListResources();if(t)return this.logger.info(`listResources:cache-hit-return count=${t.length}`),t}else this.logger.debug("listResources:cache-disabled");this.logger.info("listResources:api-call path=api/localization/client/list");let r=(await this.send({method:"GET",path:"api/localization/client/list"})??[]).map(t=>({key:t.resourceKey,value:t.value,language:t.languageKey}));return this.isCacheEnabled()&&await this.cacheHelper.storeListResources(r),this.logger.info(`listResources:success count=${r.length}`),r})}async invalidateCache(e){return this.errorHandler.run("invalidateCache",async()=>this.cacheHelper.invalidate(e))}async clearCache(){return this.errorHandler.run("clearCache",async()=>this.cacheHelper.invalidate())}async resolveFromCachedResources(e,r){return (await this.listResources()).find(i=>i.key!==e?false:r===void 0?true:i.language===r)?.value??""}async send(e){try{let r=await this.dependencies.authProvider?.getToken(),t=r?{...e.headers,"X-Auth-Token":r}:e.headers;this.logger.debug(`request:start method=${e.method} path=${e.path} hasAuth=${!!r}`);let n=await this.dependencies.httpTransport.request({...e,headers:t});return this.logger.debug(`request:success method=${e.method} path=${e.path} status=${n.status}`),n.data}catch(r){throw this.errorHandler.preserveCause(r)}}resolveLocaleHeader(e){let r=e?.locale?.trim()||this.dependencies.locale?.trim()||this.resolveBrowserLocale();if(r)return {"Accept-Language":r}}resolveBrowserLocale(){return globalThis.navigator?.language?.trim()||void 0}isCacheEnabled(){if(this.dependencies.cacheEnabled!==void 0)return this.logger.debug(`isCacheEnabled: enabled=${this.dependencies.cacheEnabled} source=cacheEnabled-flag`),this.dependencies.cacheEnabled;let e=!!this.dependencies.cacheProvider;return this.logger.debug(`isCacheEnabled: enabled=${e} source=cacheProvider`),e}};function $(o){M(o);let e=o.cache?.enabled??false,r=e?o.cache?.provider??new u:void 0,t=new L({baseUrl:o.baseUrl,fetchFn:o.fetchFn,timeoutMs:o.timeoutMs??1e4,defaultHeaders:o.headers,middleware:o.middleware});return new P({httpTransport:t,authProvider:o.authProvider??(o.token?new c(o.token):void 0),locale:o.locale,cacheEnabled:e,cacheProvider:r,cacheTtlMs:o.cache?.ttlMs,enableLogs:o.enableLogs??false})}function M(o){if(!o?.baseUrl?.trim())throw new a("baseUrl is required to create localization client")}var R=class{constructor(e){this.storage=e;}get(e){let r=this.storage.getItem(e);if(!r)return Promise.resolve(null);let t=this.safeParse(r);return t?t.expiresAt!==void 0&&Date.now()>t.expiresAt?(this.storage.removeItem(e),Promise.resolve(null)):Promise.resolve(t.value):(this.storage.removeItem(e),Promise.resolve(null))}set(e,r,t){let n=t&&t>0?Date.now()+t:void 0,i={value:r,expiresAt:n};return this.storage.setItem(e,JSON.stringify(i)),Promise.resolve()}delete(e){return this.storage.removeItem(e),Promise.resolve()}clear(){return this.storage.clear(),Promise.resolve()}safeParse(e){try{return JSON.parse(e)}catch{return null}}},T=class extends R{constructor(){super(k("localStorage"));}},z=class extends R{constructor(){super(k("sessionStorage"));}};function k(o){let e=globalThis.window===void 0?void 0:globalThis.window[o];return e||O()}function O(){let o=new Map;return {get length(){return o.size},clear:()=>{o.clear();},getItem:e=>o.get(e)??null,key:e=>Array.from(o.keys())[e]??null,removeItem:e=>{o.delete(e);},setItem:(e,r)=>{o.set(e,r);}}}exports.LocalStorageCacheProvider=T;exports.LocalizationAuthError=d;exports.LocalizationError=a;exports.LocalizationNetworkError=p;exports.LocalizationServerError=g;exports.LocalizationTimeoutError=m;exports.MemoryCacheProvider=u;exports.ResourceNotFoundError=h;exports.SessionStorageCacheProvider=z;exports.XAuthTokenProvider=c;exports.createClient=$;exports.createLocalizationClient=$;return exports;})({});
1
+ var LocalizationSDK=(function(exports){'use strict';var d=class{constructor(e){this.token=e;}getToken(){return Promise.resolve(this.token?.trim()?this.token:null)}};var h=class{constructor(){this.store=new Map;}get(e){let r=this.store.get(e);return r?r.expiresAt!==void 0&&Date.now()>r.expiresAt?(this.store.delete(e),Promise.resolve(null)):Promise.resolve(r.value):Promise.resolve(null)}set(e,r,t){let o=t&&t>0?Date.now()+t:void 0;return this.store.set(e,{value:r,expiresAt:o}),Promise.resolve()}delete(e){return this.store.delete(e),Promise.resolve()}clear(){return this.store.clear(),Promise.resolve()}};var s=class extends Error{constructor(r,t){super(r);this.metadata=t;this.name="LocalizationError";}},g=class extends s{constructor(e="Authentication failed",r){super(e,r),this.name="LocalizationAuthError";}},m=class extends s{constructor(e="Resource not found",r){super(e,r),this.name="ResourceNotFoundError";}},p=class extends s{constructor(e="Localization server error",r){super(e,r),this.name="LocalizationServerError";}},f=class extends s{constructor(e="Network error while contacting localization API",r){super(e,r),this.name="LocalizationNetworkError";}},y=class extends s{constructor(e="Localization request timeout",r){super(e,r),this.name="LocalizationTimeoutError";}};var v=class extends Error{constructor(r,t,o){super(`Request failed with status ${r}`);this.statusCode=r;this.responseBody=t;this.responseHeaders=o;this.name="HttpStatusError";}},w=class extends Error{constructor(r){super(`Request timed out after ${r}ms`);this.timeoutMs=r;this.name="HttpTimeoutError";}},l=class extends Error{constructor(r){super("Network error while sending request");this.causeError=r;this.name="HttpNetworkError";}},L=class{constructor(e){this.options=e;this.fetchFn=e.fetchFn??globalThis.fetch.bind(globalThis);}async request(e){let r=e.timeoutMs??this.options.timeoutMs,t=new AbortController,o=setTimeout(()=>t.abort(),r),n=new Request(this.resolveUrl(e),{method:e.method,headers:{"Content-Type":"application/json",...this.options.defaultHeaders,...e.headers},body:e.body===void 0?void 0:JSON.stringify(e.body),signal:t.signal});try{let c=await this.runRequestMiddleware(n),u;try{u=await this.fetchFn(c);}catch(b){throw this.isAbortError(b)?new w(r):new l(b)}let a=await this.runResponseMiddleware(u);if(!a.ok){let b=await a.text();throw new v(a.status,b,a.headers)}let $=await this.parseResponse(a);return {status:a.status,headers:a.headers,data:$}}catch(c){throw await this.runErrorMiddleware(this.toError(c)),c}finally{clearTimeout(o);}}resolveUrl(e){let r=new URL(e.path,this.options.baseUrl);return e.query&&Object.entries(e.query).forEach(([t,o])=>{o!==void 0&&r.searchParams.set(t,String(o));}),r.toString()}runRequestMiddleware(e){return (this.options.middleware??[]).reduce(async(t,o)=>{let n=await t;return o.onRequest?o.onRequest(n):n},Promise.resolve(e))}runResponseMiddleware(e){return (this.options.middleware??[]).reduce(async(t,o)=>{let n=await t;return o.onResponse?o.onResponse(n):n},Promise.resolve(e))}async runErrorMiddleware(e){let r=(this.options.middleware??[]).map(t=>t.onError).filter(t=>!!t);await Promise.all(r.map(t=>t(e)));}async parseResponse(e){return e.status===204?null:(e.headers.get("content-type")??"").includes("application/json")?await e.json():await e.text()}toError(e){return e instanceof Error?e:new Error("Unknown request error")}isAbortError(e){return e instanceof DOMException&&e.name==="AbortError"}};var H="localization:listResources",C=class{constructor(e,r,t){this.cacheProvider=e;this.cacheTtlMs=r;this.logger=t;}async getListResources(){this.logger.debug(`listResources:start cacheEnabled=${!!this.cacheProvider}`);let e=await this.cacheProvider?.get(H);return e?this.logger.info(`listResources:cache-hit count=${e.length}`):this.logger.debug("listResources:cache-miss"),e}async storeListResources(e){await this.cacheProvider?.set(H,e,this.cacheTtlMs),this.logger.debug(`listResources:cache-store ttlMs=${this.cacheTtlMs??0} count=${e.length}`);}async invalidate(e){if(this.logger.debug(`invalidateCache:start scope=${e??"all"}`),!this.cacheProvider){this.logger.debug("invalidateCache:skipped no-cache-provider");return}if(e){await this.cacheProvider.delete(e),this.logger.info(`invalidateCache:deleted key=${e}`);return}await this.cacheProvider.clear(),this.logger.info("invalidateCache:cleared-all");}};var E=class{constructor(e){this.logger=e;}async run(e,r){try{return await r()}catch(t){let o=this.map(t);throw this.logger.errorForOperation(e,o,t),o}}validateRequired(e,r){if(!e?.trim())throw new s(`${r} is required`)}map(e){return e instanceof s?e:e instanceof w?new y(e.message):e instanceof l?new f(e.message):e instanceof v?this.mapStatusError(e):new s("Unexpected localization SDK error")}preserveCause(e){let r=this.map(e);return r.cause??(r.cause=e),r}mapStatusError(e){return e.statusCode===401||e.statusCode===403?new g("Invalid token for localization endpoint",{statusCode:e.statusCode}):e.statusCode===404?new m("Localization resource was not found",{statusCode:e.statusCode}):e.statusCode>=500?new p("Localization API is unavailable",{statusCode:e.statusCode}):new s(e.message,{statusCode:e.statusCode})}};var A="[LocalizationSdk]",R=class{constructor(e=false){this.enabled=e;}debug(e){this.write("debug",e);}info(e){this.write("info",e);}errorForOperation(e,r,t){this.write("error",`${e}:error ${this.formatErrorDetails(r,t)}`);}formatErrorDetails(e,r){let t=this.getOriginalCause(e,r),o=this.getErrorMessage(t),n=[`type=${e.name}`,`message=${e.message}`];return o&&o!==e.message&&n.push(`original=${o}`),e instanceof s&&e.metadata?.statusCode&&n.push(`statusCode=${e.metadata.statusCode}`),n.join(" ")}getOriginalCause(e,r){let o=e.cause??r;return o instanceof l?o.causeError:o}getErrorMessage(e){return e instanceof Error?e.message:typeof e=="string"?e:"unknown-error"}write(e,r){if(!this.enabled)return;let t=this.resolveIcon(e,r),o=`${A} ${t} ${r}`;switch(e){case "debug":console.debug(o);break;case "info":console.info(o);break;case "error":console.error(o);break}}resolveIcon(e,r){return e==="error"||r.includes(":error")?"\u274C":r.includes("request:start")||r.includes(":api-call")?"\u{1F310}":r.includes("request:success")?"\u{1F4E1}":r.includes(":cache-hit")||r.includes("cache-hit")?"\u{1F5C4}\uFE0F":r.includes("cache-miss")?"\u{1F4ED}":r.includes("cache-store")?"\u{1F4BE}":r.includes("invalidateCache")?"\u{1F9F9}":r.includes("listResources")?"\u{1F4DA}":r.includes("getByLanguage")?"\u{1F30D}":r.includes("getCurrentLanguage")?"\u{1F22F}":r.includes(":start")?"\u{1F680}":r.includes(":success")?"\u2705":e==="info"?"\u2139\uFE0F":"\u{1F50E}"}};var P=class{constructor(e){this.dependencies=e;this.logger=new R(e.enableLogs),this.cacheHelper=new C(e.cacheProvider,e.cacheTtlMs,this.logger),this.errorHandler=new E(this.logger);}async getCurrentLanguage(e,r){return this.errorHandler.run("getCurrentLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.logger.debug(`getCurrentLanguage:start resourceKey=${e}`),this.isCacheEnabled()){let o=await this.resolveFromCachedResources(e);return this.logger.info(`getCurrentLanguage:cache-${o?"hit":"miss"} resourceKey=${e} hasValue=${!!o}`),o}this.logger.info(`getCurrentLanguage:api-call path=api/localization/client/currentlanguage resourceKey=${e}`);let t=await this.send({method:"GET",path:"api/localization/client/currentlanguage",query:{resourceKey:e},headers:this.resolveLocaleHeader(r)});return this.logger.info(`getCurrentLanguage:success resourceKey=${e} hasValue=${!!t}`),t??""})}async getByLanguage(e,r,t){return this.errorHandler.run("getByLanguage",async()=>{if(this.errorHandler.validateRequired(e,"resourceKey"),this.errorHandler.validateRequired(r,"languageKey"),this.logger.debug(`getByLanguage:start resourceKey=${e} languageKey=${r}`),this.isCacheEnabled()){let n=await this.resolveFromCachedResources(e,r);return this.logger.info(`getByLanguage:cache-${n?"hit":"miss"} resourceKey=${e} languageKey=${r} hasValue=${!!n}`),n}this.logger.info(`getByLanguage:api-call path=api/localization/client/bylanguage resourceKey=${e} languageKey=${r}`);let o=await this.send({method:"GET",path:"api/localization/client/bylanguage",query:{resourceKey:e,languageKey:r},headers:this.resolveLocaleHeader(t)});return this.logger.info(`getByLanguage:success resourceKey=${e} languageKey=${r} hasValue=${!!o}`),o??""})}async listResources(){return this.errorHandler.run("listResources",async()=>{if(this.isCacheEnabled()){let t=await this.cacheHelper.getListResources();if(t)return this.logger.info(`listResources:cache-hit-return count=${t.length}`),t}else this.logger.debug("listResources:cache-disabled");this.logger.info("listResources:api-call path=api/localization/client/list");let r=(await this.send({method:"GET",path:"api/localization/client/list"})??[]).map(t=>({key:t.resourceKey,value:t.value,language:t.languageKey}));return this.isCacheEnabled()&&await this.cacheHelper.storeListResources(r),this.logger.info(`listResources:success count=${r.length}`),r})}async invalidateCache(e){return this.errorHandler.run("invalidateCache",async()=>this.cacheHelper.invalidate(e))}async clearCache(){return this.errorHandler.run("clearCache",async()=>this.cacheHelper.invalidate())}async submitKey(e,r,t,o,n){return this.submitKeys({keys:[{resourceKey:e,sourceFileName:n,translations:{[r]:o?{suggestedValue:t,description:o}:t}}]})}async submitKeyWithTranslations(e,r,t){return this.submitKeys({keys:[{resourceKey:e,translations:r,sourceFileName:t}]})}async submitKeys(e){return this.errorHandler.run("submitKeys",async()=>{let r=this.buildSubmitPayload(e);this.logger.info(`submitKeys:api-call path=api/localization/client/submit-keys count=${r.keys.length}`);let t=await this.send({method:"POST",path:"api/localization/client/submit-keys",body:r});return this.mapSubmitResult(t)})}async resolveFromCachedResources(e,r){return (await this.listResources()).find(n=>n.key!==e?false:r===void 0?true:n.language===r)?.value??""}async send(e){try{let r=await this.dependencies.authProvider?.getToken(),t=r?{...e.headers,"X-Auth-Token":r}:e.headers;this.logger.debug(`request:start method=${e.method} path=${e.path} hasAuth=${!!r}`);let o=await this.dependencies.httpTransport.request({...e,headers:t});return this.logger.debug(`request:success method=${e.method} path=${e.path} status=${o.status}`),o.data}catch(r){throw this.errorHandler.preserveCause(r)}}resolveLocaleHeader(e){let r=e?.locale?.trim()||this.dependencies.locale?.trim()||this.resolveBrowserLocale();if(r)return {"Accept-Language":r}}resolveBrowserLocale(){return globalThis.navigator?.language?.trim()||void 0}buildSubmitPayload(e){if(!e?.keys?.length)throw new s("At least one key is required.");return {keys:e.keys.map(t=>{this.errorHandler.validateRequired(t.resourceKey,"resourceKey");let o=Object.entries(t.translations??{});if(o.length===0)throw new s(`Translations are required for '${t.resourceKey}'.`);return {resourceKey:t.resourceKey.trim(),sourceFileName:M(t.sourceFileName),valueFormat:t.valueFormat??0,submittedByUserName:e.authorName,submittedByUserEmail:e.authorEmail,translations:o.map(([n,c])=>{let u=K(c);return this.errorHandler.validateRequired(n,"languageKey"),this.errorHandler.validateRequired(u.suggestedValue,"suggestedValue"),{languageKey:n.trim(),suggestedValue:u.suggestedValue.trim(),description:u.description?.trim()||void 0}})}})}}mapSubmitResult(e){let r=(e?.errors??[]).map(t=>t.description||t.code||"").filter(t=>t.length>0);return {success:!!e?.success&&r.length===0,statusCode:e?.statusCode??202,acceptedCount:e?.data?.acceptedCount??0,versionId:e?.data?.versionId??0,environment:e?.data?.environment??0,message:e?.message,errors:r,rejectedKeys:e?.data?.rejectedKeys??[]}}isCacheEnabled(){if(this.dependencies.cacheEnabled!==void 0)return this.logger.debug(`isCacheEnabled: enabled=${this.dependencies.cacheEnabled} source=cacheEnabled-flag`),this.dependencies.cacheEnabled;let e=!!this.dependencies.cacheProvider;return this.logger.debug(`isCacheEnabled: enabled=${e} source=cacheProvider`),e}};function K(i){return typeof i=="string"?{suggestedValue:i}:i}function M(i){let e=i?.trim();if(!e)return;let r=e.split(/[/\\]/);return r[r.length-1]||void 0}function x(i){q(i);let e=i.cache?.enabled??false,r=e?i.cache?.provider??new h:void 0,t=new L({baseUrl:i.baseUrl,fetchFn:i.fetchFn,timeoutMs:i.timeoutMs??1e4,defaultHeaders:i.headers,middleware:i.middleware});return new P({httpTransport:t,authProvider:i.authProvider??(i.token?new d(i.token):void 0),locale:i.locale,cacheEnabled:e,cacheProvider:r,cacheTtlMs:i.cache?.ttlMs,enableLogs:i.enableLogs??false})}function q(i){if(!i?.baseUrl?.trim())throw new s("baseUrl is required to create localization client")}var T=class{constructor(e){this.storage=e;}get(e){let r=this.storage.getItem(e);if(!r)return Promise.resolve(null);let t=this.safeParse(r);return t?t.expiresAt!==void 0&&Date.now()>t.expiresAt?(this.storage.removeItem(e),Promise.resolve(null)):Promise.resolve(t.value):(this.storage.removeItem(e),Promise.resolve(null))}set(e,r,t){let o=t&&t>0?Date.now()+t:void 0,n={value:r,expiresAt:o};return this.storage.setItem(e,JSON.stringify(n)),Promise.resolve()}delete(e){return this.storage.removeItem(e),Promise.resolve()}clear(){return this.storage.clear(),Promise.resolve()}safeParse(e){try{return JSON.parse(e)}catch{return null}}},z=class extends T{constructor(){super(k("localStorage"));}},S=class extends T{constructor(){super(k("sessionStorage"));}};function k(i){let e=globalThis.window===void 0?void 0:globalThis.window[i];return e||O()}function O(){let i=new Map;return {get length(){return i.size},clear:()=>{i.clear();},getItem:e=>i.get(e)??null,key:e=>Array.from(i.keys())[e]??null,removeItem:e=>{i.delete(e);},setItem:(e,r)=>{i.set(e,r);}}}exports.LocalStorageCacheProvider=z;exports.LocalizationAuthError=g;exports.LocalizationError=s;exports.LocalizationNetworkError=f;exports.LocalizationServerError=p;exports.LocalizationTimeoutError=y;exports.MemoryCacheProvider=h;exports.ResourceNotFoundError=m;exports.SessionStorageCacheProvider=S;exports.XAuthTokenProvider=d;exports.createClient=x;exports.createLocalizationClient=x;return exports;})({});
package/package.json CHANGED
@@ -23,17 +23,17 @@
23
23
  },
24
24
  "unpkg": "./dist/umd/localization-sdk.min.js",
25
25
  "jsdelivr": "./dist/umd/localization-sdk.min.js",
26
- "version": "1.0.5412",
26
+ "version": "1.0.5484",
27
27
  "engines": {
28
28
  "node": "^22.22.3 || ^24.15.0 || >=26.0.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@angular/core": "^22.2.3",
32
- "@angular/common": "^22.2.3",
33
- "@angular/compiler": "^22.2.3",
34
- "@angular/compiler-cli": "^22.2.3",
35
- "@angular/platform-browser": "^22.2.3",
36
- "@angular/platform-browser-dynamic": "^22.2.3",
31
+ "@angular/core": "^22.2.4",
32
+ "@angular/common": "^22.2.4",
33
+ "@angular/compiler": "^22.2.4",
34
+ "@angular/compiler-cli": "^22.2.4",
35
+ "@angular/platform-browser": "^22.2.4",
36
+ "@angular/platform-browser-dynamic": "^22.2.4",
37
37
  "jest-preset-angular": "^16.1.5",
38
38
  "graceful-fs": "^4.2.11",
39
39
  "istanbul-lib-coverage": "^3.2.2",