UNPKG

@localazy/cdn-client

Version:

Node.js module that allows you to easily interact with the Localazy CDN.

7 lines (6 loc) 11.3 kB
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LocalazyCDN={})}(this,(function(e){"use strict";var t=Object.defineProperty,s=(e,s,i)=>(((e,s,i)=>{s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[s]=i})(e,"symbol"!=typeof s?s+"":s,i),i); /* @localazy/cdn-client@1.5.2 * (c) 2024 Localazy <team@localazy.com> * @license MIT */ class i{constructor(e){s(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 a=e=>"string"==typeof e,l=e=>void 0===e,r=e=>Array.isArray(e),o=e=>"[object Object]"===Object.prototype.toString.call(e),n=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 h{constructor(){s(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 u{constructor(e){s(this,"context"),s(this,"cacheAdapter"),this.context=e,this.cacheAdapter=new h}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=[...n(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 p{constructor(e){s(this,"context"),this.context=e}}class f extends p{constructor(){super(...arguments),s(this,"flush",(()=>{this.context.cache.flush()}))}}class d{constructor(e,t){s(this,"language"),s(this,"region"),s(this,"script"),s(this,"isRtl"),s(this,"name"),s(this,"localizedName"),s(this,"uri"),s(this,"timestamp"),s(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=t}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 m{constructor(e){s(this,"id"),s(this,"file"),s(this,"path"),s(this,"library"),s(this,"module"),s(this,"buildType"),s(this,"timestamp"),s(this,"productFlavors"),s(this,"locales"),s(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 g{constructor(e,t){s(this,"projectUrl"),s(this,"baseLocale"),s(this,"locales"),s(this,"timestamp"),s(this,"files"),s(this,"filesMap"),this.projectUrl=e.projectUrl,this.timestamp=e.timestamp,this.files=g.filesFactory(e.files,e.baseLocale,t),this.filesMap=g.filesMapFactory(this.files),this.locales=g.localesFactory(this.files),this.baseLocale=this.locales.find((e=>e.isBaseLocale))}static createEmpty(e){return new g({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 d(e,t)));return i.push(new m({...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 w{constructor(e){s(this,"options"),this.options=w.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 x{constructor(e){s(this,"params"),s(this,"parsedData"),s(this,"data"),this.params=new w(e.metafile),this.parsedData=null,this.data=g.createEmpty(this.params)}setMetafile(e){this.parsedData=e,this.data=new g(e,this.params)}}class y{constructor(e){s(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]:y.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){s(this,"metafile"),s(this,"cdn"),s(this,"client"),s(this,"api"),s(this,"cache"),s(this,"responseFactory"),this.metafile=e.metafileContext,this.cdn=e.cdn,this.client=e.client,this.api=new i(this),this.cache=new u(this),this.responseFactory=new y(this)}}class F extends p{constructor(){super(...arguments),s(this,"locales",(e=>{const{excludeBaseLocale:t}=e||{},{locales:s}=this.context.metafile.data;return t?s.filter((e=>!e.isBaseLocale)):s})),s(this,"refresh",(async()=>{const e=await this.context.api.fetchMetafile();this.context.metafile.setMetafile(e)})),s(this,"switch",(async e=>{this.context.metafile.params=new w(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 L{constructor(e){s(this,"data"),s(this,"context"),this.context=e.context,this.data=e.data||{}}}class M{constructor(e){s(this,"files"),s(this,"localesMap"),s(this,"hasSingleFileResponse"),s(this,"hasSingleLocaleResponse"),s(this,"context"),this.files=[],this.localesMap=new L({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 q{constructor(e){s(this,"context"),s(this,"request"),this.context=e,this.request=new M(this.context)}addFiles(e){if(!(o(e)||a(e)||l(e)||r(e)))throw new Error('Invalid param: "request.files" must be object, array, string or undefined.');if(r(e)&&e.forEach((e=>{if(!o(e)&&!a(e))throw new Error('Invalid param: array "request.files" must contain objects or strings.')})),a(e)){this.request.hasSingleFileResponse=!0;const t=this.context.metafile.data.files.find((t=>t.id===e));if(!(t instanceof m))throw new Error(`File not found: "${e}".`);this.request.files=[t]}else if(l(e))this.request.files=[...this.context.metafile.data.files];else if(r(e))this.request.files=e.map((e=>{let t;if(a(e)){const s=this.context.metafile.data.files.find((t=>t.id===e));if(l(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(l(s))throw new Error(`File not found: "${e.id}".`);t=s}return t}));else if(o(e)){this.request.hasSingleFileResponse=!0;const t=this.context.metafile.data.files.find((t=>t.id===e.id));if(l(t))throw new Error(`File not found: "${e.id}".`);this.request.files=[t]}return this}addLocales(e,t){if(!(a(e)||l(e)||r(e)))throw new Error('Invalid param: "request.locales" must be array, string or undefined.');return r(e)&&e.forEach((e=>{if(!a(e))throw new Error('Invalid param: array "request.locales" must contain strings.')})),a(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)):l(e)?this.request.files.reduce(((e,s)=>(e.data[s.id]=t?s.locales.filter((e=>!e.isBaseLocale)):s.locales,e)),this.request.localesMap):r(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 M(this.context),e}}class R{constructor(e){s(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 j=class e{constructor(e){s(this,"metafile"),s(this,"cache"),s(this,"context"),s(this,"fetch",(async e=>{const{files:t,locales:s,excludeBaseLocale:i}=e||{};return new q(this.context).addFiles(t).addLocales(s,i).getCdnRequest().execute()}));const t=new x(e),i=new R(t.params.baseUrl);this.context=new b({metafileContext:t,cdn:this,client:i}),this.metafile=new F(this.context),this.cache=new f(this.context)}static async create(t){if(!t)throw new Error('Invalid param: missing required "options" parameter.');if(!a(t.metafile))throw new Error('Invalid param: "options.metafile" must be string.');const s=new e(t);return await s.metafile.refresh(),s}};s(j,"version","1.5.2");let U=j;e.Api=i,e.CdnBase=p,e.CdnCache=f,e.CdnClient=U,e.CdnMetafile=F,e.Context=b,e.FetchHttpAdapter=R,e.LocalesCache=u,e.LocalesMap=L,e.MemoryCacheAdapter=h,e.MetafileContext=x,e.MetafileData=g,e.MetafileFile=m,e.MetafileLocale=d,e.MetafileParams=w,e.Request=M,e.RequestBuilder=q,e.ResponseFactory=y,e.isArray=r,e.isPlainObject=o,e.isString=a,e.isUndefined=l,e.uniq=n,e.uniqBy=c,Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})})); //# sourceMappingURL=localazy-cdn-client.umd.min.js.map