New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

storyblok-js-client

Package Overview
Dependencies
Maintainers
8
Versions
201
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

storyblok-js-client - npm Package Compare versions

Comparing version 6.10.1 to 6.10.2

src/throttlePromise.test.ts

48

dist/index.umd.js

@@ -1,24 +0,24 @@

(function(g,d){typeof exports=="object"&&typeof module<"u"?module.exports=d():typeof define=="function"&&define.amd?define(d):(g=typeof globalThis<"u"?globalThis:g||self,g.StoryblokJSClient=d())})(this,function(){"use strict";var H=Object.defineProperty;var U=(g,d,y)=>d in g?H(g,d,{enumerable:!0,configurable:!0,writable:!0,value:y}):g[d]=y;var c=(g,d,y)=>U(g,typeof d!="symbol"?d+"":d,y);function g(a){return!(a!==a||a===1/0||a===-1/0)}function d(a,e,t){if(!g(e))throw new TypeError("Expected `limit` to be a finite number");if(!g(t))throw new TypeError("Expected `interval` to be a finite number");const r=[];let s=[],i=0;const n=function(){i++;const o=setTimeout(function(){i--,r.length>0&&n(),s=s.filter(function(u){return u!==o})},t);s.indexOf(o)<0&&s.push(o);const h=r.shift();h.resolve(a.apply(h.self,h.args))},l=function(...o){const h=this;return new Promise(function(u,f){r.push({resolve:u,reject:f,args:o,self:h}),i<e&&n()})};return l.abort=function(){s.forEach(clearTimeout),s=[],r.forEach(function(o){o.reject(function(){Error.call(this,"Throttled function aborted"),this.name="AbortError"})}),r.length=0},l}class y{constructor(){c(this,"isCDNUrl",(e="")=>e.indexOf("/cdn/")>-1);c(this,"getOptionsPage",(e,t=25,r=1)=>({...e,per_page:t,page:r}));c(this,"delay",e=>new Promise(t=>setTimeout(t,e)));c(this,"arrayFrom",(e=0,t)=>[...Array(e)].map(t));c(this,"range",(e=0,t=e)=>{const r=Math.abs(t-e)||0,s=e<t?1:-1;return this.arrayFrom(r,(i,n)=>n*s+e)});c(this,"asyncMap",async(e,t)=>Promise.all(e.map(t)));c(this,"flatMap",(e=[],t)=>e.map(t).reduce((r,s)=>[...r,...s],[]));c(this,"escapeHTML",function(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},r=/[&<>"']/g,s=RegExp(r.source);return e&&s.test(e)?e.replace(r,i=>t[i]):e})}stringify(e,t,r){const s=[];for(const i in e){if(!Object.prototype.hasOwnProperty.call(e,i))continue;const n=e[i],l=r?"":encodeURIComponent(i);let o;typeof n=="object"?o=this.stringify(n,t?t+encodeURIComponent("["+l+"]"):l,Array.isArray(n)):o=(t?t+encodeURIComponent("["+l+"]"):l)+"="+encodeURIComponent(n),s.push(o)}return s.join("&")}getRegionURL(e){const t="api.storyblok.com",r="api-us.storyblok.com",s="app.storyblokchina.cn",i="api-ap.storyblok.com",n="api-ca.storyblok.com";switch(e){case"us":return r;case"cn":return s;case"ap":return i;case"ca":return n;default:return t}}}const O=Object.freeze(Object.defineProperty({__proto__:null,SbHelpers:y},Symbol.toStringTag,{value:"Module"})),L=function(a,e){const t={};for(const r in a){const s=a[r];e.indexOf(r)>-1&&s!==null&&(t[r]=s)}return t},E=a=>a==="email",w={nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:a=>({tag:["pre",{tag:"code",attrs:a.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:a=>({tag:`h${a.attrs.level}`}),image:a=>({singleTag:[{tag:"img",attrs:L(a.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:a=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":a.attrs.name,emoji:a.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:a=>{if(!a.attrs)return{tag:""};const e=new y().escapeHTML,t={...a.attrs},{linktype:r="url"}=a.attrs;if(delete t.linktype,t.href&&(t.href=e(a.attrs.href||"")),E(r)&&(t.href=`mailto:${t.href}`),t.anchor&&(t.href=`${t.href}#${t.anchor}`,delete t.anchor),t.custom){for(const s in t.custom)t[s]=t.custom[s];delete t.custom}return{tag:[{tag:"a",attrs:t}]}},styled:a=>({tag:[{tag:"span",attrs:a.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:a=>({tag:[{tag:"span",attrs:a.attrs}]}),highlight:a=>{var t;return(t=a.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${a.attrs.color};`}}]}:{tag:""}},textStyle:a=>{var t;return(t=a.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${a.attrs.color}`}}]}:{tag:""}}}},j=function(a){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},t=/[&<>"']/g,r=RegExp(t.source);return a&&r.test(a)?a.replace(t,s=>e[s]):a};let S=!1;class R{constructor(e){c(this,"marks");c(this,"nodes");e||(e=w),this.marks=e.marks||[],this.nodes=e.nodes||[]}addNode(e,t){this.nodes[e]=t}addMark(e,t){this.marks[e]=t}render(e,t={optimizeImages:!1},r=!0){if(!S&&r&&(console.warn("Warning ⚠️: The RichTextResolver class is deprecated and will be removed in the next major release. Please use the `@storyblok/richtext` package instead. https://github.com/storyblok/richtext/"),S=!0),e&&e.content&&Array.isArray(e.content)){let s="";return e.content.forEach(i=>{s+=this.renderNode(i)}),t.optimizeImages?this.optimizeImages(s,t.optimizeImages):s}return console.warn(`The render method must receive an Object with a "content" field.
The "content" field must be an array of nodes as the type ISbRichtext.
ISbRichtext:
content?: ISbRichtext[]
marks?: ISbRichtext[]
attrs?: any
text?: string
type: string
Example:
{
content: [
{
content: [
{
text: 'Hello World',
type: 'text'
}
],
type: 'paragraph'
}
],
type: 'doc'
}`),""}optimizeImages(e,t){let r=0,s=0,i="",n="";typeof t!="boolean"&&(typeof t.width=="number"&&t.width>0&&(i+=`width="${t.width}" `,r=t.width),typeof t.height=="number"&&t.height>0&&(i+=`height="${t.height}" `,s=t.height),(t.loading==="lazy"||t.loading==="eager")&&(i+=`loading="${t.loading}" `),typeof t.class=="string"&&t.class.length>0&&(i+=`class="${t.class}" `),t.filters&&(typeof t.filters.blur=="number"&&t.filters.blur>=0&&t.filters.blur<=100&&(n+=`:blur(${t.filters.blur})`),typeof t.filters.brightness=="number"&&t.filters.brightness>=-100&&t.filters.brightness<=100&&(n+=`:brightness(${t.filters.brightness})`),t.filters.fill&&(t.filters.fill.match(/[0-9A-Fa-f]{6}/g)||t.filters.fill==="transparent")&&(n+=`:fill(${t.filters.fill})`),t.filters.format&&["webp","png","jpeg"].includes(t.filters.format)&&(n+=`:format(${t.filters.format})`),typeof t.filters.grayscale=="boolean"&&t.filters.grayscale&&(n+=":grayscale()"),typeof t.filters.quality=="number"&&t.filters.quality>=0&&t.filters.quality<=100&&(n+=`:quality(${t.filters.quality})`),t.filters.rotate&&[90,180,270].includes(t.filters.rotate)&&(n+=`:rotate(${t.filters.rotate})`),n.length>0&&(n="/filters"+n))),i.length>0&&(e=e.replace(/<img/g,`<img ${i.trim()}`));const l=r>0||s>0||n.length>0?`${r}x${s}${n}`:"";return e=e.replace(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|tiff|bmp)/g,`a.storyblok.com/f/$1/$2.$3/m/${l}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,o=>{var u,f;const h=o.match(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|tiff|bmp)/g);if(h&&h.length>0){const m={srcset:(u=t.srcset)==null?void 0:u.map(p=>{if(typeof p=="number")return`//${h}/m/${p}x0${n} ${p}w`;if(typeof p=="object"&&p.length===2){let $=0,C=0;return typeof p[0]=="number"&&($=p[0]),typeof p[1]=="number"&&(C=p[1]),`//${h}/m/${$}x${C}${n} ${$}w`}}).join(", "),sizes:(f=t.sizes)==null?void 0:f.map(p=>p).join(", ")};let v="";return m.srcset&&(v+=`srcset="${m.srcset}" `),m.sizes&&(v+=`sizes="${m.sizes}" `),o.replace(/<img/g,`<img ${v.trim()}`)}return o})),e}renderNode(e){const t=[];e.marks&&e.marks.forEach(s=>{const i=this.getMatchingMark(s);i&&i.tag!==""&&t.push(this.renderOpeningTag(i.tag))});const r=this.getMatchingNode(e);return r&&r.tag&&t.push(this.renderOpeningTag(r.tag)),e.content?e.content.forEach(s=>{t.push(this.renderNode(s))}):e.text?t.push(j(e.text)):r&&r.singleTag?t.push(this.renderTag(r.singleTag," /")):r&&r.html?t.push(r.html):e.type==="emoji"&&t.push(this.renderEmoji(e)),r&&r.tag&&t.push(this.renderClosingTag(r.tag)),e.marks&&e.marks.slice(0).reverse().forEach(s=>{const i=this.getMatchingMark(s);i&&i.tag!==""&&t.push(this.renderClosingTag(i.tag))}),t.join("")}renderTag(e,t){return e.constructor===String?`<${e}${t}>`:e.map(s=>{if(s.constructor===String)return`<${s}${t}>`;{let i=`<${s.tag}`;if(s.attrs){for(const n in s.attrs)if(Object.prototype.hasOwnProperty.call(s.attrs,n)){const l=s.attrs[n];l!==null&&(i+=` ${n}="${l}"`)}}return`${i}${t}>`}}).join("")}renderOpeningTag(e){return this.renderTag(e,"")}renderClosingTag(e){return e.constructor===String?`</${e}>`:e.slice(0).reverse().map(r=>r.constructor===String?`</${r}>`:`</${r.tag}>`).join("")}getMatchingNode(e){const t=this.nodes[e.type];if(typeof t=="function")return t(e)}getMatchingMark(e){const t=this.marks[e.type];if(typeof t=="function")return t(e)}renderEmoji(e){if(e.attrs.emoji)return e.attrs.emoji;const t=[{tag:"img",attrs:{src:e.attrs.fallbackImage,draggable:"false",loading:"lazy",align:"absmiddle"}}];return this.renderTag(t," /")}}class x{constructor(e){c(this,"baseURL");c(this,"timeout");c(this,"headers");c(this,"responseInterceptor");c(this,"fetch");c(this,"ejectInterceptor");c(this,"url");c(this,"parameters");c(this,"fetchOptions");this.baseURL=e.baseURL,this.headers=e.headers||new Headers,this.timeout=e!=null&&e.timeout?e.timeout*1e3:0,this.responseInterceptor=e.responseInterceptor,this.fetch=(...t)=>e.fetch?e.fetch(...t):fetch(...t),this.ejectInterceptor=!1,this.url="",this.parameters={},this.fetchOptions={}}get(e,t){return this.url=e,this.parameters=t,this._methodHandler("get")}post(e,t){return this.url=e,this.parameters=t,this._methodHandler("post")}put(e,t){return this.url=e,this.parameters=t,this._methodHandler("put")}delete(e,t){return this.url=e,this.parameters=t,this._methodHandler("delete")}async _responseHandler(e){const t=[],r={data:{},headers:{},status:0,statusText:""};e.status!==204&&await e.json().then(s=>{r.data=s});for(const s of e.headers.entries())t[s[0]]=s[1];return r.headers={...t},r.status=e.status,r.statusText=e.statusText,r}async _methodHandler(e){let t=`${this.baseURL}${this.url}`,r=null;if(e==="get"){const o=new y;t=`${this.baseURL}${this.url}?${o.stringify(this.parameters)}`}else r=JSON.stringify(this.parameters);const s=new URL(t),i=new AbortController,{signal:n}=i;let l;this.timeout&&(l=setTimeout(()=>i.abort(),this.timeout));try{const o=await this.fetch(`${s}`,{method:e,headers:this.headers,body:r,signal:n,...this.fetchOptions});this.timeout&&clearTimeout(l);const h=await this._responseHandler(o);return this.responseInterceptor&&!this.ejectInterceptor?this._statusHandler(this.responseInterceptor(h)):this._statusHandler(h)}catch(o){return{message:o}}}setFetchOptions(e={}){Object.keys(e).length>0&&"method"in e&&delete e.method,this.fetchOptions={...e}}eject(){this.ejectInterceptor=!0}_statusHandler(e){const t=/20[0-6]/g;return new Promise((r,s)=>{if(t.test(`${e.status}`))return r(e);const i={message:e.statusText,status:e.status,response:Array.isArray(e.data)?e.data[0]:e.data.error||e.data.slug};s(i)})}}const P="SB-Agent",_={defaultAgentName:"SB-JS-CLIENT",defaultAgentVersion:"SB-Agent-Version",packageVersion:"6.0.0"};let b={};const k={};class T{constructor(e,t){c(this,"client");c(this,"maxRetries");c(this,"retriesDelay");c(this,"throttle");c(this,"accessToken");c(this,"cache");c(this,"helpers");c(this,"resolveCounter");c(this,"relations");c(this,"links");c(this,"richTextResolver");c(this,"resolveNestedRelations");c(this,"stringifiedStoriesCache");let r=e.endpoint||t;if(!r){const n=new y().getRegionURL,l=e.https===!1?"http":"https";e.oauthToken?r=`${l}://${n(e.region)}/v1`:r=`${l}://${n(e.region)}/v2`}const s=new Headers;s.set("Content-Type","application/json"),s.set("Accept","application/json"),e.headers&&(e.headers.constructor.name==="Headers"?e.headers.entries().toArray():Object.entries(e.headers)).forEach(([l,o])=>{s.set(l,o)}),s.has(P)||(s.set(P,_.defaultAgentName),s.set(_.defaultAgentVersion,_.packageVersion));let i=5;e.oauthToken&&(s.set("Authorization",e.oauthToken),i=3),e.rateLimit&&(i=e.rateLimit),e.richTextSchema?this.richTextResolver=new R(e.richTextSchema):this.richTextResolver=new R,e.componentResolver&&this.setComponentResolver(e.componentResolver),this.maxRetries=e.maxRetries||10,this.retriesDelay=300,this.throttle=d(this.throttledRequest,i,1e3),this.accessToken=e.accessToken||"",this.relations={},this.links={},this.cache=e.cache||{clear:"manual"},this.helpers=new y,this.resolveCounter=0,this.resolveNestedRelations=e.resolveNestedRelations||!0,this.stringifiedStoriesCache={},this.client=new x({baseURL:r,timeout:e.timeout||0,headers:s,responseInterceptor:e.responseInterceptor,fetch:e.fetch})}setComponentResolver(e){this.richTextResolver.addNode("blok",t=>{let r="";return t.attrs.body&&t.attrs.body.forEach(s=>{r+=e(s.component,s)}),{html:r}})}parseParams(e){return e.token||(e.token=this.getToken()),e.cv||(e.cv=k[e.token]),Array.isArray(e.resolve_relations)&&(e.resolve_relations=e.resolve_relations.join(",")),typeof e.resolve_relations<"u"&&(e.resolve_level=2),e}factoryParamOptions(e,t){return this.helpers.isCDNUrl(e)?this.parseParams(t):t}makeRequest(e,t,r,s,i){const n=this.factoryParamOptions(e,this.helpers.getOptionsPage(t,r,s));return this.cacheResponse(e,n,void 0,i)}get(e,t,r){t||(t={});const s=`/${e}`,i=this.factoryParamOptions(s,t);return this.cacheResponse(s,i,void 0,r)}async getAll(e,t,r,s){const i=(t==null?void 0:t.per_page)||25,n=`/${e}`.replace(/\/$/,""),l=r??n.substring(n.lastIndexOf("/")+1),o=1,h=await this.makeRequest(n,t,i,o,s),u=h.total?Math.ceil(h.total/i):1,f=await this.helpers.asyncMap(this.helpers.range(o,u),m=>this.makeRequest(n,t,i,m+1,s));return this.helpers.flatMap([h,...f],m=>Object.values(m.data[l]))}post(e,t,r){const s=`/${e}`;return Promise.resolve(this.throttle("post",s,t,r))}put(e,t,r){const s=`/${e}`;return Promise.resolve(this.throttle("put",s,t,r))}delete(e,t,r){const s=`/${e}`;return Promise.resolve(this.throttle("delete",s,t,r))}getStories(e,t){return this._addResolveLevel(e),this.get("cdn/stories",e,t)}getStory(e,t,r){return this._addResolveLevel(t),this.get(`cdn/stories/${e}`,t,r)}getToken(){return this.accessToken}ejectInterceptor(){this.client.eject()}_addResolveLevel(e){typeof e.resolve_relations<"u"&&(e.resolve_level=2)}_cleanCopy(e){return JSON.parse(JSON.stringify(e))}_insertLinks(e,t,r){const s=e[t];s&&s.fieldtype=="multilink"&&s.linktype=="story"&&typeof s.id=="string"&&this.links[r][s.id]?s.story=this._cleanCopy(this.links[r][s.id]):s&&s.linktype==="story"&&typeof s.uuid=="string"&&this.links[r][s.uuid]&&(s.story=this._cleanCopy(this.links[r][s.uuid]))}getStoryReference(e,t){return this.relations[e][t]?(this.stringifiedStoriesCache[t]||(this.stringifiedStoriesCache[t]=JSON.stringify(this.relations[e][t])),JSON.parse(this.stringifiedStoriesCache[t])):t}_insertRelations(e,t,r,s){r.indexOf(`${e.component}.${t}`)>-1&&(typeof e[t]=="string"?e[t]=this.getStoryReference(s,e[t]):Array.isArray(e[t])&&(e[t]=e[t].map(i=>this.getStoryReference(s,i)).filter(Boolean)))}iterateTree(e,t,r){const s=i=>{if(i!=null){if(i.constructor===Array)for(let n=0;n<i.length;n++)s(i[n]);else if(i.constructor===Object){if(i._stopResolving)return;for(const n in i)(i.component&&i._uid||i.type==="link")&&(this._insertRelations(i,n,t,r),this._insertLinks(i,n,r)),s(i[n])}}};s(e.content)}async resolveLinks(e,t,r){let s=[];if(e.link_uuids){const i=e.link_uuids.length,n=[],l=50;for(let o=0;o<i;o+=l){const h=Math.min(i,o+l);n.push(e.link_uuids.slice(o,h))}for(let o=0;o<n.length;o++)(await this.getStories({per_page:l,language:t.language,version:t.version,by_uuids:n[o].join(",")})).data.stories.forEach(u=>{s.push(u)})}else s=e.links;s.forEach(i=>{this.links[r][i.uuid]={...i,_stopResolving:!0}})}async resolveRelations(e,t,r){let s=[];if(e.rel_uuids){const i=e.rel_uuids.length,n=[],l=50;for(let o=0;o<i;o+=l){const h=Math.min(i,o+l);n.push(e.rel_uuids.slice(o,h))}for(let o=0;o<n.length;o++)(await this.getStories({per_page:l,language:t.language,version:t.version,by_uuids:n[o].join(","),excluding_fields:t.excluding_fields})).data.stories.forEach(u=>{s.push(u)})}else s=e.rels;s&&s.length>0&&s.forEach(i=>{this.relations[r][i.uuid]={...i,_stopResolving:!0}})}async resolveStories(e,t,r){var i,n;let s=[];if(this.links[r]={},this.relations[r]={},typeof t.resolve_relations<"u"&&t.resolve_relations.length>0&&(typeof t.resolve_relations=="string"&&(s=t.resolve_relations.split(",")),await this.resolveRelations(e,t,r)),t.resolve_links&&["1","story","url","link"].indexOf(t.resolve_links)>-1&&((i=e.links)!=null&&i.length||(n=e.link_uuids)!=null&&n.length)&&await this.resolveLinks(e,t,r),this.resolveNestedRelations)for(const l in this.relations[r])this.iterateTree(this.relations[r][l],s,r);e.story?this.iterateTree(e.story,s,r):e.stories.forEach(l=>{this.iterateTree(l,s,r)}),this.stringifiedStoriesCache={},delete this.links[r],delete this.relations[r]}async cacheResponse(e,t,r,s){const i=this.helpers.stringify({url:e,params:t}),n=this.cacheProvider();if(this.cache.clear==="auto"&&t.version==="draft"&&await this.flushCache(),t.version==="published"&&e!="/cdn/spaces/me"){const l=await n.get(i);if(l)return Promise.resolve(l)}return new Promise(async(l,o)=>{var h;try{const u=await this.throttle("get",e,t,s);if(u.status!==200)return o(u);let f={data:u.data,headers:u.headers};if((h=u.headers)!=null&&h["per-page"]&&(f=Object.assign({},f,{perPage:u.headers["per-page"]?parseInt(u.headers["per-page"]):0,total:u.headers["per-page"]?parseInt(u.headers.total):0})),f.data.story||f.data.stories){const m=this.resolveCounter=++this.resolveCounter%1e3;await this.resolveStories(f.data,t,`${m}`)}return t.version==="published"&&e!="/cdn/spaces/me"&&await n.set(i,f),f.data.cv&&t.token&&k[t.token]!=f.data.cv&&(await this.flushCache(),k[t.token]=f.data.cv),l(f)}catch(u){if(u.response&&u.status===429&&(r=typeof r>"u"?0:r+1,r<this.maxRetries))return console.log(`Hit rate limit. Retrying in ${this.retriesDelay/1e3} seconds.`),await this.helpers.delay(this.retriesDelay),this.cacheResponse(e,t,r).then(l).catch(o);o(u)}})}throttledRequest(e,t,r,s){return this.client.setFetchOptions(s),this.client[e](t,r)}cacheVersions(){return k}cacheVersion(){return k[this.accessToken]}setCacheVersion(e){this.accessToken&&(k[this.accessToken]=e)}clearCacheVersion(){this.accessToken&&(k[this.accessToken]=0)}cacheProvider(){switch(this.cache.type){case"memory":return{get(e){return Promise.resolve(b[e])},getAll(){return Promise.resolve(b)},set(e,t){return b[e]=t,Promise.resolve(void 0)},flush(){return b={},Promise.resolve(void 0)}};case"custom":if(this.cache.custom)return this.cache.custom;default:return{get(){return Promise.resolve()},getAll(){return Promise.resolve(void 0)},set(){return Promise.resolve(void 0)},flush(){return Promise.resolve(void 0)}}}}async flushCache(){return await this.cacheProvider().flush(),this.clearCacheVersion(),this}}const A=(a,e)=>{for(const t in e)a[t]=e[t]};return A(T,{RichtextResolver:R,SbFetch:x,RichTextSchema:w}),A(T,O),T});
(function(g,d){typeof exports=="object"&&typeof module<"u"?module.exports=d():typeof define=="function"&&define.amd?define(d):(g=typeof globalThis<"u"?globalThis:g||self,g.StoryblokJSClient=d())})(this,function(){"use strict";var N=Object.defineProperty;var H=(g,d,y)=>d in g?N(g,d,{enumerable:!0,configurable:!0,writable:!0,value:y}):g[d]=y;var c=(g,d,y)=>H(g,typeof d!="symbol"?d+"":d,y);class g extends Error{constructor(e){super(e),this.name="AbortError"}}function d(a,e,t){if(!Number.isFinite(e))throw new TypeError("Expected `limit` to be a finite number");if(!Number.isFinite(t))throw new TypeError("Expected `interval` to be a finite number");const r=[];let s=[],i=0,n=!1;const l=async()=>{i++;const h=r.shift();if(h){const f=await a(...h.args);h.resolve(f)}const u=setTimeout(()=>{i--,r.length>0&&l(),s=s.filter(f=>f!==u)},t);s.includes(u)||s.push(u)},o=(...h)=>n?Promise.reject(new Error("Throttled function is already aborted and not accepting new promises")):new Promise((u,f)=>{r.push({resolve:u,reject:f,args:h}),i<e&&l()});return o.abort=()=>{n=!0,s.forEach(clearTimeout),s=[],r.forEach(h=>h.reject(()=>new g("Throttle function aborted"))),r.length=0},o}class y{constructor(){c(this,"isCDNUrl",(e="")=>e.includes("/cdn/"));c(this,"getOptionsPage",(e,t=25,r=1)=>({...e,per_page:t,page:r}));c(this,"delay",e=>new Promise(t=>setTimeout(t,e)));c(this,"arrayFrom",(e=0,t)=>Array.from({length:e},t));c(this,"range",(e=0,t=e)=>{const r=Math.abs(t-e)||0,s=e<t?1:-1;return this.arrayFrom(r,(i,n)=>n*s+e)});c(this,"asyncMap",async(e,t)=>Promise.all(e.map(t)));c(this,"flatMap",(e=[],t)=>e.map(t).reduce((r,s)=>[...r,...s],[]));c(this,"escapeHTML",function(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},r=/[&<>"']/g,s=new RegExp(r.source);return e&&s.test(e)?e.replace(r,i=>t[i]):e})}stringify(e,t,r){const s=[];for(const i in e){if(!Object.prototype.hasOwnProperty.call(e,i))continue;const n=e[i],l=r?"":encodeURIComponent(i);let o;typeof n=="object"?o=this.stringify(n,t?t+encodeURIComponent(`[${l}]`):l,Array.isArray(n)):o=`${t?t+encodeURIComponent(`[${l}]`):l}=${encodeURIComponent(n)}`,s.push(o)}return s.join("&")}getRegionURL(e){const t="api.storyblok.com",r="api-us.storyblok.com",s="app.storyblokchina.cn",i="api-ap.storyblok.com",n="api-ca.storyblok.com";switch(e){case"us":return r;case"cn":return s;case"ap":return i;case"ca":return n;default:return t}}}const E=Object.freeze(Object.defineProperty({__proto__:null,SbHelpers:y},Symbol.toStringTag,{value:"Module"})),L=function(a,e){const t={};for(const r in a){const s=a[r];e.includes(r)&&s!==null&&(t[r]=s)}return t},O=a=>a==="email",w={nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:a=>({tag:["pre",{tag:"code",attrs:a.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:a=>({tag:`h${a.attrs.level}`}),image:a=>({singleTag:[{tag:"img",attrs:L(a.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:a=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":a.attrs.name,emoji:a.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:a=>{if(!a.attrs)return{tag:""};const e=new y().escapeHTML,t={...a.attrs},{linktype:r="url"}=a.attrs;if(delete t.linktype,t.href&&(t.href=e(a.attrs.href||"")),O(r)&&(t.href=`mailto:${t.href}`),t.anchor&&(t.href=`${t.href}#${t.anchor}`,delete t.anchor),t.custom){for(const s in t.custom)t[s]=t.custom[s];delete t.custom}return{tag:[{tag:"a",attrs:t}]}},styled:a=>({tag:[{tag:"span",attrs:a.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:a=>({tag:[{tag:"span",attrs:a.attrs}]}),highlight:a=>{var t;return(t=a.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${a.attrs.color};`}}]}:{tag:""}},textStyle:a=>{var t;return(t=a.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${a.attrs.color}`}}]}:{tag:""}}}},j=function(a){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},t=/[&<>"']/g,r=new RegExp(t.source);return a&&r.test(a)?a.replace(t,s=>e[s]):a};let S=!1;class R{constructor(e){c(this,"marks");c(this,"nodes");e||(e=w),this.marks=e.marks||[],this.nodes=e.nodes||[]}addNode(e,t){this.nodes[e]=t}addMark(e,t){this.marks[e]=t}render(e,t={optimizeImages:!1},r=!0){if(!S&&r&&(console.warn("Warning ⚠️: The RichTextResolver class is deprecated and will be removed in the next major release. Please use the `@storyblok/richtext` package instead. https://github.com/storyblok/richtext/"),S=!0),e&&e.content&&Array.isArray(e.content)){let s="";return e.content.forEach(i=>{s+=this.renderNode(i)}),t.optimizeImages?this.optimizeImages(s,t.optimizeImages):s}return console.warn(`The render method must receive an Object with a "content" field.
The "content" field must be an array of nodes as the type ISbRichtext.
ISbRichtext:
content?: ISbRichtext[]
marks?: ISbRichtext[]
attrs?: any
text?: string
type: string
Example:
{
content: [
{
content: [
{
text: 'Hello World',
type: 'text'
}
],
type: 'paragraph'
}
],
type: 'doc'
}`),""}optimizeImages(e,t){let r=0,s=0,i="",n="";typeof t!="boolean"&&(typeof t.width=="number"&&t.width>0&&(i+=`width="${t.width}" `,r=t.width),typeof t.height=="number"&&t.height>0&&(i+=`height="${t.height}" `,s=t.height),(t.loading==="lazy"||t.loading==="eager")&&(i+=`loading="${t.loading}" `),typeof t.class=="string"&&t.class.length>0&&(i+=`class="${t.class}" `),t.filters&&(typeof t.filters.blur=="number"&&t.filters.blur>=0&&t.filters.blur<=100&&(n+=`:blur(${t.filters.blur})`),typeof t.filters.brightness=="number"&&t.filters.brightness>=-100&&t.filters.brightness<=100&&(n+=`:brightness(${t.filters.brightness})`),t.filters.fill&&(t.filters.fill.match(/[0-9A-F]{6}/gi)||t.filters.fill==="transparent")&&(n+=`:fill(${t.filters.fill})`),t.filters.format&&["webp","png","jpeg"].includes(t.filters.format)&&(n+=`:format(${t.filters.format})`),typeof t.filters.grayscale=="boolean"&&t.filters.grayscale&&(n+=":grayscale()"),typeof t.filters.quality=="number"&&t.filters.quality>=0&&t.filters.quality<=100&&(n+=`:quality(${t.filters.quality})`),t.filters.rotate&&[90,180,270].includes(t.filters.rotate)&&(n+=`:rotate(${t.filters.rotate})`),n.length>0&&(n=`/filters${n}`))),i.length>0&&(e=e.replace(/<img/g,`<img ${i.trim()}`));const l=r>0||s>0||n.length>0?`${r}x${s}${n}`:"";return e=e.replace(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g,`a.storyblok.com/f/$1/$2.$3/m/${l}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,o=>{var u,f;const h=o.match(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g);if(h&&h.length>0){const m={srcset:(u=t.srcset)==null?void 0:u.map(p=>{if(typeof p=="number")return`//${h}/m/${p}x0${n} ${p}w`;if(typeof p=="object"&&p.length===2){let $=0,C=0;return typeof p[0]=="number"&&($=p[0]),typeof p[1]=="number"&&(C=p[1]),`//${h}/m/${$}x${C}${n} ${$}w`}return""}).join(", "),sizes:(f=t.sizes)==null?void 0:f.map(p=>p).join(", ")};let v="";return m.srcset&&(v+=`srcset="${m.srcset}" `),m.sizes&&(v+=`sizes="${m.sizes}" `),o.replace(/<img/g,`<img ${v.trim()}`)}return o})),e}renderNode(e){const t=[];e.marks&&e.marks.forEach(s=>{const i=this.getMatchingMark(s);i&&i.tag!==""&&t.push(this.renderOpeningTag(i.tag))});const r=this.getMatchingNode(e);return r&&r.tag&&t.push(this.renderOpeningTag(r.tag)),e.content?e.content.forEach(s=>{t.push(this.renderNode(s))}):e.text?t.push(j(e.text)):r&&r.singleTag?t.push(this.renderTag(r.singleTag," /")):r&&r.html?t.push(r.html):e.type==="emoji"&&t.push(this.renderEmoji(e)),r&&r.tag&&t.push(this.renderClosingTag(r.tag)),e.marks&&e.marks.slice(0).reverse().forEach(s=>{const i=this.getMatchingMark(s);i&&i.tag!==""&&t.push(this.renderClosingTag(i.tag))}),t.join("")}renderTag(e,t){return e.constructor===String?`<${e}${t}>`:e.map(s=>{if(s.constructor===String)return`<${s}${t}>`;{let i=`<${s.tag}`;if(s.attrs){for(const n in s.attrs)if(Object.prototype.hasOwnProperty.call(s.attrs,n)){const l=s.attrs[n];l!==null&&(i+=` ${n}="${l}"`)}}return`${i}${t}>`}}).join("")}renderOpeningTag(e){return this.renderTag(e,"")}renderClosingTag(e){return e.constructor===String?`</${e}>`:e.slice(0).reverse().map(r=>r.constructor===String?`</${r}>`:`</${r.tag}>`).join("")}getMatchingNode(e){const t=this.nodes[e.type];if(typeof t=="function")return t(e)}getMatchingMark(e){const t=this.marks[e.type];if(typeof t=="function")return t(e)}renderEmoji(e){if(e.attrs.emoji)return e.attrs.emoji;const t=[{tag:"img",attrs:{src:e.attrs.fallbackImage,draggable:"false",loading:"lazy",align:"absmiddle"}}];return this.renderTag(t," /")}}class x{constructor(e){c(this,"baseURL");c(this,"timeout");c(this,"headers");c(this,"responseInterceptor");c(this,"fetch");c(this,"ejectInterceptor");c(this,"url");c(this,"parameters");c(this,"fetchOptions");this.baseURL=e.baseURL,this.headers=e.headers||new Headers,this.timeout=e!=null&&e.timeout?e.timeout*1e3:0,this.responseInterceptor=e.responseInterceptor,this.fetch=(...t)=>e.fetch?e.fetch(...t):fetch(...t),this.ejectInterceptor=!1,this.url="",this.parameters={},this.fetchOptions={}}get(e,t){return this.url=e,this.parameters=t,this._methodHandler("get")}post(e,t){return this.url=e,this.parameters=t,this._methodHandler("post")}put(e,t){return this.url=e,this.parameters=t,this._methodHandler("put")}delete(e,t){return this.url=e,this.parameters=t,this._methodHandler("delete")}async _responseHandler(e){const t=[],r={data:{},headers:{},status:0,statusText:""};e.status!==204&&await e.json().then(s=>{r.data=s});for(const s of e.headers.entries())t[s[0]]=s[1];return r.headers={...t},r.status=e.status,r.statusText=e.statusText,r}async _methodHandler(e){let t=`${this.baseURL}${this.url}`,r=null;if(e==="get"){const o=new y;t=`${this.baseURL}${this.url}?${o.stringify(this.parameters)}`}else r=JSON.stringify(this.parameters);const s=new URL(t),i=new AbortController,{signal:n}=i;let l;this.timeout&&(l=setTimeout(()=>i.abort(),this.timeout));try{const o=await this.fetch(`${s}`,{method:e,headers:this.headers,body:r,signal:n,...this.fetchOptions});this.timeout&&clearTimeout(l);const h=await this._responseHandler(o);return this.responseInterceptor&&!this.ejectInterceptor?this._statusHandler(this.responseInterceptor(h)):this._statusHandler(h)}catch(o){return{message:o}}}setFetchOptions(e={}){Object.keys(e).length>0&&"method"in e&&delete e.method,this.fetchOptions={...e}}eject(){this.ejectInterceptor=!0}_statusHandler(e){const t=/20[0-6]/g;return new Promise((r,s)=>{if(t.test(`${e.status}`))return r(e);const i={message:e.statusText,status:e.status,response:Array.isArray(e.data)?e.data[0]:e.data.error||e.data.slug};s(i)})}}const P="SB-Agent",_={defaultAgentName:"SB-JS-CLIENT",defaultAgentVersion:"SB-Agent-Version",packageVersion:"6.0.0"};let k={};const b={};class T{constructor(e,t){c(this,"client");c(this,"maxRetries");c(this,"retriesDelay");c(this,"throttle");c(this,"accessToken");c(this,"cache");c(this,"helpers");c(this,"resolveCounter");c(this,"relations");c(this,"links");c(this,"richTextResolver");c(this,"resolveNestedRelations");c(this,"stringifiedStoriesCache");let r=e.endpoint||t;if(!r){const n=new y().getRegionURL,l=e.https===!1?"http":"https";e.oauthToken?r=`${l}://${n(e.region)}/v1`:r=`${l}://${n(e.region)}/v2`}const s=new Headers;s.set("Content-Type","application/json"),s.set("Accept","application/json"),e.headers&&(e.headers.constructor.name==="Headers"?e.headers.entries().toArray():Object.entries(e.headers)).forEach(([l,o])=>{s.set(l,o)}),s.has(P)||(s.set(P,_.defaultAgentName),s.set(_.defaultAgentVersion,_.packageVersion));let i=5;e.oauthToken&&(s.set("Authorization",e.oauthToken),i=3),e.rateLimit&&(i=e.rateLimit),e.richTextSchema?this.richTextResolver=new R(e.richTextSchema):this.richTextResolver=new R,e.componentResolver&&this.setComponentResolver(e.componentResolver),this.maxRetries=e.maxRetries||10,this.retriesDelay=300,this.throttle=d(this.throttledRequest.bind(this),i,1e3),this.accessToken=e.accessToken||"",this.relations={},this.links={},this.cache=e.cache||{clear:"manual"},this.helpers=new y,this.resolveCounter=0,this.resolveNestedRelations=e.resolveNestedRelations||!0,this.stringifiedStoriesCache={},this.client=new x({baseURL:r,timeout:e.timeout||0,headers:s,responseInterceptor:e.responseInterceptor,fetch:e.fetch})}setComponentResolver(e){this.richTextResolver.addNode("blok",t=>{let r="";return t.attrs.body&&t.attrs.body.forEach(s=>{r+=e(s.component,s)}),{html:r}})}parseParams(e){return e.token||(e.token=this.getToken()),e.cv||(e.cv=b[e.token]),Array.isArray(e.resolve_relations)&&(e.resolve_relations=e.resolve_relations.join(",")),typeof e.resolve_relations<"u"&&(e.resolve_level=2),e}factoryParamOptions(e,t){return this.helpers.isCDNUrl(e)?this.parseParams(t):t}makeRequest(e,t,r,s,i){const n=this.factoryParamOptions(e,this.helpers.getOptionsPage(t,r,s));return this.cacheResponse(e,n,void 0,i)}get(e,t,r){t||(t={});const s=`/${e}`,i=this.factoryParamOptions(s,t);return this.cacheResponse(s,i,void 0,r)}async getAll(e,t,r,s){const i=(t==null?void 0:t.per_page)||25,n=`/${e}`.replace(/\/$/,""),l=r??n.substring(n.lastIndexOf("/")+1),o=1,h=await this.makeRequest(n,t,i,o,s),u=h.total?Math.ceil(h.total/i):1,f=await this.helpers.asyncMap(this.helpers.range(o,u),m=>this.makeRequest(n,t,i,m+1,s));return this.helpers.flatMap([h,...f],m=>Object.values(m.data[l]))}post(e,t,r){const s=`/${e}`;return Promise.resolve(this.throttle("post",s,t,r))}put(e,t,r){const s=`/${e}`;return Promise.resolve(this.throttle("put",s,t,r))}delete(e,t,r){const s=`/${e}`;return Promise.resolve(this.throttle("delete",s,t,r))}getStories(e,t){return this._addResolveLevel(e),this.get("cdn/stories",e,t)}getStory(e,t,r){return this._addResolveLevel(t),this.get(`cdn/stories/${e}`,t,r)}getToken(){return this.accessToken}ejectInterceptor(){this.client.eject()}_addResolveLevel(e){typeof e.resolve_relations<"u"&&(e.resolve_level=2)}_cleanCopy(e){return JSON.parse(JSON.stringify(e))}_insertLinks(e,t,r){const s=e[t];s&&s.fieldtype==="multilink"&&s.linktype==="story"&&typeof s.id=="string"&&this.links[r][s.id]?s.story=this._cleanCopy(this.links[r][s.id]):s&&s.linktype==="story"&&typeof s.uuid=="string"&&this.links[r][s.uuid]&&(s.story=this._cleanCopy(this.links[r][s.uuid]))}getStoryReference(e,t){return this.relations[e][t]?(this.stringifiedStoriesCache[t]||(this.stringifiedStoriesCache[t]=JSON.stringify(this.relations[e][t])),JSON.parse(this.stringifiedStoriesCache[t])):t}_insertRelations(e,t,r,s){r.includes(`${e.component}.${t}`)&&(typeof e[t]=="string"?e[t]=this.getStoryReference(s,e[t]):Array.isArray(e[t])&&(e[t]=e[t].map(i=>this.getStoryReference(s,i)).filter(Boolean)))}iterateTree(e,t,r){const s=i=>{if(i!=null){if(i.constructor===Array)for(let n=0;n<i.length;n++)s(i[n]);else if(i.constructor===Object){if(i._stopResolving)return;for(const n in i)(i.component&&i._uid||i.type==="link")&&(this._insertRelations(i,n,t,r),this._insertLinks(i,n,r)),s(i[n])}}};s(e.content)}async resolveLinks(e,t,r){let s=[];if(e.link_uuids){const i=e.link_uuids.length,n=[],l=50;for(let o=0;o<i;o+=l){const h=Math.min(i,o+l);n.push(e.link_uuids.slice(o,h))}for(let o=0;o<n.length;o++)(await this.getStories({per_page:l,language:t.language,version:t.version,by_uuids:n[o].join(",")})).data.stories.forEach(u=>{s.push(u)})}else s=e.links;s.forEach(i=>{this.links[r][i.uuid]={...i,_stopResolving:!0}})}async resolveRelations(e,t,r){let s=[];if(e.rel_uuids){const i=e.rel_uuids.length,n=[],l=50;for(let o=0;o<i;o+=l){const h=Math.min(i,o+l);n.push(e.rel_uuids.slice(o,h))}for(let o=0;o<n.length;o++)(await this.getStories({per_page:l,language:t.language,version:t.version,by_uuids:n[o].join(","),excluding_fields:t.excluding_fields})).data.stories.forEach(u=>{s.push(u)})}else s=e.rels;s&&s.length>0&&s.forEach(i=>{this.relations[r][i.uuid]={...i,_stopResolving:!0}})}async resolveStories(e,t,r){var i,n;let s=[];if(this.links[r]={},this.relations[r]={},typeof t.resolve_relations<"u"&&t.resolve_relations.length>0&&(typeof t.resolve_relations=="string"&&(s=t.resolve_relations.split(",")),await this.resolveRelations(e,t,r)),t.resolve_links&&["1","story","url","link"].includes(t.resolve_links)&&((i=e.links)!=null&&i.length||(n=e.link_uuids)!=null&&n.length)&&await this.resolveLinks(e,t,r),this.resolveNestedRelations)for(const l in this.relations[r])this.iterateTree(this.relations[r][l],s,r);e.story?this.iterateTree(e.story,s,r):e.stories.forEach(l=>{this.iterateTree(l,s,r)}),this.stringifiedStoriesCache={},delete this.links[r],delete this.relations[r]}async cacheResponse(e,t,r,s){const i=this.helpers.stringify({url:e,params:t}),n=this.cacheProvider();if(this.cache.clear==="auto"&&t.version==="draft"&&await this.flushCache(),t.version==="published"&&e!=="/cdn/spaces/me"){const l=await n.get(i);if(l)return Promise.resolve(l)}return new Promise(async(l,o)=>{var h;try{const u=await this.throttle("get",e,t,s);if(u.status!==200)return o(u);let f={data:u.data,headers:u.headers};if((h=u.headers)!=null&&h["per-page"]&&(f=Object.assign({},f,{perPage:u.headers["per-page"]?Number.parseInt(u.headers["per-page"]):0,total:u.headers["per-page"]?Number.parseInt(u.headers.total):0})),f.data.story||f.data.stories){const m=this.resolveCounter=++this.resolveCounter%1e3;await this.resolveStories(f.data,t,`${m}`)}return t.version==="published"&&e!=="/cdn/spaces/me"&&await n.set(i,f),f.data.cv&&t.token&&b[t.token]!==f.data.cv&&(await this.flushCache(),b[t.token]=f.data.cv),l(f)}catch(u){if(u.response&&u.status===429&&(r=typeof r>"u"?0:r+1,r<this.maxRetries))return console.log(`Hit rate limit. Retrying in ${this.retriesDelay/1e3} seconds.`),await this.helpers.delay(this.retriesDelay),this.cacheResponse(e,t,r).then(l).catch(o);o(u)}})}throttledRequest(e,t,r,s){return this.client.setFetchOptions(s),this.client[e](t,r)}cacheVersions(){return b}cacheVersion(){return b[this.accessToken]}setCacheVersion(e){this.accessToken&&(b[this.accessToken]=e)}clearCacheVersion(){this.accessToken&&(b[this.accessToken]=0)}cacheProvider(){switch(this.cache.type){case"memory":return{get(e){return Promise.resolve(k[e])},getAll(){return Promise.resolve(k)},set(e,t){return k[e]=t,Promise.resolve(void 0)},flush(){return k={},Promise.resolve(void 0)}};case"custom":if(this.cache.custom)return this.cache.custom;default:return{get(){return Promise.resolve()},getAll(){return Promise.resolve(void 0)},set(){return Promise.resolve(void 0)},flush(){return Promise.resolve(void 0)}}}}async flushCache(){return await this.cacheProvider().flush(),this.clearCacheVersion(),this}}const A=(a,e)=>{for(const t in e)a[t]=e[t]};return A(T,{RichtextResolver:R,SbFetch:x,RichTextSchema:w}),A(T,E),T});

@@ -1,24 +0,24 @@

(function(l,c){typeof exports=="object"&&typeof module<"u"?module.exports=c():typeof define=="function"&&define.amd?define(c):(l=typeof globalThis<"u"?globalThis:l||self,l.RichTextResolver=c())})(this,function(){"use strict";var R=Object.defineProperty;var I=(l,c,h)=>c in l?R(l,c,{enumerable:!0,configurable:!0,writable:!0,value:h}):l[c]=h;var f=(l,c,h)=>I(l,typeof c!="symbol"?c+"":c,h);class l{constructor(){f(this,"isCDNUrl",(e="")=>e.indexOf("/cdn/")>-1);f(this,"getOptionsPage",(e,t=25,r=1)=>({...e,per_page:t,page:r}));f(this,"delay",e=>new Promise(t=>setTimeout(t,e)));f(this,"arrayFrom",(e=0,t)=>[...Array(e)].map(t));f(this,"range",(e=0,t=e)=>{const r=Math.abs(t-e)||0,s=e<t?1:-1;return this.arrayFrom(r,(a,i)=>i*s+e)});f(this,"asyncMap",async(e,t)=>Promise.all(e.map(t)));f(this,"flatMap",(e=[],t)=>e.map(t).reduce((r,s)=>[...r,...s],[]));f(this,"escapeHTML",function(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},r=/[&<>"']/g,s=RegExp(r.source);return e&&s.test(e)?e.replace(r,a=>t[a]):e})}stringify(e,t,r){const s=[];for(const a in e){if(!Object.prototype.hasOwnProperty.call(e,a))continue;const i=e[a],g=r?"":encodeURIComponent(a);let u;typeof i=="object"?u=this.stringify(i,t?t+encodeURIComponent("["+g+"]"):g,Array.isArray(i)):u=(t?t+encodeURIComponent("["+g+"]"):g)+"="+encodeURIComponent(i),s.push(u)}return s.join("&")}getRegionURL(e){const t="api.storyblok.com",r="api-us.storyblok.com",s="app.storyblokchina.cn",a="api-ap.storyblok.com",i="api-ca.storyblok.com";switch(e){case"us":return r;case"cn":return s;case"ap":return a;case"ca":return i;default:return t}}}const c=function(n,e){const t={};for(const r in n){const s=n[r];e.indexOf(r)>-1&&s!==null&&(t[r]=s)}return t},h=n=>n==="email",T={nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:n=>({tag:["pre",{tag:"code",attrs:n.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:n=>({tag:`h${n.attrs.level}`}),image:n=>({singleTag:[{tag:"img",attrs:c(n.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:n=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":n.attrs.name,emoji:n.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:n=>{if(!n.attrs)return{tag:""};const e=new l().escapeHTML,t={...n.attrs},{linktype:r="url"}=n.attrs;if(delete t.linktype,t.href&&(t.href=e(n.attrs.href||"")),h(r)&&(t.href=`mailto:${t.href}`),t.anchor&&(t.href=`${t.href}#${t.anchor}`,delete t.anchor),t.custom){for(const s in t.custom)t[s]=t.custom[s];delete t.custom}return{tag:[{tag:"a",attrs:t}]}},styled:n=>({tag:[{tag:"span",attrs:n.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:n=>({tag:[{tag:"span",attrs:n.attrs}]}),highlight:n=>{var t;return(t=n.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${n.attrs.color};`}}]}:{tag:""}},textStyle:n=>{var t;return(t=n.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${n.attrs.color}`}}]}:{tag:""}}}},x=function(n){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},t=/[&<>"']/g,r=RegExp(t.source);return n&&r.test(n)?n.replace(t,s=>e[s]):n};let b=!1;class _{constructor(e){f(this,"marks");f(this,"nodes");e||(e=T),this.marks=e.marks||[],this.nodes=e.nodes||[]}addNode(e,t){this.nodes[e]=t}addMark(e,t){this.marks[e]=t}render(e,t={optimizeImages:!1},r=!0){if(!b&&r&&(console.warn("Warning ⚠️: The RichTextResolver class is deprecated and will be removed in the next major release. Please use the `@storyblok/richtext` package instead. https://github.com/storyblok/richtext/"),b=!0),e&&e.content&&Array.isArray(e.content)){let s="";return e.content.forEach(a=>{s+=this.renderNode(a)}),t.optimizeImages?this.optimizeImages(s,t.optimizeImages):s}return console.warn(`The render method must receive an Object with a "content" field.
The "content" field must be an array of nodes as the type ISbRichtext.
ISbRichtext:
content?: ISbRichtext[]
marks?: ISbRichtext[]
attrs?: any
text?: string
type: string
Example:
{
content: [
{
content: [
{
text: 'Hello World',
type: 'text'
}
],
type: 'paragraph'
}
],
type: 'doc'
}`),""}optimizeImages(e,t){let r=0,s=0,a="",i="";typeof t!="boolean"&&(typeof t.width=="number"&&t.width>0&&(a+=`width="${t.width}" `,r=t.width),typeof t.height=="number"&&t.height>0&&(a+=`height="${t.height}" `,s=t.height),(t.loading==="lazy"||t.loading==="eager")&&(a+=`loading="${t.loading}" `),typeof t.class=="string"&&t.class.length>0&&(a+=`class="${t.class}" `),t.filters&&(typeof t.filters.blur=="number"&&t.filters.blur>=0&&t.filters.blur<=100&&(i+=`:blur(${t.filters.blur})`),typeof t.filters.brightness=="number"&&t.filters.brightness>=-100&&t.filters.brightness<=100&&(i+=`:brightness(${t.filters.brightness})`),t.filters.fill&&(t.filters.fill.match(/[0-9A-Fa-f]{6}/g)||t.filters.fill==="transparent")&&(i+=`:fill(${t.filters.fill})`),t.filters.format&&["webp","png","jpeg"].includes(t.filters.format)&&(i+=`:format(${t.filters.format})`),typeof t.filters.grayscale=="boolean"&&t.filters.grayscale&&(i+=":grayscale()"),typeof t.filters.quality=="number"&&t.filters.quality>=0&&t.filters.quality<=100&&(i+=`:quality(${t.filters.quality})`),t.filters.rotate&&[90,180,270].includes(t.filters.rotate)&&(i+=`:rotate(${t.filters.rotate})`),i.length>0&&(i="/filters"+i))),a.length>0&&(e=e.replace(/<img/g,`<img ${a.trim()}`));const g=r>0||s>0||i.length>0?`${r}x${s}${i}`:"";return e=e.replace(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|tiff|bmp)/g,`a.storyblok.com/f/$1/$2.$3/m/${g}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,u=>{var k,$;const d=u.match(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|tiff|bmp)/g);if(d&&d.length>0){const m={srcset:(k=t.srcset)==null?void 0:k.map(o=>{if(typeof o=="number")return`//${d}/m/${o}x0${i} ${o}w`;if(typeof o=="object"&&o.length===2){let y=0,j=0;return typeof o[0]=="number"&&(y=o[0]),typeof o[1]=="number"&&(j=o[1]),`//${d}/m/${y}x${j}${i} ${y}w`}}).join(", "),sizes:($=t.sizes)==null?void 0:$.map(o=>o).join(", ")};let p="";return m.srcset&&(p+=`srcset="${m.srcset}" `),m.sizes&&(p+=`sizes="${m.sizes}" `),u.replace(/<img/g,`<img ${p.trim()}`)}return u})),e}renderNode(e){const t=[];e.marks&&e.marks.forEach(s=>{const a=this.getMatchingMark(s);a&&a.tag!==""&&t.push(this.renderOpeningTag(a.tag))});const r=this.getMatchingNode(e);return r&&r.tag&&t.push(this.renderOpeningTag(r.tag)),e.content?e.content.forEach(s=>{t.push(this.renderNode(s))}):e.text?t.push(x(e.text)):r&&r.singleTag?t.push(this.renderTag(r.singleTag," /")):r&&r.html?t.push(r.html):e.type==="emoji"&&t.push(this.renderEmoji(e)),r&&r.tag&&t.push(this.renderClosingTag(r.tag)),e.marks&&e.marks.slice(0).reverse().forEach(s=>{const a=this.getMatchingMark(s);a&&a.tag!==""&&t.push(this.renderClosingTag(a.tag))}),t.join("")}renderTag(e,t){return e.constructor===String?`<${e}${t}>`:e.map(s=>{if(s.constructor===String)return`<${s}${t}>`;{let a=`<${s.tag}`;if(s.attrs){for(const i in s.attrs)if(Object.prototype.hasOwnProperty.call(s.attrs,i)){const g=s.attrs[i];g!==null&&(a+=` ${i}="${g}"`)}}return`${a}${t}>`}}).join("")}renderOpeningTag(e){return this.renderTag(e,"")}renderClosingTag(e){return e.constructor===String?`</${e}>`:e.slice(0).reverse().map(r=>r.constructor===String?`</${r}>`:`</${r.tag}>`).join("")}getMatchingNode(e){const t=this.nodes[e.type];if(typeof t=="function")return t(e)}getMatchingMark(e){const t=this.marks[e.type];if(typeof t=="function")return t(e)}renderEmoji(e){if(e.attrs.emoji)return e.attrs.emoji;const t=[{tag:"img",attrs:{src:e.attrs.fallbackImage,draggable:"false",loading:"lazy",align:"absmiddle"}}];return this.renderTag(t," /")}}return _});
(function(l,c){typeof exports=="object"&&typeof module<"u"?module.exports=c():typeof define=="function"&&define.amd?define(c):(l=typeof globalThis<"u"?globalThis:l||self,l.RichTextResolver=c())})(this,function(){"use strict";var x=Object.defineProperty;var w=(l,c,h)=>c in l?x(l,c,{enumerable:!0,configurable:!0,writable:!0,value:h}):l[c]=h;var g=(l,c,h)=>w(l,typeof c!="symbol"?c+"":c,h);class l{constructor(){g(this,"isCDNUrl",(e="")=>e.includes("/cdn/"));g(this,"getOptionsPage",(e,t=25,r=1)=>({...e,per_page:t,page:r}));g(this,"delay",e=>new Promise(t=>setTimeout(t,e)));g(this,"arrayFrom",(e=0,t)=>Array.from({length:e},t));g(this,"range",(e=0,t=e)=>{const r=Math.abs(t-e)||0,s=e<t?1:-1;return this.arrayFrom(r,(a,i)=>i*s+e)});g(this,"asyncMap",async(e,t)=>Promise.all(e.map(t)));g(this,"flatMap",(e=[],t)=>e.map(t).reduce((r,s)=>[...r,...s],[]));g(this,"escapeHTML",function(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},r=/[&<>"']/g,s=new RegExp(r.source);return e&&s.test(e)?e.replace(r,a=>t[a]):e})}stringify(e,t,r){const s=[];for(const a in e){if(!Object.prototype.hasOwnProperty.call(e,a))continue;const i=e[a],f=r?"":encodeURIComponent(a);let u;typeof i=="object"?u=this.stringify(i,t?t+encodeURIComponent(`[${f}]`):f,Array.isArray(i)):u=`${t?t+encodeURIComponent(`[${f}]`):f}=${encodeURIComponent(i)}`,s.push(u)}return s.join("&")}getRegionURL(e){const t="api.storyblok.com",r="api-us.storyblok.com",s="app.storyblokchina.cn",a="api-ap.storyblok.com",i="api-ca.storyblok.com";switch(e){case"us":return r;case"cn":return s;case"ap":return a;case"ca":return i;default:return t}}}const c=function(n,e){const t={};for(const r in n){const s=n[r];e.includes(r)&&s!==null&&(t[r]=s)}return t},h=n=>n==="email",T={nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:n=>({tag:["pre",{tag:"code",attrs:n.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:n=>({tag:`h${n.attrs.level}`}),image:n=>({singleTag:[{tag:"img",attrs:c(n.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:n=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":n.attrs.name,emoji:n.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:n=>{if(!n.attrs)return{tag:""};const e=new l().escapeHTML,t={...n.attrs},{linktype:r="url"}=n.attrs;if(delete t.linktype,t.href&&(t.href=e(n.attrs.href||"")),h(r)&&(t.href=`mailto:${t.href}`),t.anchor&&(t.href=`${t.href}#${t.anchor}`,delete t.anchor),t.custom){for(const s in t.custom)t[s]=t.custom[s];delete t.custom}return{tag:[{tag:"a",attrs:t}]}},styled:n=>({tag:[{tag:"span",attrs:n.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:n=>({tag:[{tag:"span",attrs:n.attrs}]}),highlight:n=>{var t;return(t=n.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${n.attrs.color};`}}]}:{tag:""}},textStyle:n=>{var t;return(t=n.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${n.attrs.color}`}}]}:{tag:""}}}},_=function(n){const e={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},t=/[&<>"']/g,r=new RegExp(t.source);return n&&r.test(n)?n.replace(t,s=>e[s]):n};let b=!1;class R{constructor(e){g(this,"marks");g(this,"nodes");e||(e=T),this.marks=e.marks||[],this.nodes=e.nodes||[]}addNode(e,t){this.nodes[e]=t}addMark(e,t){this.marks[e]=t}render(e,t={optimizeImages:!1},r=!0){if(!b&&r&&(console.warn("Warning ⚠️: The RichTextResolver class is deprecated and will be removed in the next major release. Please use the `@storyblok/richtext` package instead. https://github.com/storyblok/richtext/"),b=!0),e&&e.content&&Array.isArray(e.content)){let s="";return e.content.forEach(a=>{s+=this.renderNode(a)}),t.optimizeImages?this.optimizeImages(s,t.optimizeImages):s}return console.warn(`The render method must receive an Object with a "content" field.
The "content" field must be an array of nodes as the type ISbRichtext.
ISbRichtext:
content?: ISbRichtext[]
marks?: ISbRichtext[]
attrs?: any
text?: string
type: string
Example:
{
content: [
{
content: [
{
text: 'Hello World',
type: 'text'
}
],
type: 'paragraph'
}
],
type: 'doc'
}`),""}optimizeImages(e,t){let r=0,s=0,a="",i="";typeof t!="boolean"&&(typeof t.width=="number"&&t.width>0&&(a+=`width="${t.width}" `,r=t.width),typeof t.height=="number"&&t.height>0&&(a+=`height="${t.height}" `,s=t.height),(t.loading==="lazy"||t.loading==="eager")&&(a+=`loading="${t.loading}" `),typeof t.class=="string"&&t.class.length>0&&(a+=`class="${t.class}" `),t.filters&&(typeof t.filters.blur=="number"&&t.filters.blur>=0&&t.filters.blur<=100&&(i+=`:blur(${t.filters.blur})`),typeof t.filters.brightness=="number"&&t.filters.brightness>=-100&&t.filters.brightness<=100&&(i+=`:brightness(${t.filters.brightness})`),t.filters.fill&&(t.filters.fill.match(/[0-9A-F]{6}/gi)||t.filters.fill==="transparent")&&(i+=`:fill(${t.filters.fill})`),t.filters.format&&["webp","png","jpeg"].includes(t.filters.format)&&(i+=`:format(${t.filters.format})`),typeof t.filters.grayscale=="boolean"&&t.filters.grayscale&&(i+=":grayscale()"),typeof t.filters.quality=="number"&&t.filters.quality>=0&&t.filters.quality<=100&&(i+=`:quality(${t.filters.quality})`),t.filters.rotate&&[90,180,270].includes(t.filters.rotate)&&(i+=`:rotate(${t.filters.rotate})`),i.length>0&&(i=`/filters${i}`))),a.length>0&&(e=e.replace(/<img/g,`<img ${a.trim()}`));const f=r>0||s>0||i.length>0?`${r}x${s}${i}`:"";return e=e.replace(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g,`a.storyblok.com/f/$1/$2.$3/m/${f}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,u=>{var $,k;const d=u.match(/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g);if(d&&d.length>0){const m={srcset:($=t.srcset)==null?void 0:$.map(o=>{if(typeof o=="number")return`//${d}/m/${o}x0${i} ${o}w`;if(typeof o=="object"&&o.length===2){let y=0,j=0;return typeof o[0]=="number"&&(y=o[0]),typeof o[1]=="number"&&(j=o[1]),`//${d}/m/${y}x${j}${i} ${y}w`}return""}).join(", "),sizes:(k=t.sizes)==null?void 0:k.map(o=>o).join(", ")};let p="";return m.srcset&&(p+=`srcset="${m.srcset}" `),m.sizes&&(p+=`sizes="${m.sizes}" `),u.replace(/<img/g,`<img ${p.trim()}`)}return u})),e}renderNode(e){const t=[];e.marks&&e.marks.forEach(s=>{const a=this.getMatchingMark(s);a&&a.tag!==""&&t.push(this.renderOpeningTag(a.tag))});const r=this.getMatchingNode(e);return r&&r.tag&&t.push(this.renderOpeningTag(r.tag)),e.content?e.content.forEach(s=>{t.push(this.renderNode(s))}):e.text?t.push(_(e.text)):r&&r.singleTag?t.push(this.renderTag(r.singleTag," /")):r&&r.html?t.push(r.html):e.type==="emoji"&&t.push(this.renderEmoji(e)),r&&r.tag&&t.push(this.renderClosingTag(r.tag)),e.marks&&e.marks.slice(0).reverse().forEach(s=>{const a=this.getMatchingMark(s);a&&a.tag!==""&&t.push(this.renderClosingTag(a.tag))}),t.join("")}renderTag(e,t){return e.constructor===String?`<${e}${t}>`:e.map(s=>{if(s.constructor===String)return`<${s}${t}>`;{let a=`<${s.tag}`;if(s.attrs){for(const i in s.attrs)if(Object.prototype.hasOwnProperty.call(s.attrs,i)){const f=s.attrs[i];f!==null&&(a+=` ${i}="${f}"`)}}return`${a}${t}>`}}).join("")}renderOpeningTag(e){return this.renderTag(e,"")}renderClosingTag(e){return e.constructor===String?`</${e}>`:e.slice(0).reverse().map(r=>r.constructor===String?`</${r}>`:`</${r.tag}>`).join("")}getMatchingNode(e){const t=this.nodes[e.type];if(typeof t=="function")return t(e)}getMatchingMark(e){const t=this.marks[e.type];if(typeof t=="function")return t(e)}renderEmoji(e){if(e.attrs.emoji)return e.attrs.emoji;const t=[{tag:"img",attrs:{src:e.attrs.fallbackImage,draggable:"false",loading:"lazy",align:"absmiddle"}}];return this.renderTag(t," /")}}return R});

@@ -1,1 +0,1 @@

(function(a,o){typeof exports=="object"&&typeof module<"u"?module.exports=o():typeof define=="function"&&define.amd?define(o):(a=typeof globalThis<"u"?globalThis:a||self,a.RichTextSchema=o())})(this,function(){"use strict";var h=Object.defineProperty;var m=(a,o,u)=>o in a?h(a,o,{enumerable:!0,configurable:!0,writable:!0,value:u}):a[o]=u;var c=(a,o,u)=>m(a,typeof o!="symbol"?o+"":o,u);class a{constructor(){c(this,"isCDNUrl",(e="")=>e.indexOf("/cdn/")>-1);c(this,"getOptionsPage",(e,t=25,n=1)=>({...e,per_page:t,page:n}));c(this,"delay",e=>new Promise(t=>setTimeout(t,e)));c(this,"arrayFrom",(e=0,t)=>[...Array(e)].map(t));c(this,"range",(e=0,t=e)=>{const n=Math.abs(t-e)||0,s=e<t?1:-1;return this.arrayFrom(n,(i,l)=>l*s+e)});c(this,"asyncMap",async(e,t)=>Promise.all(e.map(t)));c(this,"flatMap",(e=[],t)=>e.map(t).reduce((n,s)=>[...n,...s],[]));c(this,"escapeHTML",function(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},n=/[&<>"']/g,s=RegExp(n.source);return e&&s.test(e)?e.replace(n,i=>t[i]):e})}stringify(e,t,n){const s=[];for(const i in e){if(!Object.prototype.hasOwnProperty.call(e,i))continue;const l=e[i],g=n?"":encodeURIComponent(i);let p;typeof l=="object"?p=this.stringify(l,t?t+encodeURIComponent("["+g+"]"):g,Array.isArray(l)):p=(t?t+encodeURIComponent("["+g+"]"):g)+"="+encodeURIComponent(l),s.push(p)}return s.join("&")}getRegionURL(e){const t="api.storyblok.com",n="api-us.storyblok.com",s="app.storyblokchina.cn",i="api-ap.storyblok.com",l="api-ca.storyblok.com";switch(e){case"us":return n;case"cn":return s;case"ap":return i;case"ca":return l;default:return t}}}const o=function(r,e){const t={};for(const n in r){const s=r[n];e.indexOf(n)>-1&&s!==null&&(t[n]=s)}return t},u=r=>r==="email";return{nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:r=>({tag:["pre",{tag:"code",attrs:r.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:r=>({tag:`h${r.attrs.level}`}),image:r=>({singleTag:[{tag:"img",attrs:o(r.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:r=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":r.attrs.name,emoji:r.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:r=>{if(!r.attrs)return{tag:""};const e=new a().escapeHTML,t={...r.attrs},{linktype:n="url"}=r.attrs;if(delete t.linktype,t.href&&(t.href=e(r.attrs.href||"")),u(n)&&(t.href=`mailto:${t.href}`),t.anchor&&(t.href=`${t.href}#${t.anchor}`,delete t.anchor),t.custom){for(const s in t.custom)t[s]=t.custom[s];delete t.custom}return{tag:[{tag:"a",attrs:t}]}},styled:r=>({tag:[{tag:"span",attrs:r.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:r=>({tag:[{tag:"span",attrs:r.attrs}]}),highlight:r=>{var t;return(t=r.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${r.attrs.color};`}}]}:{tag:""}},textStyle:r=>{var t;return(t=r.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${r.attrs.color}`}}]}:{tag:""}}}}});
(function(a,o){typeof exports=="object"&&typeof module<"u"?module.exports=o():typeof define=="function"&&define.amd?define(o):(a=typeof globalThis<"u"?globalThis:a||self,a.RichTextSchema=o())})(this,function(){"use strict";var h=Object.defineProperty;var m=(a,o,u)=>o in a?h(a,o,{enumerable:!0,configurable:!0,writable:!0,value:u}):a[o]=u;var c=(a,o,u)=>m(a,typeof o!="symbol"?o+"":o,u);class a{constructor(){c(this,"isCDNUrl",(e="")=>e.includes("/cdn/"));c(this,"getOptionsPage",(e,t=25,n=1)=>({...e,per_page:t,page:n}));c(this,"delay",e=>new Promise(t=>setTimeout(t,e)));c(this,"arrayFrom",(e=0,t)=>Array.from({length:e},t));c(this,"range",(e=0,t=e)=>{const n=Math.abs(t-e)||0,s=e<t?1:-1;return this.arrayFrom(n,(i,l)=>l*s+e)});c(this,"asyncMap",async(e,t)=>Promise.all(e.map(t)));c(this,"flatMap",(e=[],t)=>e.map(t).reduce((n,s)=>[...n,...s],[]));c(this,"escapeHTML",function(e){const t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"},n=/[&<>"']/g,s=new RegExp(n.source);return e&&s.test(e)?e.replace(n,i=>t[i]):e})}stringify(e,t,n){const s=[];for(const i in e){if(!Object.prototype.hasOwnProperty.call(e,i))continue;const l=e[i],g=n?"":encodeURIComponent(i);let p;typeof l=="object"?p=this.stringify(l,t?t+encodeURIComponent(`[${g}]`):g,Array.isArray(l)):p=`${t?t+encodeURIComponent(`[${g}]`):g}=${encodeURIComponent(l)}`,s.push(p)}return s.join("&")}getRegionURL(e){const t="api.storyblok.com",n="api-us.storyblok.com",s="app.storyblokchina.cn",i="api-ap.storyblok.com",l="api-ca.storyblok.com";switch(e){case"us":return n;case"cn":return s;case"ap":return i;case"ca":return l;default:return t}}}const o=function(r,e){const t={};for(const n in r){const s=r[n];e.includes(n)&&s!==null&&(t[n]=s)}return t},u=r=>r==="email";return{nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:r=>({tag:["pre",{tag:"code",attrs:r.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:r=>({tag:`h${r.attrs.level}`}),image:r=>({singleTag:[{tag:"img",attrs:o(r.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:r=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":r.attrs.name,emoji:r.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:r=>{if(!r.attrs)return{tag:""};const e=new a().escapeHTML,t={...r.attrs},{linktype:n="url"}=r.attrs;if(delete t.linktype,t.href&&(t.href=e(r.attrs.href||"")),u(n)&&(t.href=`mailto:${t.href}`),t.anchor&&(t.href=`${t.href}#${t.anchor}`,delete t.anchor),t.custom){for(const s in t.custom)t[s]=t.custom[s];delete t.custom}return{tag:[{tag:"a",attrs:t}]}},styled:r=>({tag:[{tag:"span",attrs:r.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:r=>({tag:[{tag:"span",attrs:r.attrs}]}),highlight:r=>{var t;return(t=r.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${r.attrs.color};`}}]}:{tag:""}},textStyle:r=>{var t;return(t=r.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${r.attrs.color}`}}]}:{tag:""}}}}});

@@ -1,2 +0,2 @@

declare const METHOD: {
declare const _METHOD: {
readonly GET: "get";

@@ -8,3 +8,3 @@ readonly DELETE: "delete";

type ObjectValues<T> = T[keyof T];
type Method = ObjectValues<typeof METHOD>;
type Method = ObjectValues<typeof _METHOD>;
export default Method;

@@ -11,0 +11,0 @@ export declare const STORYBLOK_AGENT = "SB-Agent";

@@ -6,4 +6,4 @@ import Client from './index';

export { default as RichtextResolver } from './richTextResolver';
export { default as RichtextSchema } from './schema';
export { default as SbFetch } from './sbFetch';
export * from './sbHelpers';
export { default as RichtextSchema } from './schema';
import RichTextResolver from './richTextResolver';
import { ISbStoriesParams, ISbConfig, ISbResult, ISbStories, ISbStory, ISbStoryData, ISbStoryParams, ISbContentMangmntAPI, ISbCustomFetch } from './interfaces';
type ComponentResolverFn = {
import type { ISbConfig, ISbContentMangmntAPI, ISbCustomFetch, ISbResponseData, ISbResult, ISbStories, ISbStoriesParams, ISbStory, ISbStoryParams } from './interfaces';
interface ComponentResolverFn {
(...args: any): any;
};
type CachedVersions = {
}
interface CachedVersions {
[key: string]: number;
};
type LinksType = {
}
interface LinksType {
[key: string]: any;
};
type RelationsType = {
}
interface RelationsType {
[key: string]: any;
};
export interface ISbResponseData {
link_uuids: string[];
links: string[];
rel_uuids: string[];
rels: any;
story: ISbStoryData;
stories: Array<ISbStoryData>;
}

@@ -40,3 +32,3 @@ declare class Storyblok {

* @param config ISbConfig interface
* @param endpoint string, optional
* @param pEndpoint string, optional
*/

@@ -43,0 +35,0 @@ constructor(config: ISbConfig, pEndpoint?: string);

@@ -1,2 +0,3 @@

import { ResponseFn } from './sbFetch';
import type { ResponseFn } from './sbFetch';
import type Method from './constants';
export interface ISbStoriesParams extends Partial<ISbStoryData>, ISbMultipleStoriesData, ISbAssetsParams {

@@ -54,3 +55,3 @@ resolve_level?: number;

}
type Dimension = {
interface Dimension {
id: number;

@@ -62,3 +63,3 @@ name: string;

updated_at: string;
};
}
/**

@@ -226,2 +227,3 @@ * @interface ISbDimensions

statusText: string;
headers: any;
}

@@ -245,8 +247,8 @@ export interface ISbError {

}
export type NodeSchema = {
export interface NodeSchema {
(node: ISbNode): object;
};
export type MarkSchema = {
}
export interface MarkSchema {
(node: ISbNode): object;
};
}
export interface ISbContentMangmntAPI<Content = ISbComponentType<string> & {

@@ -314,10 +316,25 @@ [index: string]: any;

}
export type ThrottleFn = {
(...args: any): any;
};
export interface Queue<T> {
resolve: (value: unknown) => void;
reject: (reason?: unknown) => void;
args: T;
}
export interface ISbResponseData {
link_uuids: string[];
links: string[];
rel_uuids: string[];
rels: any;
story: ISbStoryData;
stories: Array<ISbStoryData>;
}
export interface ISbThrottle<T extends (...args: Parameters<T>) => ReturnType<T>> {
abort?: () => void;
(...args: Parameters<T>): Promise<unknown>;
}
export type ISbThrottledRequest = (type: Method, url: string, params: ISbStoriesParams, fetchOptions?: ISbCustomFetch) => Promise<unknown>;
export type AsyncFn = (...args: any) => [] | Promise<ISbResult>;
export type ArrayFn = (...args: any) => void;
export type HtmlEscapes = {
export interface HtmlEscapes {
[key: string]: string;
};
}
export interface ISbCustomFetch extends Omit<RequestInit, 'method'> {

@@ -324,0 +341,0 @@ }

@@ -1,2 +0,2 @@

import { ISbSchema, ISbRichtext } from './interfaces';
import type { ISbRichtext, ISbSchema } from './interfaces';
type OptimizeImagesOptions = boolean | {

@@ -19,5 +19,5 @@ class?: string;

};
type RenderOptions = {
interface RenderOptions {
optimizeImages?: OptimizeImagesOptions;
};
}
interface ISbFunction<T extends any[], R> {

@@ -24,0 +24,0 @@ (...args: T): R;

@@ -1,5 +0,5 @@

import { ISbResponse, ISbError, ISbStoriesParams, ISbCustomFetch } from './interfaces';
export type ResponseFn = {
import type { ISbCustomFetch, ISbError, ISbResponse, ISbStoriesParams } from './interfaces';
export interface ResponseFn {
(arg?: ISbResponse | any): any;
};
}
export interface ISbFetch {

@@ -6,0 +6,0 @@ baseURL: string;

@@ -1,2 +0,2 @@

import { ISbStoriesParams, ISbResult, AsyncFn } from './interfaces';
import type { AsyncFn, ISbResult, ISbStoriesParams } from './interfaces';
interface ISbParams extends ISbStoriesParams {

@@ -114,6 +114,6 @@ [key: string]: any;

* @method stringify
* @param {Object} params
* @param {String} prefix
* @param {Boolean} isArray
* @return {String} Stringified object
* @param {object} params
* @param {string} prefix
* @param {boolean} isArray
* @return {string} Stringified object
*/

@@ -123,4 +123,4 @@ stringify(params: ISbParams, prefix?: string, isArray?: boolean): string;

* @method getRegionURL
* @param {String} regionCode region code, could be eu, us, cn, ap or ca
* @return {String} The base URL of the region
* @param {string} regionCode region code, could be eu, us, cn, ap or ca
* @return {string} The base URL of the region
*/

@@ -130,4 +130,4 @@ getRegionURL(regionCode?: string): string;

* @method escapeHTML
* @param {String} string text to be parsed
* @return {String} Text parsed
* @param {string} string text to be parsed
* @return {string} Text parsed
*/

@@ -134,0 +134,0 @@ escapeHTML: (string: string) => string;

@@ -1,2 +0,2 @@

import { NodeSchema, MarkSchema } from './interfaces';
import type { MarkSchema, NodeSchema } from './interfaces';
declare const _default: {

@@ -3,0 +3,0 @@ nodes: {

@@ -1,15 +0,3 @@

import { ThrottleFn } from './interfaces';
type Queue = {
resolve: (args: any) => any;
reject: (args: any) => any;
args: any[];
self: any;
};
interface ISbThrottle {
abort: () => any;
(args: []): Promise<Queue>;
name: string;
AbortError?: () => void;
}
declare function throttledQueue(fn: ThrottleFn, limit: number, interval: number): ISbThrottle;
import type { ISbThrottle } from './interfaces';
declare function throttledQueue<T extends (...args: Parameters<T>) => ReturnType<T>>(fn: T, limit: number, interval: number): ISbThrottle<T>;
export default throttledQueue;
{
"name": "storyblok-js-client",
"module": "./dist/index.mjs",
"version": "6.10.1",
"packageManager": "pnpm@9.1.4",
"version": "6.10.2",
"packageManager": "pnpm@9.12.3",
"description": "Universal JavaScript SDK for Storyblok's API",
"author": "Alexander Feiglstorfer <delooks@gmail.com>",
"license": "MIT",
"homepage": "https://github.com/storyblok/storyblok-js-client#readme",
"repository": {
"type": "git",
"url": "https://github.com/storyblok/storyblok-js-client.git"
},
"bugs": {
"url": "https://github.com/storyblok/storyblok-js-client/issues"
},
"keywords": [

@@ -14,24 +22,25 @@ "storyblok",

"sideEffects": false,
"types": "./dist/types/entry.esm.d.ts",
"main": "./dist/index.umd.js",
"unpkg": "./dist/index.umd.js",
"jsdelivr": "./dist/index.umd.js",
"source": "src/index.ts",
"exports": {
".": {
"types": "./dist/types/entry.esm.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.umd.js",
"types": "./dist/types/entry.esm.d.ts"
"require": "./dist/index.umd.js"
},
"./richTextResolver": {
"types": "./dist/types/richTextResolver.d.ts",
"import": "./dist/richTextResolver.mjs",
"require": "./dist/richTextResolver.umd.js",
"types": "./dist/types/richTextResolver.d.ts"
"require": "./dist/richTextResolver.umd.js"
},
"./schema": {
"types": "./dist/types/schema.d.ts",
"import": "./dist/schema.mjs",
"require": "./dist/schema.umd.js",
"types": "./dist/types/schema.d.ts"
"require": "./dist/schema.umd.js"
}
},
"main": "./dist/index.umd.js",
"module": "./dist/index.mjs",
"unpkg": "./dist/index.umd.js",
"jsdelivr": "./dist/index.umd.js",
"types": "./dist/types/entry.esm.d.ts",
"source": "src/index.ts",
"files": [

@@ -44,3 +53,2 @@ "dist",

"lint": "eslint --max-warnings=0 './src/**/*.{ts,js}'",
"prettier": "prettier . --write",
"build": "node vite.build.mjs && tsc",

@@ -55,30 +63,21 @@ "demo": "vite serve playground",

},
"repository": {
"type": "git",
"url": "https://github.com/storyblok/storyblok-js-client.git"
},
"author": "Alexander Feiglstorfer <delooks@gmail.com>",
"bugs": {
"url": "https://github.com/storyblok/storyblok-js-client/issues"
},
"homepage": "https://github.com/storyblok/storyblok-js-client#readme",
"devDependencies": {
"@commitlint/cli": "^18.4.3",
"@commitlint/config-conventional": "^18.4.3",
"@tsconfig/recommended": "^1.0.7",
"@typescript-eslint/eslint-plugin": "^6.12.0",
"@typescript-eslint/parser": "^6.12.0",
"@vitest/coverage-v8": "^2.0.5",
"@vitest/ui": "^2.0.5",
"eslint": "^8.54.0",
"eslint-config-prettier": "^9.0.0",
"husky": "^9.1.5",
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"@storyblok/eslint-config": "^0.3.0",
"@tsconfig/recommended": "^1.0.8",
"@typescript-eslint/eslint-plugin": "^8.14.0",
"@typescript-eslint/parser": "^8.14.0",
"@vitest/coverage-v8": "^2.1.4",
"@vitest/ui": "^2.1.4",
"eslint": "^9.14.0",
"eslint-config-prettier": "^9.1.0",
"isomorphic-fetch": "^3.0.0",
"kolorist": "^1.8.0",
"prettier": "^3.3.3",
"typescript": "^5.5.4",
"vite": "^5.4.2",
"vite-plugin-banner": "^0.7.1",
"vite-plugin-dts": "^4.0.3",
"vitest": "^2.0.5"
"typescript": "^5.6.3",
"vite": "^5.4.11",
"vite-plugin-banner": "^0.8.0",
"vite-plugin-dts": "^4.3.0",
"vitest": "^2.1.4"
},

@@ -101,11 +100,2 @@ "release": {

},
"lint-staged": {
"*.{js,jsx,css,ts,tsx}": [
"prettier --write",
"eslint"
],
"*.md": [
"prettier --write"
]
},
"commitlint": {

@@ -115,35 +105,3 @@ "extends": [

]
},
"eslintConfig": {
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-var-requires": 1,
"no-async-promise-executor": 0,
"no-undef": 0
}
},
"prettier": {
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}
}

@@ -1,2 +0,2 @@

const METHOD = {
const _METHOD = {
GET: 'get',

@@ -6,10 +6,10 @@ DELETE: 'delete',

PUT: 'put',
} as const
} as const;
type ObjectValues<T> = T[keyof T]
type Method = ObjectValues<typeof METHOD>
type ObjectValues<T> = T[keyof T];
type Method = ObjectValues<typeof _METHOD>;
export default Method
export default Method;
export const STORYBLOK_AGENT = 'SB-Agent'
export const STORYBLOK_AGENT = 'SB-Agent';

@@ -20,2 +20,2 @@ export const STORYBLOK_JS_CLIENT_AGENT = {

packageVersion: '6.0.0',
}
};

@@ -1,10 +0,10 @@

import Client from './index'
import Client from './index';
// All default and named exports, including types for ESM bundle
export default Client
export * from './constants'
export * from './interfaces'
export { default as RichtextResolver } from './richTextResolver'
export { default as RichtextSchema } from './schema'
export { default as SbFetch } from './sbFetch'
export * from './sbHelpers'
export default Client;
export * from './constants';
export * from './interfaces';
export { default as RichtextResolver } from './richTextResolver';
export { default as SbFetch } from './sbFetch';
export * from './sbHelpers';
export { default as RichtextSchema } from './schema';

@@ -1,15 +0,17 @@

import Client from './index'
import RichtextResolver from './richTextResolver'
import SbFetch from './sbFetch'
import RichTextSchema from './schema'
import * as sbHelpers from './sbHelpers'
import Client from './index';
import RichtextResolver from './richTextResolver';
import SbFetch from './sbFetch';
import RichTextSchema from './schema';
import * as sbHelpers from './sbHelpers';
const extend = (to: Record<any, any>, _from: Record<any, any>) => {
for (const key in _from) to[key] = _from[key]
}
for (const key in _from) {
to[key] = _from[key];
}
};
extend(Client, { RichtextResolver, SbFetch, RichTextSchema })
extend(Client, sbHelpers)
extend(Client, { RichtextResolver, SbFetch, RichTextSchema });
extend(Client, sbHelpers);
// Single default export object for UMD friendly bundle
export default Client
export default Client;

@@ -1,5 +0,6 @@

import StoryblokClient from '.'
import { describe, it, expect, beforeEach, vi } from 'vitest'
import SbFetch, { ResponseFn } from './sbFetch'
import { SbHelpers } from './sbHelpers'
import StoryblokClient from '.';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { ResponseFn } from './sbFetch';
import SbFetch from './sbFetch';
import { SbHelpers } from './sbHelpers';

@@ -14,21 +15,22 @@ // Mocking external dependencies

status: 200,
})
const mockPost = vi.fn()
const mockSetFetchOptions = vi.fn()
});
const mockPost = vi.fn();
const mockSetFetchOptions = vi.fn();
// Define a mock class with baseURL property
class MockSbFetch {
private baseURL: string
private timeout?: number
private headers: Headers
private helpers: any
private responseInterceptor?: ResponseFn
private baseURL: string;
private timeout?: number;
private headers: Headers;
private helpers: any;
private responseInterceptor?: ResponseFn;
constructor(config: any) {
this.helpers = new SbHelpers()
this.baseURL = config.baseURL || 'https://api.storyblok.com/v2'
this.responseInterceptor = config.responseInterceptor
this.helpers = new SbHelpers();
this.baseURL = config.baseURL || 'https://api.storyblok.com/v2';
this.responseInterceptor = config.responseInterceptor;
}
public get = mockGet
public post = mockPost
public setFetchOptions = mockSetFetchOptions
public get = mockGet;
public post = mockPost;
public setFetchOptions = mockSetFetchOptions;
}

@@ -38,7 +40,7 @@

default: MockSbFetch,
}
})
};
});
describe('StoryblokClient', () => {
let client
describe('storyblokClient', () => {
let client;

@@ -50,38 +52,38 @@ beforeEach(() => {

/* fetch: mockFetch, */
})
})
});
});
describe('initialization', () => {
it('should initialize a client instance', () => {
expect(client).toBeDefined()
expect(client).toBeInstanceOf(StoryblokClient)
})
expect(client).toBeDefined();
expect(client).toBeInstanceOf(StoryblokClient);
});
it('should initialize with default values', () => {
expect(client.maxRetries).toBe(10)
expect(client.retriesDelay).toBe(300)
expect(client.maxRetries).toBe(10);
expect(client.retriesDelay).toBe(300);
expect(client.cache).toEqual({
clear: 'manual',
})
expect(client.relations).toEqual({})
expect(client.links).toEqual({})
});
expect(client.relations).toEqual({});
expect(client.links).toEqual({});
// Failing test
/* expect(client.helpers).toBeInstanceOf(SbHelpers) */
expect(client.resolveCounter).toBe(0)
expect(client.resolveNestedRelations).toBeTruthy()
expect(client.stringifiedStoriesCache).toEqual({})
})
expect(client.resolveCounter).toBe(0);
expect(client.resolveNestedRelations).toBeTruthy();
expect(client.stringifiedStoriesCache).toEqual({});
});
it('should set an accessToken', () => {
expect(client.accessToken).toBe('test-token')
})
expect(client.accessToken).toBe('test-token');
});
it('should set an endpoint', () => {
expect(client.client.baseURL).toBe('https://api.storyblok.com/v2')
})
expect(client.client.baseURL).toBe('https://api.storyblok.com/v2');
});
it('should set a fetch instance', () => {
expect(client.client).toBeInstanceOf(SbFetch)
})
})
expect(client.client).toBeInstanceOf(SbFetch);
});
});

@@ -92,7 +94,6 @@ describe('configuration via options', () => {

endpoint: 'https://api-custom.storyblok.com/v2',
})
});
expect(client.client.baseURL).toBe('https://api-custom.storyblok.com/v2')
})
expect(client.client.baseURL).toBe('https://api-custom.storyblok.com/v2');
});
it('https: should set the http endpoint if option is set to false', () => {

@@ -102,27 +103,27 @@ client = new StoryblokClient({

https: false,
})
});
expect(client.client.baseURL).toBe('http://api.storyblok.com/v2')
})
expect(client.client.baseURL).toBe('http://api.storyblok.com/v2');
});
it('should set the management endpoint v1 if oauthToken is available', () => {
client = new StoryblokClient({
oauthToken: 'test-token',
})
});
expect(client.client.baseURL).toBe('https://api.storyblok.com/v1')
})
expect(client.client.baseURL).toBe('https://api.storyblok.com/v1');
});
it('should set the correct region endpoint', () => {
client = new StoryblokClient({
region: 'us',
})
});
expect(client.client.baseURL).toBe('https://api-us.storyblok.com/v2')
})
expect(client.client.baseURL).toBe('https://api-us.storyblok.com/v2');
});
it('should set maxRetries', () => {
client = new StoryblokClient({
maxRetries: 5,
})
});
expect(client.maxRetries).toBe(5)
})
expect(client.maxRetries).toBe(5);
});
// TODO: seems like implmentation is missing

@@ -132,6 +133,6 @@ it.skip('should desactivate resolveNestedRelations', () => {

resolveNestedRelations: false,
})
});
expect(client.resolveNestedRelations).toBeFalsy()
})
expect(client.resolveNestedRelations).toBeFalsy();
});

@@ -143,53 +144,52 @@ it('should set automatic cache clearing', () => {

},
})
});
expect(client.cache.clear).toBe('auto')
})
expect(client.cache.clear).toBe('auto');
});
it('should set a responseInterceptor', async () => {
const responseInterceptor = (response) => {
return response
}
return response;
};
client = new StoryblokClient({
responseInterceptor,
})
await client.getAll('cdn/links')
expect(client.client.responseInterceptor).toBe(responseInterceptor)
})
})
});
await client.getAll('cdn/links');
expect(client.client.responseInterceptor).toBe(responseInterceptor);
});
});
describe('cache', () => {
it('should return cacheVersions', async () => {
const mockThrottle = vi.fn().mockResolvedValue({
data: {
data: {
stories: [{ id: 1, title: 'Update' }],
cv: 1645521118
cv: 1645521118,
},
headers: {},
status: 200
status: 200,
});
client.throttle = mockThrottle;
await client.get('test', { version: 'draft', token: 'test-token' });
expect(client.cacheVersions()).toEqual({
'test-token': 1645521118
'test-token': 1645521118,
});
})
});
it('should return cacheVersion', async () => {
const mockThrottle = vi.fn().mockResolvedValue({
data: {
data: {
stories: [{ id: 1, title: 'Update' }],
cv: 1645521118
cv: 1645521118,
},
headers: {},
status: 200
status: 200,
});
client.throttle = mockThrottle;
await client.get('test', { version: 'draft', token: 'test-token' });
expect(client.cacheVersion('test-token')).toBe(1645521118);
})
});

@@ -199,8 +199,8 @@ it('should set the cache version', async () => {

expect(client.cacheVersions()).toEqual({
'test-token': 1645521118
'test-token': 1645521118,
});
})
});
it('should clear the cache', async () => {
// Mock the cacheProvider and its flush method
// Mock the cacheProvider and its flush method
client.cacheProvider = vi.fn().mockReturnValue({

@@ -211,7 +211,7 @@ flush: vi.fn().mockResolvedValue(undefined),

client.clearCacheVersion = vi.fn();
await client.flushCache();
await client.flushCache();
expect(client.cacheProvider().flush).toHaveBeenCalled();
expect(client.clearCacheVersion).toHaveBeenCalled();
})
});

@@ -221,3 +221,3 @@ it('should clear the cache version', async () => {

expect(client.cacheVersion()).toEqual(0);
})
});

@@ -236,13 +236,15 @@ it('should flush the cache when the draft version is requested and clear is auto', async () => {

});
})
});
describe('get', () => {
it('should fetch data from the API', async () => {
const result = await client.get('test')
expect(result).toEqual({ data: {
links: 'Test data',
}, headers: {} })
})
})
const result = await client.get('test');
expect(result).toEqual({
data: {
links: 'Test data',
},
headers: {},
});
});
});

@@ -260,10 +262,10 @@ describe('getAll', () => {

status: 200,
})
client.makeRequest = mockMakeRequest
const result = await client.getAll('links', { version: 'draft' })
});
client.makeRequest = mockMakeRequest;
const result = await client.getAll('links', { version: 'draft' });
expect(result).toEqual([
{ id: 1, name: 'Test 1' },
{ id: 2, name: 'Test 2' },
])
})
]);
});

@@ -280,10 +282,14 @@ it('should resolve using entity option', async () => {

status: 200,
})
client.makeRequest = mockMakeRequest
const result = await client.getAll('cdn/links', { version: 'draft' }, 'custom')
});
client.makeRequest = mockMakeRequest;
const result = await client.getAll(
'cdn/links',
{ version: 'draft' },
'custom',
);
expect(result).toEqual([
{ id: 1, name: 'Test 1' },
{ id: 2, name: 'Test 2' },
])
})
]);
});

@@ -300,7 +306,7 @@ it('should make a request for each page', async () => {

status: 200,
})
client.makeRequest = mockMakeRequest
await client.getAll('links', { per_page: 1 })
expect(mockMakeRequest).toBeCalledTimes(2)
})
});
client.makeRequest = mockMakeRequest;
await client.getAll('links', { per_page: 1 });
expect(mockMakeRequest).toBeCalledTimes(2);
});

@@ -317,11 +323,11 @@ it('should get all stories if the slug is passed with the trailing slash', async () => {

status: 200,
})
client.makeRequest = mockMakeRequest
const result = await client.getAll('cdn/stories/', { version: 'draft' })
});
client.makeRequest = mockMakeRequest;
const result = await client.getAll('cdn/stories/', { version: 'draft' });
expect(result).toEqual([
{ id: 1, name: 'Test Story 1' },
{ id: 2, name: 'Test Story 2' },
])
})
})
]);
});
});

@@ -331,19 +337,19 @@ describe('post', () => {

const mockThrottle = vi.fn().mockResolvedValue({
data: {
stories: [{ id: 1, title: 'Keep me posted' }]
data: {
stories: [{ id: 1, title: 'Keep me posted' }],
},
headers: {},
status: 200
status: 200,
});
client.throttle = mockThrottle;
const result = await client.post('test', { data: 'test' })
expect(result).toEqual({
const result = await client.post('test', { data: 'test' });
expect(result).toEqual({
data: {
stories: [{ id: 1, title: 'Keep me posted' }]
},
stories: [{ id: 1, title: 'Keep me posted' }],
},
headers: {},
status: 200
})
})
})
status: 200,
});
});
});

@@ -353,19 +359,19 @@ describe('put', () => {

const mockThrottle = vi.fn().mockResolvedValue({
data: {
stories: [{ id: 1, title: 'Update' }]
data: {
stories: [{ id: 1, title: 'Update' }],
},
headers: {},
status: 200
status: 200,
});
client.throttle = mockThrottle;
const result = await client.put('test', { data: 'test' })
expect(result).toEqual({
const result = await client.put('test', { data: 'test' });
expect(result).toEqual({
data: {
stories: [{ id: 1, title: 'Update' }]
},
stories: [{ id: 1, title: 'Update' }],
},
headers: {},
status: 200
})
})
})
status: 200,
});
});
});

@@ -375,19 +381,19 @@ describe('delete', () => {

const mockThrottle = vi.fn().mockResolvedValue({
data: {
stories: [{ id: 1, title: 'Delete' }]
data: {
stories: [{ id: 1, title: 'Delete' }],
},
headers: {},
status: 200
status: 200,
});
client.throttle = mockThrottle;
const result = await client.delete('test')
expect(result).toEqual({
const result = await client.delete('test');
expect(result).toEqual({
data: {
stories: [{ id: 1, title: 'Delete' }]
},
stories: [{ id: 1, title: 'Delete' }],
},
headers: {},
status: 200
})
})
})
status: 200,
});
});
});

@@ -398,3 +404,3 @@ it('should resolve stories when response contains a story or stories', async () => {

headers: {},
status: 200
status: 200,
});

@@ -406,5 +412,8 @@ client.throttle = mockThrottle;

});
await client.cacheResponse('/test-url', { token: 'test-token', version: 'published' });
await client.cacheResponse('/test-url', {
token: 'test-token',
version: 'published',
});
expect(client.resolveStories).toHaveBeenCalled();

@@ -414,8 +423,5 @@ expect(client.resolveCounter).toBe(1);

it('should return access token', () => {
it('should return access token', () => {
expect(client.getToken()).toBe('test-token');
})
})
});
});

@@ -1,82 +0,74 @@

import throttledQueue from './throttlePromise'
import RichTextResolver from './richTextResolver'
import { SbHelpers } from './sbHelpers'
import SbFetch from './sbFetch'
import { STORYBLOK_AGENT, STORYBLOK_JS_CLIENT_AGENT } from './constants'
import throttledQueue from './throttlePromise';
import RichTextResolver from './richTextResolver';
import { SbHelpers } from './sbHelpers';
import SbFetch from './sbFetch';
import type Method from './constants';
import { STORYBLOK_AGENT, STORYBLOK_JS_CLIENT_AGENT } from './constants';
import Method from './constants'
import {
ISbStoriesParams,
import type {
ICacheProvider,
IMemoryType,
ISbCache,
ISbConfig,
ISbContentMangmntAPI,
ISbCustomFetch,
ISbLinkURLObject,
ISbNode,
ISbResponse,
ISbResponseData,
ISbResult,
ISbStories,
ISbStoriesParams,
ISbStory,
ISbStoryData,
ISbStoryParams,
ISbContentMangmntAPI,
ISbNode,
ThrottleFn,
IMemoryType,
ICacheProvider,
ISbCustomFetch,
} from './interfaces'
} from './interfaces';
let memory: Partial<IMemoryType> = {}
let memory: Partial<IMemoryType> = {};
const cacheVersions = {} as CachedVersions
const cacheVersions = {} as CachedVersions;
type ComponentResolverFn = {
(...args: any): any
interface ComponentResolverFn {
(...args: any): any;
}
type CachedVersions = {
[key: string]: number
interface CachedVersions {
[key: string]: number;
}
type LinksType = {
[key: string]: any
interface LinksType {
[key: string]: any;
}
type RelationsType = {
[key: string]: any
interface RelationsType {
[key: string]: any;
}
interface ISbFlatMapped {
data: any
data: any;
}
export interface ISbResponseData {
link_uuids: string[]
links: string[]
rel_uuids: string[]
rels: any
story: ISbStoryData
stories: Array<ISbStoryData>
}
const VERSION = {
const _VERSION = {
V1: 'v1',
V2: 'v2',
} as const
} as const;
type ObjectValues<T> = T[keyof T]
type Version = ObjectValues<typeof VERSION>
type ObjectValues<T> = T[keyof T];
type Version = ObjectValues<typeof _VERSION>;
class Storyblok {
private client: SbFetch
private maxRetries: number
private retriesDelay: number
private throttle: ThrottleFn
private accessToken: string
private cache: ISbCache
private helpers: SbHelpers
private resolveCounter: number
public relations: RelationsType
public links: LinksType
private client: SbFetch;
private maxRetries: number;
private retriesDelay: number;
private throttle: ReturnType<typeof throttledQueue>;
private accessToken: string;
private cache: ISbCache;
private helpers: SbHelpers;
private resolveCounter: number;
public relations: RelationsType;
public links: LinksType;
// TODO: Remove on v7.x.x
public richTextResolver: RichTextResolver
public resolveNestedRelations: boolean
private stringifiedStoriesCache: Record<string, string>
public richTextResolver: RichTextResolver;
public resolveNestedRelations: boolean;
private stringifiedStoriesCache: Record<string, string>;

@@ -86,79 +78,89 @@ /**

* @param config ISbConfig interface
* @param endpoint string, optional
* @param pEndpoint string, optional
*/
public constructor(config: ISbConfig, pEndpoint?: string) {
let endpoint = config.endpoint || pEndpoint
let endpoint = config.endpoint || pEndpoint;
if (!endpoint) {
const getRegion = new SbHelpers().getRegionURL
const protocol = config.https === false ? 'http' : 'https'
const getRegion = new SbHelpers().getRegionURL;
const protocol = config.https === false ? 'http' : 'https';
if (!config.oauthToken) {
endpoint = `${protocol}://${getRegion(config.region)}/${'v2' as Version}`
} else {
endpoint = `${protocol}://${getRegion(config.region)}/${'v1' as Version}`
endpoint = `${protocol}://${getRegion(config.region)}/${'v2' as Version}`;
}
else {
endpoint = `${protocol}://${getRegion(config.region)}/${'v1' as Version}`;
}
}
const headers: Headers = new Headers()
const headers: Headers = new Headers();
headers.set('Content-Type', 'application/json')
headers.set('Accept', 'application/json')
headers.set('Content-Type', 'application/json');
headers.set('Accept', 'application/json');
if (config.headers) {
const entries = (config.headers.constructor.name === 'Headers') ? config.headers.entries().toArray() : Object.entries(config.headers)
const entries
= config.headers.constructor.name === 'Headers'
? config.headers.entries().toArray()
: Object.entries(config.headers);
entries.forEach(([key, value]: [string, string]) => {
headers.set(key, value)
})
headers.set(key, value);
});
}
if (!headers.has(STORYBLOK_AGENT)) {
headers.set(STORYBLOK_AGENT, STORYBLOK_JS_CLIENT_AGENT.defaultAgentName)
headers.set(STORYBLOK_AGENT, STORYBLOK_JS_CLIENT_AGENT.defaultAgentName);
headers.set(
STORYBLOK_JS_CLIENT_AGENT.defaultAgentVersion,
STORYBLOK_JS_CLIENT_AGENT.packageVersion
)
STORYBLOK_JS_CLIENT_AGENT.packageVersion,
);
}
let rateLimit = 5 // per second for cdn api
let rateLimit = 5; // per second for cdn api
if (config.oauthToken) {
headers.set('Authorization', config.oauthToken)
rateLimit = 3 // per second for management api
headers.set('Authorization', config.oauthToken);
rateLimit = 3; // per second for management api
}
if (config.rateLimit) {
rateLimit = config.rateLimit
rateLimit = config.rateLimit;
}
if (config.richTextSchema) {
this.richTextResolver = new RichTextResolver(config.richTextSchema)
} else {
this.richTextResolver = new RichTextResolver()
this.richTextResolver = new RichTextResolver(config.richTextSchema);
}
else {
this.richTextResolver = new RichTextResolver();
}
if (config.componentResolver) {
this.setComponentResolver(config.componentResolver)
this.setComponentResolver(config.componentResolver);
}
this.maxRetries = config.maxRetries || 10
this.retriesDelay = 300
this.throttle = throttledQueue(this.throttledRequest, rateLimit, 1000)
this.accessToken = config.accessToken || ''
this.relations = {} as RelationsType
this.links = {} as LinksType
this.cache = config.cache || { clear: 'manual' }
this.helpers = new SbHelpers()
this.resolveCounter = 0
this.resolveNestedRelations = config.resolveNestedRelations || true
this.stringifiedStoriesCache = {} as Record<string, string>
this.maxRetries = config.maxRetries || 10;
this.retriesDelay = 300;
this.throttle = throttledQueue(
this.throttledRequest.bind(this),
rateLimit,
1000,
);
this.accessToken = config.accessToken || '';
this.relations = {} as RelationsType;
this.links = {} as LinksType;
this.cache = config.cache || { clear: 'manual' };
this.helpers = new SbHelpers();
this.resolveCounter = 0;
this.resolveNestedRelations = config.resolveNestedRelations || true;
this.stringifiedStoriesCache = {} as Record<string, string>;
this.client = new SbFetch({
baseURL: endpoint,
timeout: config.timeout || 0,
headers: headers,
headers,
responseInterceptor: config.responseInterceptor,
fetch: config.fetch,
})
});
}

@@ -168,14 +170,14 @@

this.richTextResolver.addNode('blok', (node: ISbNode) => {
let html = ''
let html = '';
if (node.attrs.body) {
node.attrs.body.forEach((blok) => {
html += resolver(blok.component, blok)
})
html += resolver(blok.component, blok);
});
}
return {
html: html,
}
})
html,
};
});
}

@@ -185,18 +187,18 @@

if (!params.token) {
params.token = this.getToken()
params.token = this.getToken();
}
if (!params.cv) {
params.cv = cacheVersions[params.token]
params.cv = cacheVersions[params.token];
}
if (Array.isArray(params.resolve_relations)) {
params.resolve_relations = params.resolve_relations.join(',')
params.resolve_relations = params.resolve_relations.join(',');
}
if (typeof params.resolve_relations !== 'undefined') {
params.resolve_level = 2
params.resolve_level = 2;
}
return params
return params;
}

@@ -206,9 +208,9 @@

url: string,
params: ISbStoriesParams
params: ISbStoriesParams,
): ISbStoriesParams {
if (this.helpers.isCDNUrl(url)) {
return this.parseParams(params)
return this.parseParams(params);
}
return params
return params;
}

@@ -221,10 +223,10 @@

page: number,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbResult> {
const query = this.factoryParamOptions(
url,
this.helpers.getOptionsPage(params, per_page, page)
)
this.helpers.getOptionsPage(params, per_page, page),
);
return this.cacheResponse(url, query, undefined, fetchOptions)
return this.cacheResponse(url, query, undefined, fetchOptions);
}

@@ -235,9 +237,11 @@

params?: ISbStoriesParams,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbResult> {
if (!params) params = {} as ISbStoriesParams
const url = `/${slug}`
const query = this.factoryParamOptions(url, params)
if (!params) {
params = {} as ISbStoriesParams;
}
const url = `/${slug}`;
const query = this.factoryParamOptions(url, params);
return this.cacheResponse(url, query, undefined, fetchOptions)
return this.cacheResponse(url, query, undefined, fetchOptions);
}

@@ -249,9 +253,9 @@

entity?: string,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<any[]> {
const perPage = params?.per_page || 25
const url = `/${slug}`.replace(/\/$/, '')
const e = entity ?? url.substring(url.lastIndexOf('/') + 1)
const perPage = params?.per_page || 25;
const url = `/${slug}`.replace(/\/$/, '');
const e = entity ?? url.substring(url.lastIndexOf('/') + 1);
const firstPage = 1
const firstPage = 1;
const firstRes = await this.makeRequest(

@@ -262,5 +266,5 @@ url,

firstPage,
fetchOptions
)
const lastPage = firstRes.total ? Math.ceil(firstRes.total / perPage) : 1
fetchOptions,
);
const lastPage = firstRes.total ? Math.ceil(firstRes.total / perPage) : 1;

@@ -270,9 +274,8 @@ const restRes: any = await this.helpers.asyncMap(

(i: number) => {
return this.makeRequest(url, params, perPage, i + 1, fetchOptions)
}
)
return this.makeRequest(url, params, perPage, i + 1, fetchOptions);
},
);
return this.helpers.flatMap([firstRes, ...restRes], (res: ISbFlatMapped) =>
Object.values(res.data[e])
)
Object.values(res.data[e]));
}

@@ -283,7 +286,9 @@

params: ISbStoriesParams | ISbContentMangmntAPI,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbResponseData> {
const url = `/${slug}`
const url = `/${slug}`;
return Promise.resolve(this.throttle('post', url, params, fetchOptions))
return Promise.resolve(
this.throttle('post', url, params, fetchOptions),
) as Promise<ISbResponseData>;
}

@@ -294,7 +299,9 @@

params: ISbStoriesParams | ISbContentMangmntAPI,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbResponseData> {
const url = `/${slug}`
const url = `/${slug}`;
return Promise.resolve(this.throttle('put', url, params, fetchOptions))
return Promise.resolve(
this.throttle('put', url, params, fetchOptions),
) as Promise<ISbResponseData>;
}

@@ -305,7 +312,9 @@

params: ISbStoriesParams | ISbContentMangmntAPI,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbResponseData> {
const url = `/${slug}`
const url = `/${slug}`;
return Promise.resolve(this.throttle('delete', url, params, fetchOptions))
return Promise.resolve(
this.throttle('delete', url, params, fetchOptions),
) as Promise<ISbResponseData>;
}

@@ -315,7 +324,7 @@

params: ISbStoriesParams,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbStories> {
this._addResolveLevel(params)
this._addResolveLevel(params);
return this.get('cdn/stories', params, fetchOptions)
return this.get('cdn/stories', params, fetchOptions);
}

@@ -326,15 +335,15 @@

params: ISbStoryParams,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbStory> {
this._addResolveLevel(params)
this._addResolveLevel(params);
return this.get(`cdn/stories/${slug}`, params, fetchOptions)
return this.get(`cdn/stories/${slug}`, params, fetchOptions);
}
private getToken(): string {
return this.accessToken
return this.accessToken;
}
public ejectInterceptor(): void {
this.client.eject()
this.client.eject();
}

@@ -344,3 +353,3 @@

if (typeof params.resolve_relations !== 'undefined') {
params.resolve_level = 2
params.resolve_level = 2;
}

@@ -350,3 +359,3 @@ }

private _cleanCopy(value: LinksType): JSON {
return JSON.parse(JSON.stringify(value))
return JSON.parse(JSON.stringify(value));
}

@@ -357,21 +366,22 @@

treeItem: keyof ISbStoriesParams,
resolveId: string
resolveId: string,
): void {
const node = jtree[treeItem]
const node = jtree[treeItem];
if (
node &&
node.fieldtype == 'multilink' &&
node.linktype == 'story' &&
typeof node.id === 'string' &&
this.links[resolveId][node.id]
node
&& node.fieldtype === 'multilink'
&& node.linktype === 'story'
&& typeof node.id === 'string'
&& this.links[resolveId][node.id]
) {
node.story = this._cleanCopy(this.links[resolveId][node.id])
} else if (
node &&
node.linktype === 'story' &&
typeof node.uuid === 'string' &&
this.links[resolveId][node.uuid]
node.story = this._cleanCopy(this.links[resolveId][node.id]);
}
else if (
node
&& node.linktype === 'story'
&& typeof node.uuid === 'string'
&& this.links[resolveId][node.uuid]
) {
node.story = this._cleanCopy(this.links[resolveId][node.uuid])
node.story = this._cleanCopy(this.links[resolveId][node.uuid]);
}

@@ -387,8 +397,11 @@ }

private getStoryReference(resolveId: string, uuid: string): string | JSON {
if (!this.relations[resolveId][uuid]) return uuid
if (!this.stringifiedStoriesCache[uuid])
if (!this.relations[resolveId][uuid]) {
return uuid;
}
if (!this.stringifiedStoriesCache[uuid]) {
this.stringifiedStoriesCache[uuid] = JSON.stringify(
this.relations[resolveId][uuid]
)
return JSON.parse(this.stringifiedStoriesCache[uuid])
this.relations[resolveId][uuid],
);
}
return JSON.parse(this.stringifiedStoriesCache[uuid]);
}

@@ -400,11 +413,12 @@

fields: string | Array<string>,
resolveId: string
resolveId: string,
): void {
if (fields.indexOf(`${jtree.component}.${treeItem}`) > -1) {
if (fields.includes(`${jtree.component}.${treeItem}`)) {
if (typeof jtree[treeItem] === 'string') {
jtree[treeItem] = this.getStoryReference(resolveId, jtree[treeItem])
} else if (Array.isArray(jtree[treeItem])) {
jtree[treeItem] = this.getStoryReference(resolveId, jtree[treeItem]);
}
else if (Array.isArray(jtree[treeItem])) {
jtree[treeItem] = jtree[treeItem as keyof ISbStoriesParams]
.map((uuid: string) => this.getStoryReference(resolveId, uuid))
.filter(Boolean)
.filter(Boolean);
}

@@ -417,15 +431,16 @@ }

fields: string | Array<string>,
resolveId: string
resolveId: string,
): void {
const enrich = (jtree: ISbStoriesParams | any) => {
if (jtree == null) {
return
return;
}
if (jtree.constructor === Array) {
for (let item = 0; item < jtree.length; item++) {
enrich(jtree[item])
enrich(jtree[item]);
}
} else if (jtree.constructor === Object) {
}
else if (jtree.constructor === Object) {
if (jtree._stopResolving) {
return
return;
}

@@ -438,16 +453,16 @@ for (const treeItem in jtree) {

fields,
resolveId
)
resolveId,
);
this._insertLinks(
jtree,
treeItem as keyof ISbStoriesParams,
resolveId
)
resolveId,
);
}
enrich(jtree[treeItem])
enrich(jtree[treeItem]);
}
}
}
};
enrich(story.content)
enrich(story.content);
}

@@ -458,14 +473,14 @@

params: ISbStoriesParams,
resolveId: string
resolveId: string,
): Promise<void> {
let links: (ISbStoryData | ISbLinkURLObject | string)[] = []
let links: (ISbStoryData | ISbLinkURLObject | string)[] = [];
if (responseData.link_uuids) {
const relSize = responseData.link_uuids.length
const chunks = []
const chunkSize = 50
const relSize = responseData.link_uuids.length;
const chunks = [];
const chunkSize = 50;
for (let i = 0; i < relSize; i += chunkSize) {
const end = Math.min(relSize, i + chunkSize)
chunks.push(responseData.link_uuids.slice(i, end))
const end = Math.min(relSize, i + chunkSize);
chunks.push(responseData.link_uuids.slice(i, end));
}

@@ -479,13 +494,14 @@

by_uuids: chunks[chunkIndex].join(','),
})
});
linksRes.data.stories.forEach(
(rel: ISbStoryData | ISbLinkURLObject | string) => {
links.push(rel)
}
)
links.push(rel);
},
);
}
} else {
links = responseData.links
}
else {
links = responseData.links;
}

@@ -496,4 +512,4 @@ links.forEach((story: ISbStoryData | any) => {

...{ _stopResolving: true },
}
})
};
});
}

@@ -504,14 +520,14 @@

params: ISbStoriesParams,
resolveId: string
resolveId: string,
): Promise<void> {
let relations = []
let relations = [];
if (responseData.rel_uuids) {
const relSize = responseData.rel_uuids.length
const chunks = []
const chunkSize = 50
const relSize = responseData.rel_uuids.length;
const chunks = [];
const chunkSize = 50;
for (let i = 0; i < relSize; i += chunkSize) {
const end = Math.min(relSize, i + chunkSize)
chunks.push(responseData.rel_uuids.slice(i, end))
const end = Math.min(relSize, i + chunkSize);
chunks.push(responseData.rel_uuids.slice(i, end));
}

@@ -526,11 +542,12 @@

excluding_fields: params.excluding_fields,
})
});
relationsRes.data.stories.forEach((rel: ISbStoryData) => {
relations.push(rel)
})
relations.push(rel);
});
}
} else {
relations = responseData.rels
}
else {
relations = responseData.rels;
}

@@ -542,4 +559,4 @@ if (relations && relations.length > 0) {

...{ _stopResolving: true },
}
})
};
});
}

@@ -560,25 +577,25 @@ }

params: ISbStoriesParams,
resolveId: string
resolveId: string,
): Promise<void> {
let relationParams: string[] = []
let relationParams: string[] = [];
this.links[resolveId] = {}
this.relations[resolveId] = {}
this.links[resolveId] = {};
this.relations[resolveId] = {};
if (
typeof params.resolve_relations !== 'undefined' &&
params.resolve_relations.length > 0
typeof params.resolve_relations !== 'undefined'
&& params.resolve_relations.length > 0
) {
if (typeof params.resolve_relations === 'string') {
relationParams = params.resolve_relations.split(',')
relationParams = params.resolve_relations.split(',');
}
await this.resolveRelations(responseData, params, resolveId)
await this.resolveRelations(responseData, params, resolveId);
}
if (
params.resolve_links &&
['1', 'story', 'url', 'link'].indexOf(params.resolve_links) > -1 &&
(responseData.links?.length || responseData.link_uuids?.length)
params.resolve_links
&& ['1', 'story', 'url', 'link'].includes(params.resolve_links)
&& (responseData.links?.length || responseData.link_uuids?.length)
) {
await this.resolveLinks(responseData, params, resolveId)
await this.resolveLinks(responseData, params, resolveId);
}

@@ -591,4 +608,4 @@

relationParams,
resolveId
)
resolveId,
);
}

@@ -598,13 +615,14 @@ }

if (responseData.story) {
this.iterateTree(responseData.story, relationParams, resolveId)
} else {
this.iterateTree(responseData.story, relationParams, resolveId);
}
else {
responseData.stories.forEach((story: ISbStoryData) => {
this.iterateTree(story, relationParams, resolveId)
})
this.iterateTree(story, relationParams, resolveId);
});
}
this.stringifiedStoriesCache = {}
this.stringifiedStoriesCache = {};
delete this.links[resolveId]
delete this.relations[resolveId]
delete this.links[resolveId];
delete this.relations[resolveId];
}

@@ -616,15 +634,15 @@

retries?: number,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<ISbResult> {
const cacheKey = this.helpers.stringify({ url: url, params: params })
const provider = this.cacheProvider()
const cacheKey = this.helpers.stringify({ url, params });
const provider = this.cacheProvider();
if (this.cache.clear === 'auto' && params.version === 'draft') {
await this.flushCache()
await this.flushCache();
}
if (params.version === 'published' && url != '/cdn/spaces/me') {
const cache = await provider.get(cacheKey)
if (params.version === 'published' && url !== '/cdn/spaces/me') {
const cache = await provider.get(cacheKey);
if (cache) {
return Promise.resolve(cache)
return Promise.resolve(cache);
}

@@ -635,8 +653,13 @@ }

try {
const res = await this.throttle('get', url, params, fetchOptions)
const res = (await this.throttle(
'get',
url,
params,
fetchOptions,
)) as ISbResponse;
if (res.status !== 200) {
return reject(res)
return reject(res);
}
let response = { data: res.data, headers: res.headers } as ISbResult
let response = { data: res.data, headers: res.headers } as ISbResult;

@@ -646,44 +669,49 @@ if (res.headers?.['per-page']) {

perPage: res.headers['per-page']
? parseInt(res.headers['per-page'])
? Number.parseInt(res.headers['per-page'])
: 0,
total: res.headers['per-page'] ? parseInt(res.headers['total']) : 0,
})
total: res.headers['per-page']
? Number.parseInt(res.headers.total)
: 0,
});
}
if (response.data.story || response.data.stories) {
const resolveId = (this.resolveCounter = ++this.resolveCounter % 1000)
await this.resolveStories(response.data, params, `${resolveId}`)
const resolveId = (this.resolveCounter
= ++this.resolveCounter % 1000);
await this.resolveStories(response.data, params, `${resolveId}`);
}
if (params.version === 'published' && url != '/cdn/spaces/me') {
await provider.set(cacheKey, response)
if (params.version === 'published' && url !== '/cdn/spaces/me') {
await provider.set(cacheKey, response);
}
if (
response.data.cv
&& params.token
&& cacheVersions[params.token] != response.data.cv
response.data.cv
&& params.token
&& cacheVersions[params.token] !== response.data.cv
) {
await this.flushCache()
cacheVersions[params.token] = response.data.cv
await this.flushCache();
cacheVersions[params.token] = response.data.cv;
}
return resolve(response)
} catch (error: Error | any) {
return resolve(response);
}
catch (error: Error | any) {
if (error.response && error.status === 429) {
retries = typeof retries === 'undefined' ? 0 : retries + 1
retries = typeof retries === 'undefined' ? 0 : retries + 1;
if (retries < this.maxRetries) {
// eslint-disable-next-line no-console
console.log(
`Hit rate limit. Retrying in ${this.retriesDelay / 1000} seconds.`
)
await this.helpers.delay(this.retriesDelay)
`Hit rate limit. Retrying in ${this.retriesDelay / 1000} seconds.`,
);
await this.helpers.delay(this.retriesDelay);
return this.cacheResponse(url, params, retries)
.then(resolve)
.catch(reject)
.catch(reject);
}
}
reject(error)
reject(error);
}
})
});
}

@@ -695,14 +723,14 @@

params: ISbStoriesParams,
fetchOptions?: ISbCustomFetch
fetchOptions?: ISbCustomFetch,
): Promise<unknown> {
this.client.setFetchOptions(fetchOptions)
return this.client[type](url, params)
this.client.setFetchOptions(fetchOptions);
return this.client[type](url, params);
}
public cacheVersions(): CachedVersions {
return cacheVersions
return cacheVersions;
}
public cacheVersion(): number {
return cacheVersions[this.accessToken]
return cacheVersions[this.accessToken];
}

@@ -712,3 +740,3 @@

if (this.accessToken) {
cacheVersions[this.accessToken] = cv
cacheVersions[this.accessToken] = cv;
}

@@ -719,3 +747,3 @@ }

if (this.accessToken) {
cacheVersions[this.accessToken] = 0
cacheVersions[this.accessToken] = 0;
}

@@ -729,18 +757,20 @@ }

get(key: string) {
return Promise.resolve(memory[key])
return Promise.resolve(memory[key]);
},
getAll() {
return Promise.resolve(memory as IMemoryType)
return Promise.resolve(memory as IMemoryType);
},
set(key: string, content: ISbResult) {
memory[key] = content
return Promise.resolve(undefined)
memory[key] = content;
return Promise.resolve(undefined);
},
flush() {
memory = {}
return Promise.resolve(undefined)
memory = {};
return Promise.resolve(undefined);
},
};
case 'custom':
if (this.cache.custom) {
return this.cache.custom;
}
case 'custom':
if (this.cache.custom) return this.cache.custom
// eslint-disable-next-line no-fallthrough

@@ -750,14 +780,14 @@ default:

get() {
return Promise.resolve()
return Promise.resolve();
},
getAll() {
return Promise.resolve(undefined)
return Promise.resolve(undefined);
},
set() {
return Promise.resolve(undefined)
return Promise.resolve(undefined);
},
flush() {
return Promise.resolve(undefined)
return Promise.resolve(undefined);
},
}
};
}

@@ -767,8 +797,8 @@ }

public async flushCache(): Promise<this> {
await this.cacheProvider().flush()
this.clearCacheVersion()
return this
await this.cacheProvider().flush();
this.clearCacheVersion();
return this;
}
}
export default Storyblok
export default Storyblok;

@@ -1,67 +0,68 @@

import { ResponseFn } from './sbFetch'
import type { ResponseFn } from './sbFetch';
import type Method from './constants';
export interface ISbStoriesParams
extends Partial<ISbStoryData>,
ISbMultipleStoriesData,
ISbAssetsParams {
resolve_level?: number
_stopResolving?: boolean
by_slugs?: string
by_uuids?: string
by_uuids_ordered?: string
component?: string
content_type?: string
cv?: number
datasource?: string
dimension?: string
excluding_fields?: string
excluding_ids?: string
excluding_slugs?: string
fallback_lang?: string
filename?: string
filter_query?: any
first_published_at_gt?: string
first_published_at_lt?: string
from_release?: string
is_startpage?: boolean
language?: string
level?: number
page?: number
per_page?: number
published_at_gt?: string
published_at_lt?: string
resolve_assets?: number
resolve_links?: 'link' | 'url' | 'story' | '0' | '1' | 'link'
resolve_links_level?: 1 | 2
resolve_relations?: string | string[]
search_term?: string
size?: string
sort_by?: string
starts_with?: string
token?: string
version?: 'draft' | 'published'
with_tag?: string
ISbMultipleStoriesData,
ISbAssetsParams {
resolve_level?: number;
_stopResolving?: boolean;
by_slugs?: string;
by_uuids?: string;
by_uuids_ordered?: string;
component?: string;
content_type?: string;
cv?: number;
datasource?: string;
dimension?: string;
excluding_fields?: string;
excluding_ids?: string;
excluding_slugs?: string;
fallback_lang?: string;
filename?: string;
filter_query?: any;
first_published_at_gt?: string;
first_published_at_lt?: string;
from_release?: string;
is_startpage?: boolean;
language?: string;
level?: number;
page?: number;
per_page?: number;
published_at_gt?: string;
published_at_lt?: string;
resolve_assets?: number;
resolve_links?: 'link' | 'url' | 'story' | '0' | '1' | 'link';
resolve_links_level?: 1 | 2;
resolve_relations?: string | string[];
search_term?: string;
size?: string;
sort_by?: string;
starts_with?: string;
token?: string;
version?: 'draft' | 'published';
with_tag?: string;
}
export interface ISbStoryParams {
resolve_level?: number
token?: string
find_by?: 'uuid'
version?: 'draft' | 'published'
resolve_links?: 'link' | 'url' | 'story' | '0' | '1'
resolve_links_level?: 1 | 2
resolve_relations?: string | string[]
cv?: number
from_release?: string
language?: string
fallback_lang?: string
resolve_level?: number;
token?: string;
find_by?: 'uuid';
version?: 'draft' | 'published';
resolve_links?: 'link' | 'url' | 'story' | '0' | '1';
resolve_links_level?: 1 | 2;
resolve_relations?: string | string[];
cv?: number;
from_release?: string;
language?: string;
fallback_lang?: string;
}
type Dimension = {
id: number
name: string
entry_value: string
datasource_id: number
created_at: string
updated_at: string
interface Dimension {
id: number;
name: string;
entry_value: string;
datasource_id: number;
created_at: string;
updated_at: string;
}

@@ -75,9 +76,9 @@

export interface ISbDimensions {
dimensions: Dimension[]
dimensions: Dimension[];
}
export interface ISbComponentType<T extends string> {
_uid?: string
component?: T
_editable?: string
_uid?: string;
component?: T;
_editable?: string;
}

@@ -88,85 +89,85 @@

> extends ISbMultipleStoriesData {
alternates: ISbAlternateObject[]
breadcrumbs?: ISbLinkURLObject[]
content: Content
created_at: string
default_full_slug?: string
default_root?: string
disble_fe_editor?: boolean
first_published_at?: string
full_slug: string
group_id: string
id: number
imported_at?: string
is_folder?: boolean
is_startpage?: boolean
lang: string
alternates: ISbAlternateObject[];
breadcrumbs?: ISbLinkURLObject[];
content: Content;
created_at: string;
default_full_slug?: string;
default_root?: string;
disble_fe_editor?: boolean;
first_published_at?: string;
full_slug: string;
group_id: string;
id: number;
imported_at?: string;
is_folder?: boolean;
is_startpage?: boolean;
lang: string;
last_author?: {
id: number
userid: string
}
meta_data: any
name: string
parent?: ISbStoryData
parent_id: number
path?: string
pinned?: '1' | boolean
position: number
published?: boolean
published_at: string | null
release_id?: number
slug: string
sort_by_date: string | null
tag_list: string[]
id: number;
userid: string;
};
meta_data: any;
name: string;
parent?: ISbStoryData;
parent_id: number;
path?: string;
pinned?: '1' | boolean;
position: number;
published?: boolean;
published_at: string | null;
release_id?: number;
slug: string;
sort_by_date: string | null;
tag_list: string[];
translated_slugs?: {
path: string
name: string | null
lang: ISbStoryData['lang']
}[]
unpublished_changes?: boolean
updated_at?: string
uuid: string
path: string;
name: string | null;
lang: ISbStoryData['lang'];
}[];
unpublished_changes?: boolean;
updated_at?: string;
uuid: string;
}
export interface ISbMultipleStoriesData {
by_ids?: string
by_uuids?: string
contain_component?: string
excluding_ids?: string
filter_query?: any
folder_only?: boolean
full_slug?: string
in_release?: string
in_trash?: boolean
is_published?: boolean
in_workflow_stages?: string
page?: number
pinned?: '1' | boolean
search?: string
sort_by?: string
starts_with?: string
story_only?: boolean
text_search?: string
with_parent?: number
with_slug?: string
with_tag?: string
by_ids?: string;
by_uuids?: string;
contain_component?: string;
excluding_ids?: string;
filter_query?: any;
folder_only?: boolean;
full_slug?: string;
in_release?: string;
in_trash?: boolean;
is_published?: boolean;
in_workflow_stages?: string;
page?: number;
pinned?: '1' | boolean;
search?: string;
sort_by?: string;
starts_with?: string;
story_only?: boolean;
text_search?: string;
with_parent?: number;
with_slug?: string;
with_tag?: string;
}
export interface ISbAlternateObject {
id: number
name: string
slug: string
published: boolean
full_slug: string
is_folder: boolean
parent_id: number
id: number;
name: string;
slug: string;
published: boolean;
full_slug: string;
is_folder: boolean;
parent_id: number;
}
export interface ISbLinkURLObject {
id: number
name: string
slug: string
full_slug: string
url: string
uuid: string
id: number;
name: string;
slug: string;
full_slug: string;
url: string;
uuid: string;
}

@@ -178,10 +179,10 @@

data: {
cv: number
links: (ISbStoryData | ISbLinkURLObject)[]
rels: ISbStoryData[]
stories: ISbStoryData<Content>[]
}
perPage: number
total: number
headers: any
cv: number;
links: (ISbStoryData | ISbLinkURLObject)[];
rels: ISbStoryData[];
stories: ISbStoryData<Content>[];
};
perPage: number;
total: number;
headers: any;
}

@@ -193,83 +194,84 @@

data: {
cv: number
links: (ISbStoryData | ISbLinkURLObject)[]
rels: ISbStoryData[]
story: ISbStoryData<Content>
}
headers: any
cv: number;
links: (ISbStoryData | ISbLinkURLObject)[];
rels: ISbStoryData[];
story: ISbStoryData<Content>;
};
headers: any;
}
export interface IMemoryType extends ISbResult {
[key: string]: any
[key: string]: any;
}
export interface ICacheProvider {
get: (key: string) => Promise<IMemoryType | void>
set: (key: string, content: ISbResult) => Promise<void>
getAll: () => Promise<IMemoryType | void>
flush: () => Promise<void>
get: (key: string) => Promise<IMemoryType | void>;
set: (key: string, content: ISbResult) => Promise<void>;
getAll: () => Promise<IMemoryType | void>;
flush: () => Promise<void>;
}
export interface ISbCache {
type?: 'none' | 'memory' | 'custom'
clear?: 'auto' | 'manual'
custom?: ICacheProvider
type?: 'none' | 'memory' | 'custom';
clear?: 'auto' | 'manual';
custom?: ICacheProvider;
}
export interface ISbConfig {
accessToken?: string
oauthToken?: string
resolveNestedRelations?: boolean
cache?: ISbCache
responseInterceptor?: ResponseFn
fetch?: typeof fetch
timeout?: number
headers?: any
region?: string
maxRetries?: number
https?: boolean
rateLimit?: number
componentResolver?: (component: string, data: any) => void
richTextSchema?: ISbSchema
endpoint?: string
accessToken?: string;
oauthToken?: string;
resolveNestedRelations?: boolean;
cache?: ISbCache;
responseInterceptor?: ResponseFn;
fetch?: typeof fetch;
timeout?: number;
headers?: any;
region?: string;
maxRetries?: number;
https?: boolean;
rateLimit?: number;
componentResolver?: (component: string, data: any) => void;
richTextSchema?: ISbSchema;
endpoint?: string;
}
export interface ISbResult {
data: any
perPage: number
total: number
headers: Headers
data: any;
perPage: number;
total: number;
headers: Headers;
}
export interface ISbResponse {
data: any
status: number
statusText: string
data: any;
status: number;
statusText: string;
headers: any;
}
export interface ISbError {
message?: string
status?: number
response?: ISbResponse
message?: string;
status?: number;
response?: ISbResponse;
}
export interface ISbNode extends Element {
content: object[]
content: object[];
attrs: {
anchor?: string
body?: Array<ISbComponentType<any>>
href?: string
level?: number
linktype?: string
custom?: LinkCustomAttributes
[key: string]: any | undefined
}
anchor?: string;
body?: Array<ISbComponentType<any>>;
href?: string;
level?: number;
linktype?: string;
custom?: LinkCustomAttributes;
[key: string]: any | undefined;
};
}
export type NodeSchema = {
(node: ISbNode): object
export interface NodeSchema {
(node: ISbNode): object;
}
export type MarkSchema = {
(node: ISbNode): object
export interface MarkSchema {
(node: ISbNode): object;
}

@@ -281,59 +283,59 @@

story: {
name: string
slug: string
content?: Content
default_root?: boolean
is_folder?: boolean
parent_id?: string
disble_fe_editor?: boolean
path?: string
is_startpage?: boolean
position?: number
first_published_at?: string
name: string;
slug: string;
content?: Content;
default_root?: boolean;
is_folder?: boolean;
parent_id?: string;
disble_fe_editor?: boolean;
path?: string;
is_startpage?: boolean;
position?: number;
first_published_at?: string;
translated_slugs_attributes?: {
path: string
name: string | null
lang: ISbContentMangmntAPI['lang']
}[]
}
force_update?: '1' | unknown
release_id?: number
publish?: '1' | unknown
lang?: string
path: string;
name: string | null;
lang: ISbContentMangmntAPI['lang'];
}[];
};
force_update?: '1' | unknown;
release_id?: number;
publish?: '1' | unknown;
lang?: string;
}
export interface ISbManagmentApiResult {
data: any
headers: any
data: any;
headers: any;
}
export interface ISbSchema {
nodes: any
marks: any
nodes: any;
marks: any;
}
export interface ISbRichtext {
content?: ISbRichtext[]
marks?: ISbRichtext[]
attrs?: any
text?: string
type: string
content?: ISbRichtext[];
marks?: ISbRichtext[];
attrs?: any;
text?: string;
type: string;
}
export interface LinkCustomAttributes {
rel?: string
title?: string
[key: string]: any
rel?: string;
title?: string;
[key: string]: any;
}
export interface ISbLink {
id?: number
slug?: string
name?: string
is_folder?: boolean
parent_id?: number
published?: boolean
position?: number
uuid?: string
is_startpage?: boolean
id?: number;
slug?: string;
name?: string;
is_folder?: boolean;
parent_id?: number;
published?: boolean;
position?: number;
uuid?: string;
is_startpage?: boolean;
}

@@ -343,16 +345,41 @@

links?: {
[key: string]: ISbLink
}
[key: string]: ISbLink;
};
}
export type ThrottleFn = {
(...args: any): any
export interface Queue<T> {
resolve: (value: unknown) => void;
reject: (reason?: unknown) => void;
args: T;
}
export type AsyncFn = (...args: any) => [] | Promise<ISbResult>
export interface ISbResponseData {
link_uuids: string[];
links: string[];
rel_uuids: string[];
rels: any;
story: ISbStoryData;
stories: Array<ISbStoryData>;
}
export type ArrayFn = (...args: any) => void
export interface ISbThrottle<
T extends (...args: Parameters<T>) => ReturnType<T>,
> {
abort?: () => void;
(...args: Parameters<T>): Promise<unknown>;
}
export type HtmlEscapes = {
[key: string]: string
export type ISbThrottledRequest = (
type: Method,
url: string,
params: ISbStoriesParams,
fetchOptions?: ISbCustomFetch
) => Promise<unknown>;
export type AsyncFn = (...args: any) => [] | Promise<ISbResult>;
export type ArrayFn = (...args: any) => void;
export interface HtmlEscapes {
[key: string]: string;
}

@@ -363,7 +390,7 @@

export interface ISbAssetsParams {
in_folder?: string
is_private?: boolean
by_alt?: string
by_copyright?: string
by_title?: string
in_folder?: string;
is_private?: boolean;
by_alt?: string;
by_copyright?: string;
by_title?: string;
}

@@ -1,6 +0,6 @@

import defaultHtmlSerializer from './schema'
import { ISbSchema, ISbRichtext } from './interfaces'
import defaultHtmlSerializer from './schema';
import type { ISbRichtext, ISbSchema } from './interfaces';
type HtmlEscapes = {
[key: string]: string
interface HtmlEscapes {
[key: string]: string;
}

@@ -11,21 +11,21 @@

| {
class?: string
filters?: {
blur?: number
brightness?: number
fill?: string
format?: 'webp' | 'jpeg' | 'png'
grayscale?: boolean
quality?: number
rotate?: 90 | 180 | 270
}
height?: number
loading?: 'lazy' | 'eager'
sizes?: string[]
srcset?: (number | [number, number])[]
width?: number
}
class?: string;
filters?: {
blur?: number;
brightness?: number;
fill?: string;
format?: 'webp' | 'jpeg' | 'png';
grayscale?: boolean;
quality?: number;
rotate?: 90 | 180 | 270;
};
height?: number;
loading?: 'lazy' | 'eager';
sizes?: string[];
srcset?: (number | [number, number])[];
width?: number;
};
type RenderOptions = {
optimizeImages?: OptimizeImagesOptions
interface RenderOptions {
optimizeImages?: OptimizeImagesOptions;
}

@@ -39,46 +39,46 @@

'"': '&quot;',
"'": '&#39;',
} as HtmlEscapes
'\'': '&#39;',
} as HtmlEscapes;
const reUnescapedHtml = /[&<>"']/g
const reHasUnescapedHtml = RegExp(reUnescapedHtml.source)
const reUnescapedHtml = /[&<>"']/g;
const reHasUnescapedHtml = new RegExp(reUnescapedHtml.source);
return string && reHasUnescapedHtml.test(string)
? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr])
: string
}
? string.replace(reUnescapedHtml, chr => htmlEscapes[chr])
: string;
};
interface ISbTag extends Element {
[key: string]: any
[key: string]: any;
}
interface ISbNode {
[key: string]: ISbSchema | ((arg: ISbRichtext) => any)
[key: string]: ISbSchema | ((arg: ISbRichtext) => any);
}
interface ISbFunction<T extends any[], R> {
(...args: T): R
(...args: T): R;
}
let hasWarnedAboutDeprecation = false;
let hasWarnedAboutDeprecation = false;
class RichTextResolver {
private marks: ISbNode
private nodes: ISbNode
private marks: ISbNode;
private nodes: ISbNode;
public constructor(schema?: ISbSchema) {
if (!schema) {
schema = defaultHtmlSerializer as ISbSchema
schema = defaultHtmlSerializer as ISbSchema;
}
this.marks = schema.marks || []
this.nodes = schema.nodes || []
this.marks = schema.marks || [];
this.nodes = schema.nodes || [];
}
public addNode(key: string, schema: ISbSchema | ISbFunction<any, any>) {
this.nodes[key] = schema
this.nodes[key] = schema;
}
public addMark(key: string, schema: ISbSchema) {
this.marks[key] = schema
this.marks[key] = schema;
}

@@ -89,22 +89,22 @@

options: RenderOptions = { optimizeImages: false },
deprecationWarning = true
deprecationWarning = true,
) {
if(!hasWarnedAboutDeprecation && deprecationWarning) {
if (!hasWarnedAboutDeprecation && deprecationWarning) {
console.warn(
"Warning ⚠️: The RichTextResolver class is deprecated and will be removed in the next major release. Please use the `@storyblok/richtext` package instead. https://github.com/storyblok/richtext/"
'Warning ⚠️: The RichTextResolver class is deprecated and will be removed in the next major release. Please use the `@storyblok/richtext` package instead. https://github.com/storyblok/richtext/',
);
hasWarnedAboutDeprecation = true
hasWarnedAboutDeprecation = true;
}
if (data && data.content && Array.isArray(data.content)) {
let html = ''
let html = '';
data.content.forEach((node) => {
html += this.renderNode(node)
})
html += this.renderNode(node);
});
if (options.optimizeImages) {
return this.optimizeImages(html, options.optimizeImages)
return this.optimizeImages(html, options.optimizeImages);
}
return html
return html;
}

@@ -114,52 +114,52 @@

`The render method must receive an Object with a "content" field.
The "content" field must be an array of nodes as the type ISbRichtext.
ISbRichtext:
content?: ISbRichtext[]
marks?: ISbRichtext[]
attrs?: any
text?: string
type: string
Example:
{
content: [
{
content: [
{
text: 'Hello World',
type: 'text'
}
],
type: 'paragraph'
}
],
type: 'doc'
}`
)
return ''
The "content" field must be an array of nodes as the type ISbRichtext.
ISbRichtext:
content?: ISbRichtext[]
marks?: ISbRichtext[]
attrs?: any
text?: string
type: string
Example:
{
content: [
{
content: [
{
text: 'Hello World',
type: 'text'
}
],
type: 'paragraph'
}
],
type: 'doc'
}`,
);
return '';
}
private optimizeImages(html: string, options: OptimizeImagesOptions): string {
let w = 0
let h = 0
let imageAttributes = ''
let filters = ''
let w = 0;
let h = 0;
let imageAttributes = '';
let filters = '';
if (typeof options !== 'boolean') {
if (typeof options.width === 'number' && options.width > 0) {
imageAttributes += `width="${options.width}" `
w = options.width
imageAttributes += `width="${options.width}" `;
w = options.width;
}
if (typeof options.height === 'number' && options.height > 0) {
imageAttributes += `height="${options.height}" `
h = options.height
imageAttributes += `height="${options.height}" `;
h = options.height;
}
if (options.loading === 'lazy' || options.loading === 'eager') {
imageAttributes += `loading="${options.loading}" `
imageAttributes += `loading="${options.loading}" `;
}
if (typeof options.class === 'string' && options.class.length > 0) {
imageAttributes += `class="${options.class}" `
imageAttributes += `class="${options.class}" `;
}

@@ -169,55 +169,57 @@

if (
typeof options.filters.blur === 'number' &&
options.filters.blur >= 0 &&
options.filters.blur <= 100
typeof options.filters.blur === 'number'
&& options.filters.blur >= 0
&& options.filters.blur <= 100
) {
filters += `:blur(${options.filters.blur})`
filters += `:blur(${options.filters.blur})`;
}
if (
typeof options.filters.brightness === 'number' &&
options.filters.brightness >= -100 &&
options.filters.brightness <= 100
typeof options.filters.brightness === 'number'
&& options.filters.brightness >= -100
&& options.filters.brightness <= 100
) {
filters += `:brightness(${options.filters.brightness})`
filters += `:brightness(${options.filters.brightness})`;
}
if (
options.filters.fill &&
(options.filters.fill.match(/[0-9A-Fa-f]{6}/g) ||
options.filters.fill === 'transparent')
options.filters.fill
&& (options.filters.fill.match(/[0-9A-F]{6}/gi)
|| options.filters.fill === 'transparent')
) {
filters += `:fill(${options.filters.fill})`
filters += `:fill(${options.filters.fill})`;
}
if (
options.filters.format &&
['webp', 'png', 'jpeg'].includes(options.filters.format)
options.filters.format
&& ['webp', 'png', 'jpeg'].includes(options.filters.format)
) {
filters += `:format(${options.filters.format})`
filters += `:format(${options.filters.format})`;
}
if (
typeof options.filters.grayscale === 'boolean' &&
options.filters.grayscale
typeof options.filters.grayscale === 'boolean'
&& options.filters.grayscale
) {
filters += ':grayscale()'
filters += ':grayscale()';
}
if (
typeof options.filters.quality === 'number' &&
options.filters.quality >= 0 &&
options.filters.quality <= 100
typeof options.filters.quality === 'number'
&& options.filters.quality >= 0
&& options.filters.quality <= 100
) {
filters += `:quality(${options.filters.quality})`
filters += `:quality(${options.filters.quality})`;
}
if (
options.filters.rotate &&
[90, 180, 270].includes(options.filters.rotate)
options.filters.rotate
&& [90, 180, 270].includes(options.filters.rotate)
) {
filters += `:rotate(${options.filters.rotate})`
filters += `:rotate(${options.filters.rotate})`;
}
if (filters.length > 0) filters = '/filters' + filters
if (filters.length > 0) {
filters = `/filters${filters}`;
}
}

@@ -227,12 +229,12 @@ }

if (imageAttributes.length > 0) {
html = html.replace(/<img/g, `<img ${imageAttributes.trim()}`)
html = html.replace(/<img/g, `<img ${imageAttributes.trim()}`);
}
const parameters =
w > 0 || h > 0 || filters.length > 0 ? `${w}x${h}${filters}` : ''
const parameters
= w > 0 || h > 0 || filters.length > 0 ? `${w}x${h}${filters}` : '';
html = html.replace(
/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|tiff|bmp)/g,
`a.storyblok.com/f/$1/$2.$3/m/${parameters}`
)
/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g,
`a.storyblok.com/f/$1/$2.$3/m/${parameters}`,
);

@@ -242,4 +244,4 @@ if (typeof options !== 'boolean' && (options.sizes || options.srcset)) {

const url = value.match(
/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|tiff|bmp)/g
)
/a.storyblok.com\/f\/(\d+)\/([^.]+)\.(gif|jpg|jpeg|png|tif|bmp)/g,
);

@@ -251,52 +253,58 @@ if (url && url.length > 0) {

if (typeof value === 'number') {
return `//${url}/m/${value}x0${filters} ${value}w`
return `//${url}/m/${value}x0${filters} ${value}w`;
}
if (typeof value === 'object' && value.length === 2) {
let w = 0
let h = 0
if (typeof value[0] === 'number') w = value[0]
if (typeof value[1] === 'number') h = value[1]
return `//${url}/m/${w}x${h}${filters} ${w}w`
let w = 0;
let h = 0;
if (typeof value[0] === 'number') {
w = value[0];
}
if (typeof value[1] === 'number') {
h = value[1];
}
return `//${url}/m/${w}x${h}${filters} ${w}w`;
}
return '';
})
.join(', '),
sizes: options.sizes?.map((size) => size).join(', '),
}
sizes: options.sizes?.map(size => size).join(', '),
};
let renderImageAttributes = ''
let renderImageAttributes = '';
if (imageAttributes.srcset) {
renderImageAttributes += `srcset="${imageAttributes.srcset}" `
renderImageAttributes += `srcset="${imageAttributes.srcset}" `;
}
if (imageAttributes.sizes) {
renderImageAttributes += `sizes="${imageAttributes.sizes}" `
renderImageAttributes += `sizes="${imageAttributes.sizes}" `;
}
return value.replace(/<img/g, `<img ${renderImageAttributes.trim()}`)
return value.replace(/<img/g, `<img ${renderImageAttributes.trim()}`);
}
return value
})
return value;
});
}
return html
return html;
}
private renderNode(item: ISbRichtext) {
const html = []
const html = [];
if (item.marks) {
item.marks.forEach((m) => {
const mark = this.getMatchingMark(m)
const mark = this.getMatchingMark(m);
if (mark && mark.tag !== '') {
html.push(this.renderOpeningTag(mark.tag))
html.push(this.renderOpeningTag(mark.tag));
}
})
});
}
const node = this.getMatchingNode(item)
const node = this.getMatchingNode(item);
if (node && node.tag) {
html.push(this.renderOpeningTag(node.tag))
html.push(this.renderOpeningTag(node.tag));
}

@@ -306,16 +314,20 @@

item.content.forEach((content) => {
html.push(this.renderNode(content))
})
} else if (item.text) {
html.push(escapeHTML(item.text))
} else if (node && node.singleTag) {
html.push(this.renderTag(node.singleTag, ' /'))
} else if (node && node.html) {
html.push(node.html)
} else if (item.type === 'emoji') {
html.push(this.renderEmoji(item))
html.push(this.renderNode(content));
});
}
else if (item.text) {
html.push(escapeHTML(item.text));
}
else if (node && node.singleTag) {
html.push(this.renderTag(node.singleTag, ' /'));
}
else if (node && node.html) {
html.push(node.html);
}
else if (item.type === 'emoji') {
html.push(this.renderEmoji(item));
}
if (node && node.tag) {
html.push(this.renderClosingTag(node.tag))
html.push(this.renderClosingTag(node.tag));
}

@@ -328,11 +340,11 @@

.forEach((m) => {
const mark = this.getMatchingMark(m)
const mark = this.getMatchingMark(m);
if (mark && mark.tag !== '') {
html.push(this.renderClosingTag(mark.tag))
html.push(this.renderClosingTag(mark.tag));
}
})
});
}
return html.join('')
return html.join('');
}

@@ -342,3 +354,3 @@

if (tags.constructor === String) {
return `<${tags}${ending}>`
return `<${tags}${ending}>`;
}

@@ -348,11 +360,12 @@

if (tag.constructor === String) {
return `<${tag}${ending}>`
} else {
let h = `<${tag.tag}`
return `<${tag}${ending}>`;
}
else {
let h = `<${tag.tag}`;
if (tag.attrs) {
for (const key in tag.attrs) {
if (Object.prototype.hasOwnProperty.call(tag.attrs, key)) {
const value = tag.attrs[key]
const value = tag.attrs[key];
if (value !== null) {
h += ` ${key}="${value}"`
h += ` ${key}="${value}"`;
}

@@ -363,10 +376,10 @@ }

return `${h}${ending}>`
return `${h}${ending}>`;
}
})
return all.join('')
});
return all.join('');
}
private renderOpeningTag(tags: ISbTag[]) {
return this.renderTag(tags, '')
return this.renderTag(tags, '');
}

@@ -376,3 +389,3 @@

if (tags.constructor === String) {
return `</${tags}>`
return `</${tags}>`;
}

@@ -385,15 +398,16 @@

if (tag.constructor === String) {
return `</${tag}>`
} else {
return `</${tag.tag}>`
return `</${tag}>`;
}
})
else {
return `</${tag.tag}>`;
}
});
return all.join('')
return all.join('');
}
private getMatchingNode(item: ISbRichtext) {
const node = this.nodes[item.type]
const node = this.nodes[item.type];
if (typeof node === 'function') {
return node(item)
return node(item);
}

@@ -403,5 +417,5 @@ }

private getMatchingMark(item: ISbRichtext) {
const node = this.marks[item.type]
const node = this.marks[item.type];
if (typeof node === 'function') {
return node(item)
return node(item);
}

@@ -412,3 +426,3 @@ }

if (item.attrs.emoji) {
return item.attrs.emoji
return item.attrs.emoji;
}

@@ -426,8 +440,8 @@

},
] as unknown as ISbTag[]
] as unknown as ISbTag[];
return this.renderTag(emojiImageContainer, ' /')
return this.renderTag(emojiImageContainer, ' /');
}
}
export default RichTextResolver
export default RichTextResolver;

@@ -1,17 +0,18 @@

import { describe, it, expect, vi, afterEach } from 'vitest'
import SbFetch, { ISbFetch } from './sbFetch'
import { headersToObject } from '../tests/utils'
import { afterEach, describe, expect, it, vi } from 'vitest';
import type { ISbFetch } from './sbFetch';
import SbFetch from './sbFetch';
import { headersToObject } from '../tests/utils';
describe('SbFetch', () => {
let sbFetch: SbFetch
const mockFetch = vi.fn()
describe('sbFetch', () => {
let sbFetch: SbFetch;
const mockFetch = vi.fn();
afterEach(() => {
vi.restoreAllMocks()
})
vi.restoreAllMocks();
});
it('should initialize', () => {
sbFetch = new SbFetch({} as ISbFetch)
expect(sbFetch).toBeInstanceOf(SbFetch)
})
sbFetch = new SbFetch({} as ISbFetch);
expect(sbFetch).toBeInstanceOf(SbFetch);
});

@@ -23,28 +24,28 @@ describe('get', () => {

fetch: mockFetch,
} as ISbFetch)
} as ISbFetch);
const response = new Response(JSON.stringify({ data: 'test' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
mockFetch.mockResolvedValue(response)
});
mockFetch.mockResolvedValue(response);
await sbFetch.get('test', {
is_startpage: false,
search_term: 'test',
})
});
expect(mockFetch).toHaveBeenCalledWith(
'https://api.storyblok.com/v2/test?is_startpage=false&search_term=test',
expect.anything()
)
})
})
expect.anything(),
);
});
});
describe('post', () => {
it('should handle POST requests correctly', async () => {
const testPayload = { title: 'New Story' }
const testPayload = { title: 'New Story' };
const response = new Response(JSON.stringify({ data: 'test' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
mockFetch.mockResolvedValue(response)
await sbFetch.post('stories', testPayload)
});
mockFetch.mockResolvedValue(response);
await sbFetch.post('stories', testPayload);
expect(mockFetch).toHaveBeenCalledWith(

@@ -57,5 +58,5 @@ 'https://api.storyblok.com/v2/stories',

signal: expect.any(AbortSignal),
}
)
})
},
);
});

@@ -69,28 +70,28 @@ it('should set specific headers for POST requests', async () => {

fetch: mockFetch,
} as ISbFetch)
const testPayload = { title: 'New Story' }
} as ISbFetch);
const testPayload = { title: 'New Story' };
const response = new Response(JSON.stringify({ data: 'test' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
mockFetch.mockResolvedValue(response)
});
mockFetch.mockResolvedValue(response);
await sbFetch.post('stories', testPayload)
await sbFetch.post('stories', testPayload);
// Get the last call to fetch and extract the headers
const lastCall = mockFetch.mock.calls[mockFetch.mock.calls.length - 1]
const actualHeaders = headersToObject(lastCall[1].headers)
expect(actualHeaders['content-type']).toBe('application/json')
})
})
const lastCall = mockFetch.mock.calls[mockFetch.mock.calls.length - 1];
const actualHeaders = headersToObject(lastCall[1].headers);
expect(actualHeaders['content-type']).toBe('application/json');
});
});
describe('put', () => {
it('should handle PUT requests correctly', async () => {
const testPayload = { title: 'Updated Story' }
const testPayload = { title: 'Updated Story' };
const response = new Response(JSON.stringify({ data: 'test' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
mockFetch.mockResolvedValue(response)
await sbFetch.put('stories/1', testPayload)
});
mockFetch.mockResolvedValue(response);
await sbFetch.put('stories/1', testPayload);
expect(mockFetch).toHaveBeenCalledWith(

@@ -103,6 +104,6 @@ 'https://api.storyblok.com/v2/stories/1',

signal: expect.any(AbortSignal),
}
)
})
})
},
);
});
});

@@ -113,5 +114,5 @@ describe('delete', () => {

status: 204, // Typically, DELETE operations might not return content
})
mockFetch.mockResolvedValue(response)
await sbFetch.delete('stories/1', {})
});
mockFetch.mockResolvedValue(response);
await sbFetch.delete('stories/1', {});
expect(mockFetch).toHaveBeenCalledWith(

@@ -124,9 +125,9 @@ 'https://api.storyblok.com/v2/stories/1',

signal: expect.any(AbortSignal),
}
)
})
})
},
);
});
});
it('should handle network errors gracefully', async () => {
const mockFetch = vi.fn().mockRejectedValue(new Error('Network Failure'))
const mockFetch = vi.fn().mockRejectedValue(new Error('Network Failure'));
const sbFetch = new SbFetch({

@@ -136,6 +137,6 @@ baseURL: 'https://api.example.com',

fetch: mockFetch,
})
});
// Assuming your implementation wraps the error message inside an object under `message`.
const result = await sbFetch.get('/test', {})
const result = await sbFetch.get('/test', {});

@@ -145,7 +146,7 @@ // Check if the error object format matches your implementation.

message: expect.any(Error), // Checks if `message` is an instance of Error
})
});
// If you want to be more specific and check the message of the error:
expect(result.message.message).toEqual('Network Failure') // This path needs to match the structure you actually use.
})
})
expect(result.message.message).toEqual('Network Failure'); // This path needs to match the structure you actually use.
});
});

@@ -1,45 +0,45 @@

import { SbHelpers } from './sbHelpers'
import { SbHelpers } from './sbHelpers';
import {
import type {
ISbCustomFetch,
ISbError,
ISbResponse,
ISbError,
ISbStoriesParams,
ISbCustomFetch,
} from './interfaces'
import Method from './constants'
} from './interfaces';
import type Method from './constants';
export type ResponseFn = {
(arg?: ISbResponse | any): any
export interface ResponseFn {
(arg?: ISbResponse | any): any;
}
export interface ISbFetch {
baseURL: string
timeout?: number
headers: Headers
responseInterceptor?: ResponseFn
fetch?: typeof fetch
baseURL: string;
timeout?: number;
headers: Headers;
responseInterceptor?: ResponseFn;
fetch?: typeof fetch;
}
class SbFetch {
private baseURL: string
private timeout?: number
private headers: Headers
private responseInterceptor?: ResponseFn
private fetch: typeof fetch
private ejectInterceptor?: boolean
private url: string
private parameters: ISbStoriesParams
private fetchOptions: ISbCustomFetch
private baseURL: string;
private timeout?: number;
private headers: Headers;
private responseInterceptor?: ResponseFn;
private fetch: typeof fetch;
private ejectInterceptor?: boolean;
private url: string;
private parameters: ISbStoriesParams;
private fetchOptions: ISbCustomFetch;
public constructor($c: ISbFetch) {
this.baseURL = $c.baseURL
this.headers = $c.headers || new Headers()
this.timeout = $c?.timeout ? $c.timeout * 1000 : 0
this.responseInterceptor = $c.responseInterceptor
this.baseURL = $c.baseURL;
this.headers = $c.headers || new Headers();
this.timeout = $c?.timeout ? $c.timeout * 1000 : 0;
this.responseInterceptor = $c.responseInterceptor;
this.fetch = (...args: [any]) =>
$c.fetch ? $c.fetch(...args) : fetch(...args)
this.ejectInterceptor = false
this.url = ''
this.parameters = {} as ISbStoriesParams
this.fetchOptions = {}
$c.fetch ? $c.fetch(...args) : fetch(...args);
this.ejectInterceptor = false;
this.url = '';
this.parameters = {} as ISbStoriesParams;
this.fetchOptions = {};
}

@@ -54,27 +54,27 @@

public get(url: string, params: ISbStoriesParams) {
this.url = url
this.parameters = params
return this._methodHandler('get')
this.url = url;
this.parameters = params;
return this._methodHandler('get');
}
public post(url: string, params: ISbStoriesParams) {
this.url = url
this.parameters = params
return this._methodHandler('post')
this.url = url;
this.parameters = params;
return this._methodHandler('post');
}
public put(url: string, params: ISbStoriesParams) {
this.url = url
this.parameters = params
return this._methodHandler('put')
this.url = url;
this.parameters = params;
return this._methodHandler('put');
}
public delete(url: string, params: ISbStoriesParams) {
this.url = url
this.parameters = params
return this._methodHandler('delete')
this.url = url;
this.parameters = params;
return this._methodHandler('delete');
}
private async _responseHandler(res: Response) {
const headers: string[] = []
const headers: string[] = [];
const response = {

@@ -85,46 +85,47 @@ data: {},

statusText: '',
}
};
if (res.status !== 204) {
await res.json().then(($r) => {
response.data = $r
})
response.data = $r;
});
}
for (const pair of res.headers.entries()) {
headers[pair[0] as any] = pair[1]
headers[pair[0] as any] = pair[1];
}
response.headers = { ...headers }
response.status = res.status
response.statusText = res.statusText
response.headers = { ...headers };
response.status = res.status;
response.statusText = res.statusText;
return response
return response;
}
private async _methodHandler(
method: Method
method: Method,
): Promise<ISbResponse | ISbError> {
let urlString = `${this.baseURL}${this.url}`
let urlString = `${this.baseURL}${this.url}`;
let body = null
let body = null;
if (method === 'get') {
const helper = new SbHelpers()
const helper = new SbHelpers();
urlString = `${this.baseURL}${this.url}?${helper.stringify(
this.parameters
)}`
} else {
body = JSON.stringify(this.parameters)
this.parameters,
)}`;
}
else {
body = JSON.stringify(this.parameters);
}
const url = new URL(urlString)
const url = new URL(urlString);
const controller = new AbortController()
const { signal } = controller
const controller = new AbortController();
const { signal } = controller;
let timeout
let timeout;
if (this.timeout) {
timeout = setTimeout(() => controller.abort(), this.timeout)
timeout = setTimeout(() => controller.abort(), this.timeout);
}

@@ -139,22 +140,24 @@

...this.fetchOptions,
})
});
if (this.timeout) {
clearTimeout(timeout)
clearTimeout(timeout);
}
const response = (await this._responseHandler(
fetchResponse
)) as ISbResponse
fetchResponse,
)) as ISbResponse;
if (this.responseInterceptor && !this.ejectInterceptor) {
return this._statusHandler(this.responseInterceptor(response))
} else {
return this._statusHandler(response)
return this._statusHandler(this.responseInterceptor(response));
}
} catch (err: any) {
else {
return this._statusHandler(response);
}
}
catch (err: any) {
const error: ISbError = {
message: err,
}
return error
};
return error;
}

@@ -165,17 +168,17 @@ }

if (Object.keys(fetchOptions).length > 0 && 'method' in fetchOptions) {
delete fetchOptions.method
delete fetchOptions.method;
}
this.fetchOptions = { ...fetchOptions }
this.fetchOptions = { ...fetchOptions };
}
public eject() {
this.ejectInterceptor = true
this.ejectInterceptor = true;
}
private _statusHandler(res: ISbResponse): Promise<ISbResponse | ISbError> {
const statusOk = /20[0-6]/g
const statusOk = /20[0-6]/g;
return new Promise((resolve, reject) => {
if (statusOk.test(`${res.status}`)) {
return resolve(res)
return resolve(res);
}

@@ -189,9 +192,9 @@

: res.data.error || res.data.slug,
}
};
reject(error)
})
reject(error);
});
}
}
export default SbFetch
export default SbFetch;

@@ -1,29 +0,29 @@

import { describe, it, expect, beforeEach, vi } from 'vitest'
import { SbHelpers } from './sbHelpers'
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { SbHelpers } from './sbHelpers';
describe('SbHelpers', () => {
let helpers: SbHelpers
describe('sbHelpers', () => {
let helpers: SbHelpers;
beforeEach(() => {
helpers = new SbHelpers()
})
helpers = new SbHelpers();
});
it('should create a new instance', () => {
expect(helpers).toBeDefined()
expect(helpers).toBeInstanceOf(SbHelpers)
})
expect(helpers).toBeDefined();
expect(helpers).toBeInstanceOf(SbHelpers);
});
describe('isCDNUrl', () => {
it('returns true if the URL contains /cdn/', () => {
expect(helpers.isCDNUrl('http://example.com/cdn/content')).toBe(true)
})
expect(helpers.isCDNUrl('http://example.com/cdn/content')).toBe(true);
});
it('returns false if the URL does not contain /cdn/', () => {
expect(helpers.isCDNUrl('http://example.com/content')).toBe(false)
})
})
expect(helpers.isCDNUrl('http://example.com/content')).toBe(false);
});
});
describe('getOptionsPage', () => {
it('constructs options with default pagination', () => {
const options = { uuid: 'awiwi' }
const options = { uuid: 'awiwi' };
expect(helpers.getOptionsPage(options)).toEqual({

@@ -33,4 +33,4 @@ uuid: 'awiwi',

page: 1,
})
})
});
});

@@ -42,15 +42,15 @@ it('overrides defaults when parameters are provided', () => {

page: 2,
})
})
})
});
});
});
describe('delay', () => {
it('delays execution by specified ms', async () => {
vi.useFakeTimers()
const promise = helpers.delay(1000)
vi.advanceTimersByTime(1000)
await expect(promise).resolves.toBeUndefined()
vi.useRealTimers()
})
})
vi.useFakeTimers();
const promise = helpers.delay(1000);
vi.advanceTimersByTime(1000);
await expect(promise).resolves.toBeUndefined();
vi.useRealTimers();
});
});

@@ -60,15 +60,15 @@ describe.skip('range', () => {

// TODO: This test is failing on the current implementation
expect(helpers.range(1, 5)).toEqual([1, 2, 3, 4, 5])
expect(helpers.range(5, 1)).toEqual([5, 4, 3, 2, 1])
})
})
expect(helpers.range(1, 5)).toEqual([1, 2, 3, 4, 5]);
expect(helpers.range(5, 1)).toEqual([5, 4, 3, 2, 1]);
});
});
describe('asyncMap', () => {
it('applies an async function to each element in the array', async () => {
const numbers = [1, 2, 3]
const doubleAsync = async (n: number) => n * 2
const results = await helpers.asyncMap(numbers, doubleAsync)
expect(results).toEqual([2, 4, 6])
})
})
const numbers = [1, 2, 3];
const doubleAsync = async (n: number) => n * 2;
const results = await helpers.asyncMap(numbers, doubleAsync);
expect(results).toEqual([2, 4, 6]);
});
});

@@ -80,77 +80,77 @@ describe('flatMap', () => {

{ id: 2, values: [30, 40] },
]
const flattenValues = (item: { values: number[] }) => item.values
const result = helpers.flatMap(data, flattenValues)
expect(result).toEqual([10, 20, 30, 40])
})
})
];
const flattenValues = (item: { values: number[] }) => item.values;
const result = helpers.flatMap(data, flattenValues);
expect(result).toEqual([10, 20, 30, 40]);
});
});
describe('stringify', () => {
it('stringifies simple objects', () => {
const params = { name: 'John', age: 30 }
const result = helpers.stringify(params)
expect(result).toBe('name=John&age=30')
})
const params = { name: 'John', age: 30 };
const result = helpers.stringify(params);
expect(result).toBe('name=John&age=30');
});
it('handles arrays correctly', () => {
const params = { names: ['John', 'Jane'] }
const result = helpers.stringify(params, '', true)
expect(result).toBe('=John&=Jane')
})
})
const params = { names: ['John', 'Jane'] };
const result = helpers.stringify(params, '', true);
expect(result).toBe('=John&=Jane');
});
});
describe('arrayFrom function', () => {
it('arrayFrom(undefined, (v, i) => i)) should be an empty array', () => {
expect(helpers.arrayFrom(undefined, (_, i) => i)).toEqual([])
})
expect(helpers.arrayFrom(undefined, (_, i) => i)).toEqual([]);
});
it('arrayFrom(0, (v, i) => i)) should be an empty array', () => {
expect(helpers.arrayFrom(0, (_, i) => i)).toEqual([])
})
expect(helpers.arrayFrom(0, (_, i) => i)).toEqual([]);
});
it('arrayFrom(2, () => 1) should be an array with 1 and 1', () => {
expect(helpers.arrayFrom(2, () => 1)).toEqual([1, 1])
})
expect(helpers.arrayFrom(2, () => 1)).toEqual([1, 1]);
});
it('arrayFrom(2, (v, i) => v)) should be an array with undefined values', () => {
expect(helpers.arrayFrom(2, (v) => v)).toEqual([undefined, undefined])
})
expect(helpers.arrayFrom(2, v => v)).toEqual([undefined, undefined]);
});
it('arrayFrom(2, (v, i) => i) should be an array with 0 and 1', () => {
expect(helpers.arrayFrom(2, (v, i) => i)).toEqual([0, 1])
})
})
expect(helpers.arrayFrom(2, (v, i) => i)).toEqual([0, 1]);
});
});
describe('getRegionURL', () => {
it('returns the EU API URL by default', () => {
expect(helpers.getRegionURL()).toBe('api.storyblok.com')
expect(helpers.getRegionURL('unknown')).toBe('api.storyblok.com') // test for unrecognized region code
})
expect(helpers.getRegionURL()).toBe('api.storyblok.com');
expect(helpers.getRegionURL('unknown')).toBe('api.storyblok.com'); // test for unrecognized region code
});
it('returns the US API URL when region code is "us"', () => {
expect(helpers.getRegionURL('us')).toBe('api-us.storyblok.com')
})
expect(helpers.getRegionURL('us')).toBe('api-us.storyblok.com');
});
it('returns the CN API URL when region code is "cn"', () => {
expect(helpers.getRegionURL('cn')).toBe('app.storyblokchina.cn')
})
expect(helpers.getRegionURL('cn')).toBe('app.storyblokchina.cn');
});
it('returns the AP API URL when region code is "ap"', () => {
expect(helpers.getRegionURL('ap')).toBe('api-ap.storyblok.com')
})
expect(helpers.getRegionURL('ap')).toBe('api-ap.storyblok.com');
});
it('returns the CA API URL when region code is "ca"', () => {
expect(helpers.getRegionURL('ca')).toBe('api-ca.storyblok.com')
})
})
expect(helpers.getRegionURL('ca')).toBe('api-ca.storyblok.com');
});
});
describe('escapeHTML', () => {
it('escapes HTML characters', () => {
const str = '<div>Test & "more" test</div>'
const escaped = helpers.escapeHTML(str)
const str = '<div>Test & "more" test</div>';
const escaped = helpers.escapeHTML(str);
expect(escaped).toBe(
'&lt;div&gt;Test &amp; &quot;more&quot; test&lt;/div&gt;'
)
})
})
})
'&lt;div&gt;Test &amp; &quot;more&quot; test&lt;/div&gt;',
);
});
});
});

@@ -1,14 +0,20 @@

import { ISbStoriesParams, ISbResult, AsyncFn, HtmlEscapes } from './interfaces'
import type {
AsyncFn,
HtmlEscapes,
ISbResult,
ISbStoriesParams,
} from './interfaces';
interface ISbParams extends ISbStoriesParams {
[key: string]: any
[key: string]: any;
}
type ArrayFn = (...args: any) => void
type ArrayFn = (...args: any) => void;
type FlatMapFn = (...args: any) => [] | any
type FlatMapFn = (...args: any) => [] | any;
type RangeFn = (...args: any) => []
type RangeFn = (...args: any) => [];
export class SbHelpers {
public isCDNUrl = (url = '') => url.indexOf('/cdn/') > -1
public isCDNUrl = (url = '') => url.includes('/cdn/');

@@ -18,3 +24,3 @@ public getOptionsPage = (

perPage = 25,
page = 1
page = 1,
) => {

@@ -25,27 +31,27 @@ return {

page,
}
}
};
};
public delay = (ms: number) => new Promise((res) => setTimeout(res, ms))
public delay = (ms: number) => new Promise(res => setTimeout(res, ms));
public arrayFrom = (length = 0, func: ArrayFn) => [...Array(length)].map(func)
public arrayFrom = (length = 0, func: ArrayFn) => Array.from({ length }, func);
public range = (start = 0, end = start): Array<any> => {
const length = Math.abs(end - start) || 0
const step = start < end ? 1 : -1
return this.arrayFrom(length, (_, i: number) => i * step + start)
}
const length = Math.abs(end - start) || 0;
const step = start < end ? 1 : -1;
return this.arrayFrom(length, (_, i: number) => i * step + start);
};
public asyncMap = async (arr: RangeFn[], func: AsyncFn) =>
Promise.all(arr.map(func))
Promise.all(arr.map(func));
public flatMap = (arr: ISbResult[] = [], func: FlatMapFn) =>
arr.map(func).reduce((xs, ys) => [...xs, ...ys], [])
arr.map(func).reduce((xs, ys) => [...xs, ...ys], []);
/**
* @method stringify
* @param {Object} params
* @param {String} prefix
* @param {Boolean} isArray
* @return {String} Stringified object
* @param {object} params
* @param {string} prefix
* @param {boolean} isArray
* @return {string} Stringified object
*/

@@ -55,27 +61,27 @@ public stringify(

prefix?: string,
isArray?: boolean
isArray?: boolean,
): string {
const pairs = []
const pairs = [];
for (const key in params) {
if (!Object.prototype.hasOwnProperty.call(params, key)) {
continue
continue;
}
const value = params[key]
const enkey = isArray ? '' : encodeURIComponent(key)
let pair
const value = params[key];
const enkey = isArray ? '' : encodeURIComponent(key);
let pair;
if (typeof value === 'object') {
pair = this.stringify(
value,
prefix ? prefix + encodeURIComponent('[' + enkey + ']') : enkey,
Array.isArray(value)
)
} else {
pair =
(prefix ? prefix + encodeURIComponent('[' + enkey + ']') : enkey) +
'=' +
encodeURIComponent(value)
prefix ? prefix + encodeURIComponent(`[${enkey}]`) : enkey,
Array.isArray(value),
);
}
pairs.push(pair)
else {
pair = `${
prefix ? prefix + encodeURIComponent(`[${enkey}]`) : enkey
}=${encodeURIComponent(value)}`;
}
pairs.push(pair);
}
return pairs.join('&')
return pairs.join('&');
}

@@ -85,23 +91,23 @@

* @method getRegionURL
* @param {String} regionCode region code, could be eu, us, cn, ap or ca
* @return {String} The base URL of the region
* @param {string} regionCode region code, could be eu, us, cn, ap or ca
* @return {string} The base URL of the region
*/
public getRegionURL(regionCode?: string): string {
const EU_API_URL = 'api.storyblok.com'
const US_API_URL = 'api-us.storyblok.com'
const CN_API_URL = 'app.storyblokchina.cn'
const AP_API_URL = 'api-ap.storyblok.com'
const CA_API_URL = 'api-ca.storyblok.com'
const EU_API_URL = 'api.storyblok.com';
const US_API_URL = 'api-us.storyblok.com';
const CN_API_URL = 'app.storyblokchina.cn';
const AP_API_URL = 'api-ap.storyblok.com';
const CA_API_URL = 'api-ca.storyblok.com';
switch (regionCode) {
case 'us':
return US_API_URL
return US_API_URL;
case 'cn':
return CN_API_URL
return CN_API_URL;
case 'ap':
return AP_API_URL
return AP_API_URL;
case 'ca':
return CA_API_URL
return CA_API_URL;
default:
return EU_API_URL
return EU_API_URL;
}

@@ -112,4 +118,4 @@ }

* @method escapeHTML
* @param {String} string text to be parsed
* @return {String} Text parsed
* @param {string} string text to be parsed
* @return {string} Text parsed
*/

@@ -122,12 +128,12 @@ public escapeHTML = function (string: string) {

'"': '&quot;',
"'": '&#39;',
} as HtmlEscapes
'\'': '&#39;',
} as HtmlEscapes;
const reUnescapedHtml = /[&<>"']/g
const reHasUnescapedHtml = RegExp(reUnescapedHtml.source)
const reUnescapedHtml = /[&<>"']/g;
const reHasUnescapedHtml = new RegExp(reUnescapedHtml.source);
return string && reHasUnescapedHtml.test(string)
? string.replace(reUnescapedHtml, (chr) => htmlEscapes[chr])
: string
}
? string.replace(reUnescapedHtml, chr => htmlEscapes[chr])
: string;
};
}

@@ -1,20 +0,25 @@

import { ISbNode, NodeSchema, MarkSchema, ISbComponentType } from './interfaces'
import { SbHelpers } from './sbHelpers'
import type {
ISbComponentType,
ISbNode,
MarkSchema,
NodeSchema,
} from './interfaces';
import { SbHelpers } from './sbHelpers';
const pick = function (attrs: Attrs, allowed: string[]) {
const h = {} as Attrs
const h = {} as Attrs;
for (const key in attrs) {
const value = attrs[key]
if (allowed.indexOf(key) > -1 && value !== null) {
h[key] = value
const value = attrs[key];
if (allowed.includes(key) && value !== null) {
h[key] = value;
}
}
return h
}
return h;
};
const isEmailLinkType = (type: string) => type === 'email'
const isEmailLinkType = (type: string) => type === 'email';
type Attrs = {
[key: string]: string | number | Array<ISbComponentType<any>>
interface Attrs {
[key: string]: string | number | Array<ISbComponentType<any>>;
}

@@ -26,14 +31,14 @@

singleTag: 'hr',
}
}
};
};
const blockquote: NodeSchema = () => {
return {
tag: 'blockquote',
}
}
};
};
const bullet_list: NodeSchema = () => {
return {
tag: 'ul',
}
}
};
};
const code_block: NodeSchema = (node: ISbNode) => {

@@ -48,14 +53,14 @@ return {

],
}
}
};
};
const hard_break: NodeSchema = () => {
return {
singleTag: 'br',
}
}
};
};
const heading: NodeSchema = (node: ISbNode) => {
return {
tag: `h${node.attrs.level}`,
}
}
};
};

@@ -70,26 +75,26 @@ const image: NodeSchema = (node: ISbNode) => {

],
}
}
};
};
const list_item: NodeSchema = () => {
return {
tag: 'li',
}
}
};
};
const ordered_list: NodeSchema = () => {
return {
tag: 'ol',
}
}
};
};
const paragraph: NodeSchema = () => {
return {
tag: 'p',
}
}
};
};
const emoji: NodeSchema = (node: ISbNode) => {
const attrs = {
['data-type']: 'emoji',
['data-name']: node.attrs.name,
emoji: node.attrs.emoji,
}
'data-type': 'emoji',
'data-name': node.attrs.name,
'emoji': node.attrs.emoji,
};

@@ -100,7 +105,7 @@ return {

tag: 'span',
attrs: attrs,
attrs,
},
],
}
}
};
};

@@ -111,29 +116,29 @@ // marks

tag: 'b',
}
}
};
};
const strike: MarkSchema = () => {
return {
tag: 's',
}
}
};
};
const underline: MarkSchema = () => {
return {
tag: 'u',
}
}
};
};
const strong: MarkSchema = () => {
return {
tag: 'strong',
}
}
};
};
const code: MarkSchema = () => {
return {
tag: 'code',
}
}
};
};
const italic: MarkSchema = () => {
return {
tag: 'i',
}
}
};
};
const link: MarkSchema = (node: ISbNode) => {

@@ -143,20 +148,20 @@ if (!node.attrs) {

tag: '',
}
};
}
const escapeHTML = new SbHelpers().escapeHTML
const attrs = { ...node.attrs }
const { linktype = 'url' } = node.attrs
delete attrs.linktype
const escapeHTML = new SbHelpers().escapeHTML;
const attrs = { ...node.attrs };
const { linktype = 'url' } = node.attrs;
delete attrs.linktype;
if (attrs.href) {
attrs.href = escapeHTML(node.attrs.href || '')
attrs.href = escapeHTML(node.attrs.href || '');
}
if (isEmailLinkType(linktype)) {
attrs.href = `mailto:${attrs.href}`
attrs.href = `mailto:${attrs.href}`;
}
if (attrs.anchor) {
attrs.href = `${attrs.href}#${attrs.anchor}`
delete attrs.anchor
attrs.href = `${attrs.href}#${attrs.anchor}`;
delete attrs.anchor;
}

@@ -166,5 +171,5 @@

for (const key in attrs.custom) {
attrs[key] = attrs.custom[key]
attrs[key] = attrs.custom[key];
}
delete attrs.custom
delete attrs.custom;
}

@@ -176,7 +181,7 @@

tag: 'a',
attrs: attrs,
attrs,
},
],
}
}
};
};

@@ -191,4 +196,4 @@ const styled: MarkSchema = (node: ISbNode) => {

],
}
}
};
};

@@ -198,4 +203,4 @@ const subscript: MarkSchema = () => {

tag: 'sub',
}
}
};
};

@@ -205,4 +210,4 @@ const superscript: MarkSchema = () => {

tag: 'sup',
}
}
};
};

@@ -217,14 +222,15 @@ const anchor: MarkSchema = (node: ISbNode) => {

],
}
}
};
};
const highlight: MarkSchema = (node: ISbNode) => {
if (!node.attrs?.color)
if (!node.attrs?.color) {
return {
tag: '',
}
};
}
const attrs = {
['style']: `background-color:${node.attrs.color};`,
}
style: `background-color:${node.attrs.color};`,
};
return {

@@ -237,14 +243,15 @@ tag: [

],
}
}
};
};
const textStyle: MarkSchema = (node: ISbNode) => {
if (!node.attrs?.color)
if (!node.attrs?.color) {
return {
tag: '',
}
};
}
const attrs = {
['style']: `color:${node.attrs.color}`,
}
style: `color:${node.attrs.color}`,
};
return {

@@ -257,4 +264,4 @@ tag: [

],
}
}
};
};

@@ -290,2 +297,2 @@ export default {

},
}
};

@@ -1,104 +0,88 @@

import { ThrottleFn } from './interfaces'
import type { ISbThrottle, Queue } from './interfaces';
type Shifted = {
args: any
self: any
resolve: (args: any) => any
}
type Queue = {
resolve: (args: any) => any
reject: (args: any) => any
args: any[]
self: any
}
interface ISbThrottle {
abort: () => any
(args: []): Promise<Queue>
name: string
AbortError?: () => void
}
function isFinite(value: number) {
if (value !== value || value === Infinity || value === -Infinity) {
return false
class AbortError extends Error {
constructor(msg: string) {
super(msg);
this.name = 'AbortError';
}
return true
}
function throttledQueue(fn: ThrottleFn, limit: number, interval: number) {
if (!isFinite(limit)) {
throw new TypeError('Expected `limit` to be a finite number')
function throttledQueue<T extends (...args: Parameters<T>) => ReturnType<T>>(
fn: T,
limit: number,
interval: number,
): ISbThrottle<T> {
if (!Number.isFinite(limit)) {
throw new TypeError('Expected `limit` to be a finite number');
}
if (!isFinite(interval)) {
throw new TypeError('Expected `interval` to be a finite number')
if (!Number.isFinite(interval)) {
throw new TypeError('Expected `interval` to be a finite number');
}
const queue: Queue[] = []
let timeouts: ReturnType<typeof setTimeout>[] = []
let activeCount = 0
const queue: Queue<Parameters<T>>[] = [];
let timeouts: ReturnType<typeof setTimeout>[] = [];
let activeCount = 0;
let isAborted = false;
const next = function () {
activeCount++
const next = async () => {
activeCount++;
const id = setTimeout(function () {
activeCount--
const x = queue.shift();
if (x) {
const res = await fn(...x.args);
x.resolve(res);
}
const id = setTimeout(() => {
activeCount--;
if (queue.length > 0) {
next()
next();
}
timeouts = timeouts.filter(function (currentId) {
return currentId !== id
})
}, interval)
timeouts = timeouts.filter(currentId => currentId !== id);
}, interval);
if (timeouts.indexOf(id) < 0) {
timeouts.push(id)
if (!timeouts.includes(id)) {
timeouts.push(id);
}
};
const x = queue.shift() as unknown as Shifted
x.resolve(fn.apply(x.self, x.args))
}
const throttled: ISbThrottle<T> = (...args) => {
if (isAborted) {
return Promise.reject(
new Error(
'Throttled function is already aborted and not accepting new promises',
),
);
}
const throttled: ISbThrottle = function (
this: ISbThrottle,
...args: []
): Promise<Queue> {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
queue.push({
resolve: resolve,
reject: reject,
args: args,
self,
})
resolve,
reject,
args,
});
if (activeCount < limit) {
next()
next();
}
})
}
});
};
throttled.abort = function () {
timeouts.forEach(clearTimeout)
timeouts = []
throttled.abort = () => {
isAborted = true;
timeouts.forEach(clearTimeout);
timeouts = [];
queue.forEach(function (x) {
x.reject(function (this: ISbThrottle) {
Error.call(this, 'Throttled function aborted')
this.name = 'AbortError'
})
})
queue.length = 0
}
queue.forEach(x =>
x.reject(() => new AbortError('Throttle function aborted')),
);
queue.length = 0;
};
return throttled
return throttled;
}
export default throttledQueue
export default throttledQueue;

@@ -1,6 +0,6 @@

import StoryblokClient from 'storyblok-js-client'
import { describe, it, expect, beforeEach } from 'vitest'
import StoryblokClient from 'storyblok-js-client';
import { beforeEach, describe, expect, it } from 'vitest';
describe('StoryblokClient', () => {
let client
let client: StoryblokClient;

@@ -12,4 +12,4 @@ beforeEach(() => {

cache: { type: 'memory', clear: 'auto' },
})
})
});
});
// TODO: Uncomment when we have a valid token

@@ -32,37 +32,37 @@ /* if (process.env.VITE_OAUTH_TOKEN) {

describe('get function', () => {
it("get('cdn/spaces/me') should return the space information", async () => {
const { data } = await client.get('cdn/spaces/me')
expect(data.space.id).toBe(Number(process.env.VITE_SPACE_ID))
})
it('get(\'cdn/spaces/me\') should return the space information', async () => {
const { data } = await client.get('cdn/spaces/me');
expect(data.space.id).toBe(Number(process.env.VITE_SPACE_ID));
});
it("get('cdn/stories') should return all stories", async () => {
const { data } = await client.get('cdn/stories')
expect(data.stories.length).toBeGreaterThan(0)
})
it('get(\'cdn/stories\') should return all stories', async () => {
const { data } = await client.get('cdn/stories');
expect(data.stories.length).toBeGreaterThan(0);
});
it("get('cdn/stories/testcontent-0' should return the specific story", async () => {
const { data } = await client.get('cdn/stories/testcontent-0')
expect(data.story.slug).toBe('testcontent-0')
})
it('get(\'cdn/stories/testcontent-0\' should return the specific story', async () => {
const { data } = await client.get('cdn/stories/testcontent-0');
expect(data.story.slug).toBe('testcontent-0');
});
it("get('cdn/stories' { starts_with: testcontent-0 } should return the specific story", async () => {
it('get(\'cdn/stories\' { starts_with: testcontent-0 } should return the specific story', async () => {
const { data } = await client.get('cdn/stories', {
starts_with: 'testcontent-0',
})
expect(data.stories.length).toBe(1)
})
});
expect(data.stories.length).toBe(1);
});
it("get('cdn/stories/testcontent-draft', { version: 'draft' }) should return the specific story draft", async () => {
it('get(\'cdn/stories/testcontent-draft\', { version: \'draft\' }) should return the specific story draft', async () => {
const { data } = await client.get('cdn/stories/testcontent-draft', {
version: 'draft'
})
expect(data.story.slug).toBe('testcontent-draft')
})
version: 'draft',
});
expect(data.story.slug).toBe('testcontent-draft');
});
it("get('cdn/stories/testcontent-0', { version: 'published' }) should return the specific story published", async () => {
it('get(\'cdn/stories/testcontent-0\', { version: \'published\' }) should return the specific story published', async () => {
const { data } = await client.get('cdn/stories/testcontent-0', {
version: 'published',
})
expect(data.story.slug).toBe('testcontent-0')
})
});
expect(data.story.slug).toBe('testcontent-0');
});

@@ -72,29 +72,29 @@ it('cdn/stories/testcontent-0 should resolve author relations', async () => {

resolve_relations: 'root.author',
})
console.log(data)
expect(data.story.content.author[0].slug).toBe('edgar-allan-poe')
})
});
it("get('cdn/stories', { by_slugs: 'folder/*' }) should return the specific story", async () => {
expect(data.story.content.author[0].slug).toBe('edgar-allan-poe');
});
it('get(\'cdn/stories\', { by_slugs: \'folder/*\' }) should return the specific story', async () => {
const { data } = await client.get('cdn/stories', {
by_slugs: 'folder/*',
})
expect(data.stories.length).toBeGreaterThan(0)
})
})
});
expect(data.stories.length).toBeGreaterThan(0);
});
});
describe('getAll function', () => {
it("getAll('cdn/stories') should return all stories", async () => {
const result = await client.getAll('cdn/stories')
expect(result.length).toBeGreaterThan(0)
})
it('getAll(\'cdn/stories\') should return all stories', async () => {
const result = await client.getAll('cdn/stories');
expect(result.length).toBeGreaterThan(0);
});
it("getAll('cdn/stories') should return all stories with filtered results", async () => {
it('getAll(\'cdn/stories\') should return all stories with filtered results', async () => {
const result = await client.getAll('cdn/stories', {
starts_with: 'testcontent-0',
})
expect(result.length).toBe(1)
})
});
expect(result.length).toBe(1);
});
it("getAll('cdn/stories', filter_query: { __or: [{ category: { any_in_array: 'Category 1' } }, { category: { any_in_array: 'Category 2' } }]}) should return all stories with the specific filter applied", async () => {
it('getAll(\'cdn/stories\', filter_query: { __or: [{ category: { any_in_array: \'Category 1\' } }, { category: { any_in_array: \'Category 2\' } }]}) should return all stories with the specific filter applied', async () => {
const result = await client.getAll('cdn/stories', {

@@ -107,45 +107,45 @@ filter_query: {

},
})
expect(result.length).toBeGreaterThan(0)
})
});
expect(result.length).toBeGreaterThan(0);
});
it("getAll('cdn/stories', {by_slugs: 'folder/*'}) should return all stories with the specific filter applied", async () => {
it('getAll(\'cdn/stories\', {by_slugs: \'folder/*\'}) should return all stories with the specific filter applied', async () => {
const result = await client.getAll('cdn/stories', {
by_slugs: 'folder/*',
})
expect(result.length).toBeGreaterThan(0)
})
});
expect(result.length).toBeGreaterThan(0);
});
it("getAll('cdn/links') should return all links", async () => {
const result = await client.getAll('cdn/links')
expect(result.length).toBeGreaterThan(0)
})
})
it('getAll(\'cdn/links\') should return all links', async () => {
const result = await client.getAll('cdn/links');
expect(result.length).toBeGreaterThan(0);
});
});
describe('caching', () => {
it("get('cdn/spaces/me') should not be cached", async () => {
const provider = client.cacheProvider()
await provider.flush()
await client.get('cdn/spaces/me')
expect(Object.values(provider.getAll()).length).toBe(0)
})
it('get(\'cdn/spaces/me\') should not be cached', async () => {
const provider = client.cacheProvider();
await provider.flush();
await client.get('cdn/spaces/me');
expect(Object.values(provider.getAll()).length).toBe(0);
});
it("get('cdn/stories') should be cached when is a published version", async () => {
const cacheVersion = client.cacheVersion()
it('get(\'cdn/stories\') should be cached when is a published version', async () => {
const cacheVersion = client.cacheVersion();
await client.get('cdn/stories')
await client.get('cdn/stories');
expect(cacheVersion).not.toBe(undefined)
expect(cacheVersion).not.toBe(undefined);
const newCacheVersion = client.cacheVersion()
const newCacheVersion = client.cacheVersion();
await client.get('cdn/stories')
await client.get('cdn/stories');
expect(newCacheVersion).toBe(client.cacheVersion())
expect(newCacheVersion).toBe(client.cacheVersion());
await client.get('cdn/stories')
await client.get('cdn/stories');
expect(newCacheVersion).toBe(client.cacheVersion())
})
})
})
expect(newCacheVersion).toBe(client.cacheVersion());
});
});
});

@@ -1,1 +0,1 @@

import 'isomorphic-fetch'
import 'isomorphic-fetch';

@@ -1,7 +0,7 @@

export function headersToObject(headers) {
const obj = {}
export function headersToObject(headers: Headers) {
const obj: { [key: string]: string } = {};
for (const [key, value] of headers.entries()) {
obj[key] = value
obj[key] = value;
}
return obj
return obj;
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc