storyblok-js-client
Advanced tools
Comparing version
@@ -1,2 +0,8 @@ | ||
(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(l,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 o=async()=>{i++;const h=r.shift();if(h)try{const f=await l(...h.args);h.resolve(f)}catch(f){h.reject(f)}const u=setTimeout(()=>{i--,r.length>0&&o(),s=s.filter(f=>f!==u)},t);s.includes(u)||s.push(u)},a=(...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&&o()});return a.abort=()=>{n=!0,s.forEach(clearTimeout),s=[],r.forEach(h=>h.reject(()=>new g("Throttle function aborted"))),r.length=0},a}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={"&":"&","<":"<",">":">",'"':""","'":"'"},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],o=r?"":encodeURIComponent(i);let a;typeof n=="object"?a=this.stringify(n,t?t+encodeURIComponent(`[${o}]`):o,Array.isArray(n)):a=`${t?t+encodeURIComponent(`[${o}]`):o}=${encodeURIComponent(n)}`,s.push(a)}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"})),j=function(l,e){const t={};for(const r in l){const s=l[r];e.includes(r)&&s!==null&&(t[r]=s)}return t},L=l=>l==="email",w={nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:l=>({tag:["pre",{tag:"code",attrs:l.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:l=>({tag:`h${l.attrs.level}`}),image:l=>({singleTag:[{tag:"img",attrs:j(l.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:l=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":l.attrs.name,emoji:l.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:l=>{if(!l.attrs)return{tag:""};const e=new y().escapeHTML,t={...l.attrs},{linktype:r="url"}=l.attrs;if(delete t.linktype,t.href&&(t.href=e(l.attrs.href||"")),L(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:l=>({tag:[{tag:"span",attrs:l.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:l=>({tag:[{tag:"span",attrs:l.attrs}]}),highlight:l=>{var t;return(t=l.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${l.attrs.color};`}}]}:{tag:""}},textStyle:l=>{var t;return(t=l.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${l.attrs.color}`}}]}:{tag:""}}}},O=function(l){const e={"&":"&","<":"<",">":">",'"':""","'":"'"},t=/[&<>"']/g,r=new RegExp(t.source);return l&&r.test(l)?l.replace(t,s=>e[s]):l};let S=!1;class _{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. | ||
/** | ||
* name: storyblok-js-client | ||
* (c) 2025 | ||
* description: Universal JavaScript SDK for Storyblok's API | ||
* author: Alexander Feiglstorfer <delooks@gmail.com> | ||
*/ | ||
(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(l,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 o=async()=>{i++;const h=r.shift();if(h)try{const f=await l(...h.args);h.resolve(f)}catch(f){h.reject(f)}const u=setTimeout(()=>{i--,r.length>0&&o(),s=s.filter(f=>f!==u)},t);s.includes(u)||s.push(u)},a=(...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&&o()});return a.abort=()=>{n=!0,s.forEach(clearTimeout),s=[],r.forEach(h=>h.reject(()=>new g("Throttle function aborted"))),r.length=0},a}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={"&":"&","<":"<",">":">",'"':""","'":"'"},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],o=r?"":encodeURIComponent(i);let a;typeof n=="object"?a=this.stringify(n,t?t+encodeURIComponent(`[${o}]`):o,Array.isArray(n)):a=`${t?t+encodeURIComponent(`[${o}]`):o}=${encodeURIComponent(n)}`,s.push(a)}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"})),j=function(l,e){const t={};for(const r in l){const s=l[r];e.includes(r)&&s!==null&&(t[r]=s)}return t},L=l=>l==="email",w={nodes:{horizontal_rule:()=>({singleTag:"hr"}),blockquote:()=>({tag:"blockquote"}),bullet_list:()=>({tag:"ul"}),code_block:l=>({tag:["pre",{tag:"code",attrs:l.attrs}]}),hard_break:()=>({singleTag:"br"}),heading:l=>({tag:`h${l.attrs.level}`}),image:l=>({singleTag:[{tag:"img",attrs:j(l.attrs,["src","alt","title"])}]}),list_item:()=>({tag:"li"}),ordered_list:()=>({tag:"ol"}),paragraph:()=>({tag:"p"}),emoji:l=>({tag:[{tag:"span",attrs:{"data-type":"emoji","data-name":l.attrs.name,emoji:l.attrs.emoji}}]})},marks:{bold:()=>({tag:"b"}),strike:()=>({tag:"s"}),underline:()=>({tag:"u"}),strong:()=>({tag:"strong"}),code:()=>({tag:"code"}),italic:()=>({tag:"i"}),link:l=>{if(!l.attrs)return{tag:""};const e=new y().escapeHTML,t={...l.attrs},{linktype:r="url"}=l.attrs;if(delete t.linktype,t.href&&(t.href=e(l.attrs.href||"")),L(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:l=>({tag:[{tag:"span",attrs:l.attrs}]}),subscript:()=>({tag:"sub"}),superscript:()=>({tag:"sup"}),anchor:l=>({tag:[{tag:"span",attrs:l.attrs}]}),highlight:l=>{var t;return(t=l.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`background-color:${l.attrs.color};`}}]}:{tag:""}},textStyle:l=>{var t;return(t=l.attrs)!=null&&t.color?{tag:[{tag:"span",attrs:{style:`color:${l.attrs.color}`}}]}:{tag:""}}}},O=function(l){const e={"&":"&","<":"<",">":">",'"':""","'":"'"},t=/[&<>"']/g,r=new RegExp(t.source);return l&&r.test(l)?l.replace(t,s=>e[s]):l};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. | ||
@@ -24,2 +30,2 @@ ISbRichtext: | ||
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 o=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/${o}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,a=>{var u,f;const h=a.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 T="";return m.srcset&&(T+=`srcset="${m.srcset}" `),m.sizes&&(T+=`sizes="${m.sizes}" `),a.replace(/<img/g,`<img ${T.trim()}`)}return a})),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(O(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 o=s.attrs[n];o!==null&&(i+=` ${n}="${o}"`)}}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 a=new y;t=`${this.baseURL}${this.url}?${a.stringify(this.parameters)}`}else r=JSON.stringify(this.parameters);const s=new URL(t),i=new AbortController,{signal:n}=i;let o;this.timeout&&(o=setTimeout(()=>i.abort(),this.timeout));try{const a=await this.fetch(`${s}`,{method:e,headers:this.headers,body:r,signal:n,...this.fetchOptions});this.timeout&&clearTimeout(o);const h=await this._responseHandler(a);return this.responseInterceptor&&!this.ejectInterceptor?this._statusHandler(this.responseInterceptor(h)):this._statusHandler(h)}catch(a){return{message:a}}}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 A="SB-Agent",R={defaultAgentName:"SB-JS-CLIENT",defaultAgentVersion:"SB-Agent-Version",packageVersion:"6.0.0"};let k={};const b={};class v{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,o=e.https===!1?"http":"https";e.oauthToken?r=`${o}://${n(e.region)}/v1`:r=`${o}://${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(([o,a])=>{s.set(o,a)}),s.has(A)||(s.set(A,R.defaultAgentName),s.set(R.defaultAgentVersion,R.packageVersion));let i=5;e.oauthToken&&(s.set("Authorization",e.oauthToken),i=3),e.rateLimit&&(i=e.rateLimit),e.richTextSchema?this.richTextResolver=new _(e.richTextSchema):this.richTextResolver=new _,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(/\/$/,""),o=r??n.substring(n.lastIndexOf("/")+1),a=1,h=await this.makeRequest(n,t,i,a,s),u=h.total?Math.ceil(h.total/i):1,f=await this.helpers.asyncMap(this.helpers.range(a,u),m=>this.makeRequest(n,t,i,m+1,s));return this.helpers.flatMap([h,...f],m=>Object.values(m.data[o]))}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){t||(t={});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]?JSON.parse(this.stringifiedStoriesCache[t]||JSON.stringify(this.relations[e][t])):t}_resolveField(e,t,r){const s=e[t];typeof s=="string"?e[t]=this.getStoryReference(r,s):Array.isArray(s)&&(e[t]=s.map(i=>this.getStoryReference(r,i)).filter(Boolean))}_insertRelations(e,t,r,s){if(Array.isArray(r)?r.find(o=>o.endsWith(`.${t}`)):r.endsWith(`.${t}`)){this._resolveField(e,t,s);return}const n=e.component?`${e.component}.${t}`:t;(Array.isArray(r)?r.includes(n):r===n)&&this._resolveField(e,t,s)}iterateTree(e,t,r){const s=(i,n="")=>{if(!(!i||i._stopResolving)){if(Array.isArray(i))i.forEach((o,a)=>s(o,`${n}[${a}]`));else if(typeof i=="object")for(const o in i){const a=n?`${n}.${o}`:o;(i.component&&i._uid||i.type==="link")&&(this._insertRelations(i,o,t,r),this._insertLinks(i,o,r)),s(i[o],a)}}};s(e.content)}async resolveLinks(e,t,r){let s=[];if(e.link_uuids){const i=e.link_uuids.length,n=[],o=50;for(let a=0;a<i;a+=o){const h=Math.min(i,a+o);n.push(e.link_uuids.slice(a,h))}for(let a=0;a<n.length;a++)(await this.getStories({per_page:o,language:t.language,version:t.version,by_uuids:n[a].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=[],o=50;for(let a=0;a<i;a+=o){const h=Math.min(i,a+o);n.push(e.rel_uuids.slice(a,h))}for(let a=0;a<n.length;a++)(await this.getStories({per_page:o,language:t.language,version:t.version,by_uuids:n[a].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 o in this.relations[r])this.iterateTree(this.relations[r][o],s,r);e.story?this.iterateTree(e.story,s,r):e.stories.forEach(o=>{this.iterateTree(o,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 o=await n.get(i);if(o)return Promise.resolve(o)}return new Promise(async(o,a)=>{var h;try{const u=await this.throttle("get",e,t,s);if(u.status!==200)return a(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),o(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(o).catch(a);a(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 P=(l,e)=>{for(const t in e)l[t]=e[t]};return P(v,{RichtextResolver:_,SbFetch:x,RichTextSchema:w}),P(v,E),v}); | ||
}`),""}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 o=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/${o}`),typeof t!="boolean"&&(t.sizes||t.srcset)&&(e=e.replace(/<img.*?src=["|'](.*?)["|']/g,a=>{var u,f;const h=a.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 v=0,C=0;return typeof p[0]=="number"&&(v=p[0]),typeof p[1]=="number"&&(C=p[1]),`//${h}/m/${v}x${C}${n} ${v}w`}return""}).join(", "),sizes:(f=t.sizes)==null?void 0:f.map(p=>p).join(", ")};let k="";return m.srcset&&(k+=`srcset="${m.srcset}" `),m.sizes&&(k+=`sizes="${m.sizes}" `),a.replace(/<img/g,`<img ${k.trim()}`)}return a})),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(O(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 o=s.attrs[n];o!==null&&(i+=` ${n}="${o}"`)}}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 a=new y;t=`${this.baseURL}${this.url}?${a.stringify(this.parameters)}`}else r=JSON.stringify(this.parameters);const s=new URL(t),i=new AbortController,{signal:n}=i;let o;this.timeout&&(o=setTimeout(()=>i.abort(),this.timeout));try{const a=await this.fetch(`${s}`,{method:e,headers:this.headers,body:r,signal:n,...this.fetchOptions});this.timeout&&clearTimeout(o);const h=await this._responseHandler(a);return this.responseInterceptor&&!this.ejectInterceptor?this._statusHandler(this.responseInterceptor(h)):this._statusHandler(h)}catch(a){return{message:a}}}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 A="SB-Agent",T={defaultAgentName:"SB-JS-CLIENT",defaultAgentVersion:"SB-Agent-Version",packageVersion:"6.0.0"};let _={};const b={};class ${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,o=e.https===!1?"http":"https";e.oauthToken?r=`${o}://${n(e.region)}/v1`:r=`${o}://${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(([o,a])=>{s.set(o,a)}),s.has(A)||(s.set(A,T.defaultAgentName),s.set(T.defaultAgentVersion,T.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(/\/$/,""),o=r??n.substring(n.lastIndexOf("/")+1),a=1,h=await this.makeRequest(n,t,i,a,s),u=h.total?Math.ceil(h.total/i):1,f=await this.helpers.asyncMap(this.helpers.range(a,u),m=>this.makeRequest(n,t,i,m+1,s));return this.helpers.flatMap([h,...f],m=>Object.values(m.data[o]))}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){t||(t={});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]?JSON.parse(this.stringifiedStoriesCache[t]||JSON.stringify(this.relations[e][t])):t}_resolveField(e,t,r){const s=e[t];typeof s=="string"?e[t]=this.getStoryReference(r,s):Array.isArray(s)&&(e[t]=s.map(i=>this.getStoryReference(r,i)).filter(Boolean))}_insertRelations(e,t,r,s){if(Array.isArray(r)?r.find(o=>o.endsWith(`.${t}`)):r.endsWith(`.${t}`)){this._resolveField(e,t,s);return}const n=e.component?`${e.component}.${t}`:t;(Array.isArray(r)?r.includes(n):r===n)&&this._resolveField(e,t,s)}iterateTree(e,t,r){const s=(i,n="")=>{if(!(!i||i._stopResolving)){if(Array.isArray(i))i.forEach((o,a)=>s(o,`${n}[${a}]`));else if(typeof i=="object")for(const o in i){const a=n?`${n}.${o}`:o;(i.component&&i._uid||i.type==="link")&&(this._insertRelations(i,o,t,r),this._insertLinks(i,o,r)),s(i[o],a)}}};s(e.content)}async resolveLinks(e,t,r){let s=[];if(e.link_uuids){const i=e.link_uuids.length,n=[],o=50;for(let a=0;a<i;a+=o){const h=Math.min(i,a+o);n.push(e.link_uuids.slice(a,h))}for(let a=0;a<n.length;a++)(await this.getStories({per_page:o,language:t.language,version:t.version,by_uuids:n[a].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=[],o=50;for(let a=0;a<i;a+=o){const h=Math.min(i,a+o);n.push(e.rel_uuids.slice(a,h))}for(let a=0;a<n.length;a++)(await this.getStories({per_page:o,language:t.language,version:t.version,by_uuids:n[a].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 o in this.relations[r])this.iterateTree(this.relations[r][o],s,r);e.story?this.iterateTree(e.story,s,r):e.stories.forEach(o=>{this.iterateTree(o,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(t.version==="published"&&e!=="/cdn/spaces/me"){const o=await n.get(i);if(o)return Promise.resolve(o)}return new Promise(async(o,a)=>{var h;try{const u=await this.throttle("get",e,t,s);if(u.status!==200)return a(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 k=this.resolveCounter=++this.resolveCounter%1e3;await this.resolveStories(f.data,t,`${k}`)}t.version==="published"&&e!=="/cdn/spaces/me"&&await n.set(i,f);const m=this.cache.clear==="onpreview"&&t.version==="draft"||this.cache.clear==="auto";return t.token&&f.data.cv&&(m&&b[t.token]&&b[t.token]!==f.data.cv&&await this.flushCache(),b[t.token]=f.data.cv),o(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(o).catch(a);a(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(_[e])},getAll(){return Promise.resolve(_)},set(e,t){return _[e]=t,Promise.resolve(void 0)},flush(){return _={},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 P=(l,e)=>{for(const t in e)l[t]=e[t]};return P($,{RichtextResolver:R,SbFetch:x,RichTextSchema:w}),P($,E),$}); |
@@ -0,1 +1,7 @@ | ||
/** | ||
* name: storyblok-js-client | ||
* (c) 2025 | ||
* description: Universal JavaScript SDK for Storyblok's API | ||
* author: Alexander Feiglstorfer <delooks@gmail.com> | ||
*/ | ||
(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={"&":"&","<":"<",">":">",'"':""","'":"'"},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={"&":"&","<":"<",">":">",'"':""","'":"'"},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. | ||
@@ -2,0 +8,0 @@ The "content" field must be an array of nodes as the type ISbRichtext. |
@@ -0,1 +1,7 @@ | ||
/** | ||
* name: storyblok-js-client | ||
* (c) 2025 | ||
* description: Universal JavaScript SDK for Storyblok's API | ||
* author: Alexander Feiglstorfer <delooks@gmail.com> | ||
*/ | ||
(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={"&":"&","<":"<",">":">",'"':""","'":"'"},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 @@ | ||
import Client from './index'; | ||
import { default as Client } from './index'; | ||
export default Client; | ||
@@ -3,0 +3,0 @@ export * from './constants'; |
@@ -1,2 +0,2 @@ | ||
import Client from './index'; | ||
import { default as Client } from './index'; | ||
export default Client; |
@@ -1,3 +0,3 @@ | ||
import RichTextResolver from './richTextResolver'; | ||
import type { ISbConfig, ISbContentMangmntAPI, ISbCustomFetch, ISbLinksParams, ISbLinksResult, ISbResponseData, ISbResult, ISbStories, ISbStoriesParams, ISbStory, ISbStoryParams } from './interfaces'; | ||
import { default as RichTextResolver } from './richTextResolver'; | ||
import { ICacheProvider, ISbConfig, ISbContentMangmntAPI, ISbCustomFetch, ISbLinksParams, ISbLinksResult, ISbResponseData, ISbResult, ISbStories, ISbStoriesParams, ISbStory, ISbStoryParams } from './interfaces'; | ||
interface ComponentResolverFn { | ||
@@ -113,5 +113,5 @@ (...args: any): any; | ||
clearCacheVersion(): void; | ||
private cacheProvider; | ||
cacheProvider(): ICacheProvider; | ||
flushCache(): Promise<this>; | ||
} | ||
export default Storyblok; |
@@ -1,3 +0,3 @@ | ||
import type { ResponseFn } from './sbFetch'; | ||
import type Method from './constants'; | ||
import { ResponseFn } from './sbFetch'; | ||
import { default as Method } from './constants'; | ||
export interface ISbStoriesParams extends Partial<ISbStoryData>, ISbMultipleStoriesData, ISbAssetsParams { | ||
@@ -211,3 +211,3 @@ resolve_level?: number; | ||
type?: 'none' | 'memory' | 'custom'; | ||
clear?: 'auto' | 'manual'; | ||
clear?: 'auto' | 'manual' | 'onpreview'; | ||
custom?: ICacheProvider; | ||
@@ -214,0 +214,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import type { ISbRichtext, ISbSchema } from './interfaces'; | ||
import { ISbRichtext, ISbSchema } from './interfaces'; | ||
type OptimizeImagesOptions = boolean | { | ||
@@ -3,0 +3,0 @@ class?: string; |
@@ -1,2 +0,2 @@ | ||
import type { ISbCustomFetch, ISbError, ISbResponse, ISbStoriesParams } from './interfaces'; | ||
import { ISbCustomFetch, ISbError, ISbResponse, ISbStoriesParams } from './interfaces'; | ||
export interface ResponseFn { | ||
@@ -3,0 +3,0 @@ (arg?: ISbResponse | any): any; |
@@ -1,2 +0,2 @@ | ||
import type { AsyncFn, ISbResult, ISbStoriesParams } from './interfaces'; | ||
import { AsyncFn, ISbResult, ISbStoriesParams } from './interfaces'; | ||
interface ISbParams extends ISbStoriesParams { | ||
@@ -48,5 +48,5 @@ [key: string]: any; | ||
with_tag?: string; | ||
alternates?: import("./interfaces").ISbAlternateObject[] | undefined; | ||
breadcrumbs?: import("./interfaces").ISbLinkURLObject[] | undefined; | ||
content?: (import("./interfaces").ISbComponentType<string> & { | ||
alternates?: import('./interfaces').ISbAlternateObject[] | undefined; | ||
breadcrumbs?: import('./interfaces').ISbLinkURLObject[] | undefined; | ||
content?: (import('./interfaces').ISbComponentType<string> & { | ||
[index: string]: any; | ||
@@ -72,6 +72,6 @@ }) | undefined; | ||
last_author_id?: number | undefined; | ||
localized_paths?: import("./interfaces").LocalizedPath[] | null | undefined; | ||
localized_paths?: import('./interfaces').LocalizedPath[] | null | undefined; | ||
meta_data?: any; | ||
name?: string | undefined; | ||
parent?: import("./interfaces").ISbStoryData | undefined; | ||
parent?: import('./interfaces').ISbStoryData | undefined; | ||
parent_id?: number | null | undefined; | ||
@@ -81,3 +81,3 @@ path?: string | undefined; | ||
position?: number | undefined; | ||
preview_token?: import("./interfaces").PreviewToken | undefined; | ||
preview_token?: import('./interfaces').PreviewToken | undefined; | ||
published?: boolean | undefined; | ||
@@ -93,3 +93,3 @@ published_at?: string | null | undefined; | ||
name: string | null; | ||
lang: import("./interfaces").ISbStoryData["lang"]; | ||
lang: import('./interfaces').ISbStoryData["lang"]; | ||
}[] | null | undefined; | ||
@@ -96,0 +96,0 @@ unpublished_changes?: boolean | undefined; |
@@ -1,2 +0,2 @@ | ||
import type { MarkSchema, NodeSchema } from './interfaces'; | ||
import { MarkSchema, NodeSchema } from './interfaces'; | ||
declare const _default: { | ||
@@ -3,0 +3,0 @@ nodes: { |
@@ -1,3 +0,3 @@ | ||
import type { ISbThrottle } from './interfaces'; | ||
import { 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", | ||
"version": "6.10.7", | ||
"packageManager": "pnpm@9.15.0", | ||
"version": "6.10.8", | ||
"packageManager": "pnpm@10.2.0", | ||
"description": "Universal JavaScript SDK for Storyblok's API", | ||
@@ -51,4 +51,11 @@ "author": "Alexander Feiglstorfer <delooks@gmail.com>", | ||
"scripts": { | ||
"lint": "eslint --max-warnings=0 './src/**/*.{ts,js}'", | ||
"build": "node vite.build.mjs && tsc", | ||
"dev": "vite build --watch", | ||
"build": "node vite.build.mjs", | ||
"test": "pnpm run test:unit:ci && pnpm run test:e2e", | ||
"test:unit": "vitest", | ||
"test:unit:ci": "vitest run", | ||
"test:unit:ui": "vitest --ui", | ||
"test:e2e": "vitest run -c vitest.config.e2e.ts", | ||
"lint": "eslint .", | ||
"lint:fix": "eslint . --fix", | ||
"playground": "pnpm run --filter ./playground/vanilla dev", | ||
@@ -58,28 +65,23 @@ "playground:svelte": "pnpm run --filter ./playground/svelte dev", | ||
"dev:umd": "npx serve ./", | ||
"test": "vitest run", | ||
"test:e2e": "vitest run -c vitest.config.e2e.ts", | ||
"test:ui": "vitest --ui --coverage.enabled=true", | ||
"coverage": "vitest run --coverage", | ||
"prepare": "npm run build" | ||
"prepare": "pnpm simple-git-hooks", | ||
"prepublishOnly": "pnpm build" | ||
}, | ||
"devDependencies": { | ||
"@commitlint/cli": "^19.6.1", | ||
"@commitlint/config-conventional": "^19.6.0", | ||
"@commitlint/cli": "^19.7.1", | ||
"@commitlint/config-conventional": "^19.7.1", | ||
"@storyblok/eslint-config": "^0.3.0", | ||
"@tsconfig/recommended": "^1.0.8", | ||
"@typescript-eslint/eslint-plugin": "^8.18.1", | ||
"@typescript-eslint/parser": "^8.18.1", | ||
"@vitest/coverage-v8": "^2.1.8", | ||
"@vitest/ui": "^2.1.8", | ||
"eslint": "^9.17.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"isomorphic-fetch": "^3.0.0", | ||
"@vitest/coverage-v8": "^3.0.5", | ||
"@vitest/ui": "^3.0.5", | ||
"eslint": "^9.19.0", | ||
"eslint-config-prettier": "^10.0.1", | ||
"kolorist": "^1.8.0", | ||
"prettier": "^3.4.2", | ||
"simple-git-hooks": "^2.11.1", | ||
"typescript": "^5.7.2", | ||
"vite": "^5.4.11", | ||
"typescript": "^5.7.3", | ||
"vite": "^6.1.0", | ||
"vite-plugin-banner": "^0.8.0", | ||
"vite-plugin-dts": "^4.4.0", | ||
"vitest": "^2.1.8" | ||
"vite-plugin-dts": "^4.5.0", | ||
"vitest": "^3.0.5" | ||
}, | ||
@@ -105,3 +107,10 @@ "release": { | ||
"@commitlint/config-conventional" | ||
] | ||
], | ||
"rules": { | ||
"body-max-line-length": [ | ||
2, | ||
"always", | ||
200 | ||
] | ||
} | ||
}, | ||
@@ -108,0 +117,0 @@ "simple-git-hooks": { |
@@ -167,2 +167,4 @@ <div align="center"> | ||
To only clear the cache automatically when requests to the draft version happens you can set the config to `clear: 'onpreview'`. | ||
```javascript | ||
@@ -169,0 +171,0 @@ let Storyblok = new StoryblokClient({ |
@@ -214,15 +214,2 @@ import StoryblokClient from '.'; | ||
}); | ||
it('should flush the cache when the draft version is requested and clear is auto', async () => { | ||
client = new StoryblokClient({ cache: { clear: 'auto' } }); | ||
client.cacheProvider = vi.fn().mockReturnValue({ | ||
flush: vi.fn().mockResolvedValue(undefined), | ||
}); | ||
client.clearCacheVersion = vi.fn(); | ||
// Setup scenario where draft version triggers cache flush | ||
await client.get('test-draft', { version: 'draft' }); | ||
// Ensure cache flush method was called | ||
expect(client.cacheProvider().flush).toHaveBeenCalled(); | ||
expect(client.clearCacheVersion).toHaveBeenCalled(); | ||
}); | ||
}); | ||
@@ -229,0 +216,0 @@ |
@@ -680,6 +680,2 @@ import throttledQueue from './throttlePromise'; | ||
if (this.cache.clear === 'auto' && params.version === 'draft') { | ||
await this.flushCache(); | ||
} | ||
if (params.version === 'published' && url !== '/cdn/spaces/me') { | ||
@@ -727,8 +723,12 @@ const cache = await provider.get(cacheKey); | ||
if ( | ||
response.data.cv | ||
&& params.token | ||
&& cacheVersions[params.token] !== response.data.cv | ||
) { | ||
await this.flushCache(); | ||
const isCacheClearable = (this.cache.clear === 'onpreview' && params.version === 'draft') | ||
|| this.cache.clear === 'auto'; | ||
if (params.token && response.data.cv) { | ||
if (isCacheClearable | ||
&& cacheVersions[params.token] // there is a cache | ||
&& cacheVersions[params.token] !== response.data.cv // a new cv is incoming | ||
) { | ||
await this.flushCache(); | ||
} | ||
cacheVersions[params.token] = response.data.cv; | ||
@@ -789,3 +789,3 @@ } | ||
private cacheProvider(): ICacheProvider { | ||
public cacheProvider(): ICacheProvider { | ||
switch (this.cache.type) { | ||
@@ -792,0 +792,0 @@ case 'memory': |
@@ -230,3 +230,3 @@ import type { ResponseFn } from './sbFetch'; | ||
type?: 'none' | 'memory' | 'custom'; | ||
clear?: 'auto' | 'manual'; | ||
clear?: 'auto' | 'manual' | 'onpreview'; | ||
custom?: ICacheProvider; | ||
@@ -233,0 +233,0 @@ } |
import StoryblokClient from 'storyblok-js-client'; | ||
import { beforeEach, describe, expect, it } from 'vitest'; | ||
import { beforeEach, describe, expect, it, vi } from 'vitest'; | ||
function sleep(ms: number): Promise<void> { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
describe('StoryblokClient', () => { | ||
@@ -85,3 +89,3 @@ let client: StoryblokClient; | ||
it('getAll(\'cdn/stories\') should return all stories', async () => { | ||
const result = await client.getAll('cdn/stories'); | ||
const result = await client.getAll('cdn/stories', {}); | ||
expect(result.length).toBeGreaterThan(0); | ||
@@ -117,3 +121,3 @@ }); | ||
it('getAll(\'cdn/links\') should return all links', async () => { | ||
const result = await client.getAll('cdn/links'); | ||
const result = await client.getAll('cdn/links', {}); | ||
expect(result.length).toBeGreaterThan(0); | ||
@@ -148,3 +152,69 @@ }); | ||
}); | ||
it('should flush the cache when version: draft + clear: onpreview', async () => { | ||
client = new StoryblokClient({ | ||
accessToken: process.env.VITE_ACCESS_TOKEN, | ||
cache: { type: 'memory', clear: 'onpreview' }, | ||
}); | ||
const mapi = new StoryblokClient({ oauthToken: process.env.VITE_OAUTH_TOKEN }); | ||
const spaceId = process.env.VITE_SPACE_ID; | ||
client.cacheProvider = vi.fn().mockReturnValue({ | ||
flush: vi.fn().mockResolvedValue(undefined), | ||
}); | ||
// Setup scenario where draft version triggers cache flush | ||
const { data } = await client.get('cdn/stories/testcontent-0', { version: 'draft' }); // no cache, so won't trigger flush | ||
await client.get('cdn/stories/testcontent-0', { version: 'draft' }); // cached, but cv didn't change, so won't trigger flush | ||
await sleep(1000); // for TTL | ||
await mapi.put(`spaces/${spaceId}/stories/${data.story.id}`, { story: { ...data.story } }); // force generating a new cv | ||
await client.get('cdn/stories/testcontent-1', { version: 'draft' }); // call a new page to force retrieval of the new cv | ||
expect(client.cacheProvider().flush).toHaveBeenCalled(); | ||
}); | ||
it('should not flush the cache when version: published + clear: onpreview', async () => { | ||
client = new StoryblokClient({ | ||
accessToken: process.env.VITE_ACCESS_TOKEN, | ||
cache: { type: 'memory', clear: 'onpreview' }, | ||
}); | ||
const mapi = new StoryblokClient({ oauthToken: process.env.VITE_OAUTH_TOKEN }); | ||
const spaceId = process.env.VITE_SPACE_ID; | ||
client.cacheProvider = vi.fn().mockReturnValue({ | ||
flush: vi.fn().mockResolvedValue(undefined), | ||
}); | ||
// Setup scenario where draft version triggers cache flush | ||
const { data } = await client.get('cdn/stories/testcontent-0'); // no cache, so won't trigger flush | ||
await client.get('cdn/stories/testcontent-0'); // cached, but cv didn't change, so won't trigger flush | ||
await sleep(1000); // for TTL | ||
await mapi.put(`spaces/${spaceId}/stories/${data.story.id}`, { story: { ...data.story }, publish: 1 }); // force generating a new cv | ||
await client.get('cdn/stories/testcontent-1'); // call a new page to force retrieval of the new cv | ||
expect(client.cacheProvider().flush).not.toHaveBeenCalled(); | ||
}); | ||
it('should flush the cache when clear: auto, even when published', async () => { | ||
client = new StoryblokClient({ | ||
accessToken: process.env.VITE_ACCESS_TOKEN, | ||
cache: { type: 'memory', clear: 'auto' }, | ||
}); | ||
const mapi = new StoryblokClient({ oauthToken: process.env.VITE_OAUTH_TOKEN }); | ||
const spaceId = process.env.VITE_SPACE_ID; | ||
client.cacheProvider = vi.fn().mockReturnValue({ | ||
flush: vi.fn().mockResolvedValue(undefined), | ||
}); | ||
// Setup scenario where draft version triggers cache flush | ||
const { data } = await client.get('cdn/stories/testcontent-0'); // no cache, so won't trigger flush | ||
await client.get('cdn/stories/testcontent-0'); // cached, but cv didn't change, so won't trigger flush | ||
await sleep(1000); // for TTL | ||
await mapi.put(`spaces/${spaceId}/stories/${data.story.id}`, { story: { ...data.story }, publish: 1 }); // force generating a new cv | ||
await client.get('cdn/stories/testcontent-1'); // call a new page to force retrieval of the new cv | ||
expect(client.cacheProvider().flush).toHaveBeenCalled(); | ||
}); | ||
}); | ||
}); |
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
245133
1.86%16
-15.79%6132
1.36%805
0.25%35
-2.78%