@localazy/cdn-client
Version:
Node.js module that allows you to easily interact with the Localazy CDN.
7 lines (6 loc) • 11 kB
JavaScript
var e=Object.defineProperty,t=(t,s,i)=>(((t,s,i)=>{s in t?e(t,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[s]=i})(t,"symbol"!=typeof s?s+"":s,i),i);
/* @localazy/cdn-client@1.5.2
* (c) 2024 Localazy <team@localazy.com>
* @license MIT */
class s{constructor(e){t(this,"context"),this.context=e}async fetchLocale(e){return this.context.cache.has(e)?new Promise((t=>{t(this.context.cache.get(e))})):this.context.client.get(e.metafileLocale.uri)}async fetchMetafile(){return await this.context.client.get(this.context.metafile.params.jsonPath)}}const i=e=>"string"==typeof e,a=e=>void 0===e,l=e=>Array.isArray(e),r=e=>"[object Object]"===Object.prototype.toString.call(e),o=e=>[...new Set(e)],c=(e,t)=>{const s={};return e.filter((e=>{const i=t(e);return!Object.hasOwn(s,i)&&(s[i]=!0,!0)}))};class n{constructor(){t(this,"map"),this.map=new Map}get(e){return this.map.get(e)}has(e){return this.map.has(e)}set(e,t){this.map.set(e,t)}flush(){this.map=new Map}}class h{constructor(e){t(this,"context"),t(this,"cacheAdapter"),this.context=e,this.cacheAdapter=new n}setIfMissed(e){const{metafileFile:t,metafileLocale:s,data:i}=e,a=this.keyFromMetafile({metafileFile:t,metafileLocale:s});this.cacheAdapter.has(a)||this.cacheAdapter.set(a,i)}has(e){const t=this.keyFromMetafile(e);return this.cacheAdapter.has(t)}get(e){const t=this.keyFromMetafile(e);return this.cacheAdapter.get(t)}flush(){this.cacheAdapter.flush()}keyFromMetafile(e){const{metafileFile:t,metafileLocale:s}=e,i=[...o(t.productFlavors)].sort().join("-");return[this.context.metafile.params.cdnId,t.id,t.file,t.path,t.library,t.module,t.buildType,i,s.locale,s.timestamp.toString()].filter((e=>""!==e)).join("-")}}class u{constructor(e){t(this,"context"),this.context=e}}class p extends u{constructor(){super(...arguments),t(this,"flush",(()=>{this.context.cache.flush()}))}}class f{constructor(e,s){t(this,"language"),t(this,"region"),t(this,"script"),t(this,"isRtl"),t(this,"name"),t(this,"localizedName"),t(this,"uri"),t(this,"timestamp"),t(this,"baseLocale"),this.language=e.language,this.region=e.region,this.script=e.script,this.isRtl=e.isRtl,this.name=e.name,this.localizedName=e.localizedName,this.uri=e.uri,this.timestamp=e.timestamp,this.baseLocale=s}get locale(){return this.language&&this.region&&this.script?`${this.language}_${this.region}#${this.script}`:this.language&&this.script?`${this.language}#${this.script}`:this.language&&this.region?`${this.language}_${this.region}`:this.language}get isBaseLocale(){return this.locale===this.baseLocale}toCdnLocale(){return{locale:this.locale,isBaseLocale:this.isBaseLocale,language:this.language,region:this.region,script:this.script,isRtl:this.isRtl,name:this.name,localizedName:this.localizedName}}}class d{constructor(e){t(this,"id"),t(this,"file"),t(this,"path"),t(this,"library"),t(this,"module"),t(this,"buildType"),t(this,"timestamp"),t(this,"productFlavors"),t(this,"locales"),t(this,"baseUrl"),this.id=e.id,this.file=e.file,this.path=e.path,this.library=e.library,this.module=e.module,this.buildType=e.buildType,this.timestamp=e.timestamp,this.productFlavors=e.productFlavors,this.locales=e.locales,this.baseUrl=e.baseUrl}toCdnFile(){return{id:this.id,file:this.file,path:this.path,library:this.library,module:this.module,buildType:this.buildType,productFlavors:this.productFlavors,locales:this.locales.map((e=>({locale:e.locale,isBaseLocale:e.isBaseLocale,uri:`${this.baseUrl}${e.uri}`})))}}}class m{constructor(e,s){t(this,"projectUrl"),t(this,"baseLocale"),t(this,"locales"),t(this,"timestamp"),t(this,"files"),t(this,"filesMap"),this.projectUrl=e.projectUrl,this.timestamp=e.timestamp,this.files=m.filesFactory(e.files,e.baseLocale,s),this.filesMap=m.filesMapFactory(this.files),this.locales=m.localesFactory(this.files),this.baseLocale=this.locales.find((e=>e.isBaseLocale))}static createEmpty(e){return new m({projectUrl:"",baseLocale:"",timestamp:0,files:{}},e)}static filesFactory(e,t,s){return Object.keys(e).reduce(((i,a)=>{const l=e[a].locales.map((e=>new f(e,t)));return i.push(new d({...e[a],id:a,locales:l,baseUrl:s.baseUrl})),i}),[])}static filesMapFactory(e){return e.reduce(((e,t)=>(e[t.id]=t,e)),{})}static localesFactory(e){const t=e.reduce(((e,t)=>(e.push(...t.locales.map((e=>e.toCdnLocale()))),e)),[]);return c(t,(e=>e.locale))}}class g{constructor(e){t(this,"options"),this.options=g.parseMetafileUrl(e)}get url(){return this.options.url}get baseUrl(){return this.options.baseUrl}get cdnId(){return this.options.cdnId}get jsonPath(){return this.options.jsonPath}static parseMetafileUrl(e){let t;try{t=new URL(e)}catch(e){throw new Error('Invalid param: "options.metafile" cannot be parsed as url.')}const s=t.pathname.match(/^\/(.*?)\/(.*?)\.(v2.json|js|ts)$/);if(null===s||4!==s.length)throw new Error('Invalid param: "options.metafile" contains invalid metafile url.');const i=s[1],a=s[2];return{url:e,baseUrl:t.origin,cdnId:i,jsonPath:`/${i}/${a}.v2.json`}}}class w{constructor(e){t(this,"params"),t(this,"parsedData"),t(this,"data"),this.params=new g(e.metafile),this.parsedData=null,this.data=m.createEmpty(this.params)}setMetafile(e){this.parsedData=e,this.data=new m(e,this.params)}}class x{constructor(e){t(this,"context"),this.context=e}createCdnResponse(e){const{requests:t,responses:s,hasSingleFileResponse:i,hasSingleLocaleResponse:a}=e;return 0===s.length?{}:(this.cacheResponses(t,s),i&&a?s[0]:x.transformResponses(e))}cacheResponses(e,t){t.forEach(((t,s)=>{const{metafileFile:i,metafileLocale:a}=e[s];i&&a&&this.context.cache.setIfMissed({metafileFile:i,metafileLocale:a,data:t})}))}static transformResponses(e){const{requests:t,responses:s,hasSingleFileResponse:i}=e;return s.reduce(((e,s,a)=>{const{metafileFile:l,metafileLocale:r}=t[a];return l&&r&&(i?e[r.locale]=s:(e[l.id]||(e[l.id]={}),e[l.id][r.locale]=s)),e}),{})}}class b{constructor(e){t(this,"metafile"),t(this,"cdn"),t(this,"client"),t(this,"api"),t(this,"cache"),t(this,"responseFactory"),this.metafile=e.metafileContext,this.cdn=e.cdn,this.client=e.client,this.api=new s(this),this.cache=new h(this),this.responseFactory=new x(this)}}class y extends u{constructor(){super(...arguments),t(this,"locales",(e=>{const{excludeBaseLocale:t}=e||{},{locales:s}=this.context.metafile.data;return t?s.filter((e=>!e.isBaseLocale)):s})),t(this,"refresh",(async()=>{const e=await this.context.api.fetchMetafile();this.context.metafile.setMetafile(e)})),t(this,"switch",(async e=>{this.context.metafile.params=new g(e.metafile),await this.refresh()}))}get projectUrl(){return this.context.metafile.data.projectUrl}get baseLocale(){return this.context.metafile.data.baseLocale}get url(){return this.context.metafile.params.url}get files(){return this.context.metafile.data.files.map((e=>e.toCdnFile()))}}class F{constructor(e){t(this,"data"),t(this,"context"),this.context=e.context,this.data=e.data||{}}}class L{constructor(e){t(this,"files"),t(this,"localesMap"),t(this,"hasSingleFileResponse"),t(this,"hasSingleLocaleResponse"),t(this,"context"),this.files=[],this.localesMap=new F({context:e}),this.hasSingleFileResponse=!1,this.hasSingleLocaleResponse=!1,this.context=e}async execute(){const e=this.getPromises(),t=e.map((e=>e[0])),s=e.map((e=>e[1])),i=await Promise.all(t);return this.context.responseFactory.createCdnResponse({requests:s,responses:i,localesMap:this.localesMap,hasSingleFileResponse:this.hasSingleFileResponse,hasSingleLocaleResponse:this.hasSingleLocaleResponse})}getPromises(){return this.files.reduce(((e,t)=>(this.localesMap.data[t.id]&&e.push(...this.localesMap.data[t.id].map((e=>{const s={metafileFile:t,metafileLocale:e};return[this.context.api.fetchLocale(s),s]}))),e)),[])}}class R{constructor(e){t(this,"context"),t(this,"request"),this.context=e,this.request=new L(this.context)}addFiles(e){if(!(r(e)||i(e)||a(e)||l(e)))throw new Error('Invalid param: "request.files" must be object, array, string or undefined.');if(l(e)&&e.forEach((e=>{if(!r(e)&&!i(e))throw new Error('Invalid param: array "request.files" must contain objects or strings.')})),i(e)){this.request.hasSingleFileResponse=!0;const t=this.context.metafile.data.files.find((t=>t.id===e));if(!(t instanceof d))throw new Error(`File not found: "${e}".`);this.request.files=[t]}else if(a(e))this.request.files=[...this.context.metafile.data.files];else if(l(e))this.request.files=e.map((e=>{let t;if(i(e)){const s=this.context.metafile.data.files.find((t=>t.id===e));if(a(s))throw new Error(`File not found: "${e}".`);t=s}else{const s=this.context.metafile.data.files.find((t=>t.id===e.id));if(a(s))throw new Error(`File not found: "${e.id}".`);t=s}return t}));else if(r(e)){this.request.hasSingleFileResponse=!0;const t=this.context.metafile.data.files.find((t=>t.id===e.id));if(a(t))throw new Error(`File not found: "${e.id}".`);this.request.files=[t]}return this}addLocales(e,t){if(!(i(e)||a(e)||l(e)))throw new Error('Invalid param: "request.locales" must be array, string or undefined.');return l(e)&&e.forEach((e=>{if(!i(e))throw new Error('Invalid param: array "request.locales" must contain strings.')})),i(e)?(this.request.hasSingleLocaleResponse=!0,this.request.files.reduce(((t,s)=>(t.data[s.id]=s.locales.filter((t=>t.locale===e)),t)),this.request.localesMap)):a(e)?this.request.files.reduce(((e,s)=>(e.data[s.id]=t?s.locales.filter((e=>!e.isBaseLocale)):s.locales,e)),this.request.localesMap):l(e)&&this.request.files.reduce(((t,s)=>(t.data[s.id]=s.locales.filter((t=>e.includes(t.locale))),t)),this.request.localesMap),this}getCdnRequest(){const e=this.request;return this.request=new L(this.context),e}}class q{constructor(e){t(this,"baseUrl"),this.baseUrl=e}async get(e){const t=await fetch(`${this.baseUrl}${e}`),s=t.headers.get("content-type"),i="application/json5"===s||"application/json"===s;if(t.status>=400)throw new Error(`Request failed with status code ${t.status}`);let a;return a=i?await t.json():await t.text(),a}}const M=class e{constructor(e){t(this,"metafile"),t(this,"cache"),t(this,"context"),t(this,"fetch",(async e=>{const{files:t,locales:s,excludeBaseLocale:i}=e||{};return new R(this.context).addFiles(t).addLocales(s,i).getCdnRequest().execute()}));const s=new w(e),i=new q(s.params.baseUrl);this.context=new b({metafileContext:s,cdn:this,client:i}),this.metafile=new y(this.context),this.cache=new p(this.context)}static async create(t){if(!t)throw new Error('Invalid param: missing required "options" parameter.');if(!i(t.metafile))throw new Error('Invalid param: "options.metafile" must be string.');const s=new e(t);return await s.metafile.refresh(),s}};t(M,"version","1.5.2");let j=M;export{s as Api,u as CdnBase,p as CdnCache,j as CdnClient,y as CdnMetafile,b as Context,q as FetchHttpAdapter,h as LocalesCache,F as LocalesMap,n as MemoryCacheAdapter,w as MetafileContext,m as MetafileData,d as MetafileFile,f as MetafileLocale,g as MetafileParams,L as Request,R as RequestBuilder,x as ResponseFactory,l as isArray,r as isPlainObject,i as isString,a as isUndefined,o as uniq,c as uniqBy};
//# sourceMappingURL=localazy-cdn-client.min.js.map