@cobrastyle/adapter-storyblok 1.0.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +68 -3
- package/dist/client.js +181 -11
- package/dist/config.d.ts +5 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +9 -1
- package/dist/types.d.ts +46 -0
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,72 @@
|
|
|
1
|
+
import StoryblokClient from 'storyblok-js-client';
|
|
2
|
+
import type { ISbCustomFetch, ISbStoriesParams } from 'storyblok-js-client';
|
|
1
3
|
import { type StoryblokVersion } from './config';
|
|
2
|
-
import type { StoryblokStory } from './types';
|
|
4
|
+
import type { FetchStoriesParams, ResolveParams, StoryblokStoriesResult, StoryblokStory } from './types';
|
|
3
5
|
import type { MapContext } from './mappers/blocks';
|
|
6
|
+
/**
|
|
7
|
+
* Storyblok caps `by_uuids` at 100 ids per request. Beyond that the query
|
|
8
|
+
* string overflows and the CDN errors, so lists longer than this are split
|
|
9
|
+
* across requests and merged. Consumers should not have to know this.
|
|
10
|
+
*/
|
|
11
|
+
export declare const UUID_CHUNK_SIZE = 100;
|
|
12
|
+
/** Drop memoised clients. Needed when the config changes (tokens, region). */
|
|
13
|
+
export declare function resetClients(): void;
|
|
14
|
+
/** The version this request should read, unless the caller pins one. */
|
|
15
|
+
export declare function resolveVersion(version?: StoryblokVersion): Promise<StoryblokVersion>;
|
|
16
|
+
/**
|
|
17
|
+
* The configured client for a version — correct token, region and richtext
|
|
18
|
+
* resolver. Exported so consumers that render their own components never have
|
|
19
|
+
* to construct a client (and re-derive token selection) themselves.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getStoryblokClient(version?: StoryblokVersion): Promise<StoryblokClient>;
|
|
4
22
|
/** Render context backed by the SDK's richtext resolver. */
|
|
5
23
|
export declare function mapContext(version: StoryblokVersion): MapContext;
|
|
6
|
-
/**
|
|
7
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Cache policy, in one place.
|
|
26
|
+
*
|
|
27
|
+
* Draft must never be cached — the Visual Editor would show stale content and
|
|
28
|
+
* the editor would think their change was lost. Published content is cached for
|
|
29
|
+
* `revalidate` seconds (from config, or per call).
|
|
30
|
+
*/
|
|
31
|
+
export declare function fetchOptionsFor(version: StoryblokVersion, revalidate?: number): ISbCustomFetch;
|
|
32
|
+
export interface FetchOptions {
|
|
33
|
+
/** Pin the version instead of resolving it from config. */
|
|
34
|
+
version?: StoryblokVersion;
|
|
35
|
+
/** Cache lifetime in seconds. Published only — draft is always uncached. */
|
|
36
|
+
revalidate?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface FetchStoryOptions extends FetchOptions {
|
|
39
|
+
/** Relation/link expansion for this story. */
|
|
40
|
+
params?: ResolveParams;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Fetch a single story by slug. Returns null on 404.
|
|
44
|
+
*
|
|
45
|
+
* Pass `params.resolve_relations` to have Storyblok substitute referenced
|
|
46
|
+
* stories rather than returning bare uuids — the alternative is batch-fetching
|
|
47
|
+
* them yourself afterwards.
|
|
48
|
+
*/
|
|
49
|
+
export declare function fetchStory(slug: string, version?: StoryblokVersion, opts?: FetchStoryOptions): Promise<StoryblokStory | null>;
|
|
50
|
+
/** Translate the public params into the SDK's wire shape. */
|
|
51
|
+
export declare function toStoriesParams(params: FetchStoriesParams, version: StoryblokVersion): ISbStoriesParams;
|
|
52
|
+
/** Translate single-story params into the SDK's wire shape. */
|
|
53
|
+
export declare function toStoryParams(params: ResolveParams, version: StoryblokVersion): Record<string, unknown>;
|
|
54
|
+
/**
|
|
55
|
+
* Query the Content Delivery API for a list of stories.
|
|
56
|
+
*
|
|
57
|
+
* Returns raw stories — mapping into `CmsPage`/`CmsBlockNode` is opt-in via
|
|
58
|
+
* `mapStory`, so consumers rendering their own components keep the full blok
|
|
59
|
+
* tree (and `_editable`, which the Visual Editor needs).
|
|
60
|
+
*
|
|
61
|
+
* `by_uuids` / `by_uuids_ordered` longer than 100 are split and merged
|
|
62
|
+
* transparently; `by_uuids_ordered` keeps the caller's order across chunks.
|
|
63
|
+
*/
|
|
64
|
+
export declare function fetchStories(params?: FetchStoriesParams, opts?: FetchOptions): Promise<StoryblokStoriesResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Every story matching the query, paging until the CDN is exhausted.
|
|
67
|
+
*
|
|
68
|
+
* `fetchStories` returns one page — fine for a capped list, wrong for "all
|
|
69
|
+
* recipes" once a space grows past `per_page`. Uuid queries are already
|
|
70
|
+
* complete (they chunk rather than page), so those short-circuit.
|
|
71
|
+
*/
|
|
72
|
+
export declare function fetchAllStories(params?: FetchStoriesParams, opts?: FetchOptions): Promise<StoryblokStoriesResult>;
|
package/dist/client.js
CHANGED
|
@@ -1,30 +1,82 @@
|
|
|
1
1
|
import StoryblokClient from 'storyblok-js-client';
|
|
2
2
|
import { getConfig } from './config';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Storyblok caps `by_uuids` at 100 ids per request. Beyond that the query
|
|
5
|
+
* string overflows and the CDN errors, so lists longer than this are split
|
|
6
|
+
* across requests and merged. Consumers should not have to know this.
|
|
7
|
+
*/
|
|
8
|
+
export const UUID_CHUNK_SIZE = 100;
|
|
9
|
+
/**
|
|
10
|
+
* One client per token. Draft and published use different tokens, so a
|
|
11
|
+
* single-slot cache would rebuild the client on every alternation — which a
|
|
12
|
+
* page rendering both preview and published content does constantly.
|
|
13
|
+
*/
|
|
14
|
+
const clients = new Map();
|
|
15
|
+
function clientFor(token) {
|
|
7
16
|
const cfg = getConfig();
|
|
17
|
+
// Keyed on everything the client is constructed from, so re-configuring with
|
|
18
|
+
// a different token or region cannot hand back a stale client.
|
|
19
|
+
const key = `${token}|${cfg.region ?? 'eu'}`;
|
|
20
|
+
const cached = clients.get(key);
|
|
21
|
+
if (cached)
|
|
22
|
+
return cached;
|
|
8
23
|
const client = new StoryblokClient({ accessToken: token, region: cfg.region });
|
|
9
|
-
|
|
24
|
+
clients.set(key, client);
|
|
10
25
|
return client;
|
|
11
26
|
}
|
|
27
|
+
/** Drop memoised clients. Needed when the config changes (tokens, region). */
|
|
28
|
+
export function resetClients() {
|
|
29
|
+
clients.clear();
|
|
30
|
+
}
|
|
12
31
|
function tokenFor(version) {
|
|
13
32
|
const cfg = getConfig();
|
|
14
33
|
return version === 'draft' ? cfg.previewToken : cfg.publicToken;
|
|
15
34
|
}
|
|
35
|
+
/** The version this request should read, unless the caller pins one. */
|
|
36
|
+
export async function resolveVersion(version) {
|
|
37
|
+
return version ?? getConfig().resolveVersion();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The configured client for a version — correct token, region and richtext
|
|
41
|
+
* resolver. Exported so consumers that render their own components never have
|
|
42
|
+
* to construct a client (and re-derive token selection) themselves.
|
|
43
|
+
*/
|
|
44
|
+
export async function getStoryblokClient(version) {
|
|
45
|
+
return clientFor(tokenFor(await resolveVersion(version)));
|
|
46
|
+
}
|
|
16
47
|
/** Render context backed by the SDK's richtext resolver. */
|
|
17
48
|
export function mapContext(version) {
|
|
18
|
-
const client =
|
|
49
|
+
const client = clientFor(tokenFor(version));
|
|
19
50
|
return {
|
|
20
|
-
renderRichText: (doc) => doc ? client.richTextResolver.render(doc) : '',
|
|
51
|
+
renderRichText: (doc) => (doc ? client.richTextResolver.render(doc) : ''),
|
|
21
52
|
};
|
|
22
53
|
}
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Cache policy, in one place.
|
|
56
|
+
*
|
|
57
|
+
* Draft must never be cached — the Visual Editor would show stale content and
|
|
58
|
+
* the editor would think their change was lost. Published content is cached for
|
|
59
|
+
* `revalidate` seconds (from config, or per call).
|
|
60
|
+
*/
|
|
61
|
+
export function fetchOptionsFor(version, revalidate) {
|
|
62
|
+
if (version === 'draft')
|
|
63
|
+
return { cache: 'no-store' };
|
|
64
|
+
const seconds = revalidate ?? getConfig().revalidate;
|
|
65
|
+
// `next` is Next.js's RequestInit extension; harmless on other runtimes.
|
|
66
|
+
return seconds != null ? { next: { revalidate: seconds } } : {};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Fetch a single story by slug. Returns null on 404.
|
|
70
|
+
*
|
|
71
|
+
* Pass `params.resolve_relations` to have Storyblok substitute referenced
|
|
72
|
+
* stories rather than returning bare uuids — the alternative is batch-fetching
|
|
73
|
+
* them yourself afterwards.
|
|
74
|
+
*/
|
|
75
|
+
export async function fetchStory(slug, version, opts = {}) {
|
|
76
|
+
const v = await resolveVersion(version ?? opts.version);
|
|
77
|
+
const client = clientFor(tokenFor(v));
|
|
26
78
|
try {
|
|
27
|
-
const res = await client.get(`cdn/stories/${slug}`,
|
|
79
|
+
const res = await client.get(`cdn/stories/${slug}`, toStoryParams(opts.params ?? {}, v), fetchOptionsFor(v, opts.revalidate));
|
|
28
80
|
return res.data.story;
|
|
29
81
|
}
|
|
30
82
|
catch (err) {
|
|
@@ -33,6 +85,124 @@ export async function fetchStory(slug, version) {
|
|
|
33
85
|
throw err;
|
|
34
86
|
}
|
|
35
87
|
}
|
|
88
|
+
/** Relation/link expansion, shared by single-story and list fetches. */
|
|
89
|
+
function applyResolveParams(out, params) {
|
|
90
|
+
// The SDK accepts a comma-joined string or an array; join so the query string
|
|
91
|
+
// is identical either way and easier to assert on.
|
|
92
|
+
if (params.resolve_relations?.length)
|
|
93
|
+
out.resolve_relations = params.resolve_relations.join(',');
|
|
94
|
+
if (params.resolve_links)
|
|
95
|
+
out.resolve_links = params.resolve_links;
|
|
96
|
+
if (params.resolve_links_level)
|
|
97
|
+
out.resolve_links_level = params.resolve_links_level;
|
|
98
|
+
if (params.language)
|
|
99
|
+
out.language = params.language;
|
|
100
|
+
if (params.fallback_lang)
|
|
101
|
+
out.fallback_lang = params.fallback_lang;
|
|
102
|
+
}
|
|
103
|
+
/** Translate the public params into the SDK's wire shape. */
|
|
104
|
+
export function toStoriesParams(params, version) {
|
|
105
|
+
const out = { version };
|
|
106
|
+
if (params.content_type)
|
|
107
|
+
out.content_type = params.content_type;
|
|
108
|
+
if (params.starts_with)
|
|
109
|
+
out.starts_with = params.starts_with;
|
|
110
|
+
if (params.by_uuids?.length)
|
|
111
|
+
out.by_uuids = params.by_uuids.join(',');
|
|
112
|
+
if (params.by_uuids_ordered?.length)
|
|
113
|
+
out.by_uuids_ordered = params.by_uuids_ordered.join(',');
|
|
114
|
+
if (params.filter_query)
|
|
115
|
+
out.filter_query = params.filter_query;
|
|
116
|
+
if (params.sort_by)
|
|
117
|
+
out.sort_by = params.sort_by;
|
|
118
|
+
if (params.search_term)
|
|
119
|
+
out.search_term = params.search_term;
|
|
120
|
+
if (params.excluding_slugs)
|
|
121
|
+
out.excluding_slugs = params.excluding_slugs;
|
|
122
|
+
if (params.per_page != null)
|
|
123
|
+
out.per_page = params.per_page;
|
|
124
|
+
if (params.page != null)
|
|
125
|
+
out.page = params.page;
|
|
126
|
+
applyResolveParams(out, params);
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
/** Translate single-story params into the SDK's wire shape. */
|
|
130
|
+
export function toStoryParams(params, version) {
|
|
131
|
+
const out = { version };
|
|
132
|
+
applyResolveParams(out, params);
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
function chunk(xs, size) {
|
|
136
|
+
const out = [];
|
|
137
|
+
for (let i = 0; i < xs.length; i += size)
|
|
138
|
+
out.push(xs.slice(i, i + size));
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
/** Restore the caller's order; ids with no story (deleted, unpublished) drop out. */
|
|
142
|
+
function orderByUuids(stories, uuids) {
|
|
143
|
+
const byUuid = new Map(stories.map((s) => [s.uuid, s]));
|
|
144
|
+
return uuids.map((id) => byUuid.get(id)).filter((s) => Boolean(s));
|
|
145
|
+
}
|
|
146
|
+
async function fetchStoriesPage(params, version, revalidate) {
|
|
147
|
+
const client = clientFor(tokenFor(version));
|
|
148
|
+
const res = await client.get('cdn/stories', params, fetchOptionsFor(version, revalidate));
|
|
149
|
+
return {
|
|
150
|
+
stories: (res.data.stories ?? []),
|
|
151
|
+
total: res.total ?? 0,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Query the Content Delivery API for a list of stories.
|
|
156
|
+
*
|
|
157
|
+
* Returns raw stories — mapping into `CmsPage`/`CmsBlockNode` is opt-in via
|
|
158
|
+
* `mapStory`, so consumers rendering their own components keep the full blok
|
|
159
|
+
* tree (and `_editable`, which the Visual Editor needs).
|
|
160
|
+
*
|
|
161
|
+
* `by_uuids` / `by_uuids_ordered` longer than 100 are split and merged
|
|
162
|
+
* transparently; `by_uuids_ordered` keeps the caller's order across chunks.
|
|
163
|
+
*/
|
|
164
|
+
export async function fetchStories(params = {}, opts = {}) {
|
|
165
|
+
const version = await resolveVersion(opts.version);
|
|
166
|
+
const ordered = params.by_uuids_ordered;
|
|
167
|
+
const ids = ordered ?? params.by_uuids;
|
|
168
|
+
if (!ids?.length || ids.length <= UUID_CHUNK_SIZE) {
|
|
169
|
+
return fetchStoriesPage(toStoriesParams(params, version), version, opts.revalidate);
|
|
170
|
+
}
|
|
171
|
+
const key = ordered ? 'by_uuids_ordered' : 'by_uuids';
|
|
172
|
+
const pages = await Promise.all(chunk(ids, UUID_CHUNK_SIZE).map((slice) => fetchStoriesPage(toStoriesParams({ ...params, [key]: slice }, version), version, opts.revalidate)));
|
|
173
|
+
const stories = pages.flatMap((p) => p.stories);
|
|
174
|
+
return {
|
|
175
|
+
stories: ordered ? orderByUuids(stories, ordered) : stories,
|
|
176
|
+
total: stories.length,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
/** Storyblok's hard cap on a single page. */
|
|
180
|
+
const MAX_PER_PAGE = 100;
|
|
181
|
+
/**
|
|
182
|
+
* Every story matching the query, paging until the CDN is exhausted.
|
|
183
|
+
*
|
|
184
|
+
* `fetchStories` returns one page — fine for a capped list, wrong for "all
|
|
185
|
+
* recipes" once a space grows past `per_page`. Uuid queries are already
|
|
186
|
+
* complete (they chunk rather than page), so those short-circuit.
|
|
187
|
+
*/
|
|
188
|
+
export async function fetchAllStories(params = {}, opts = {}) {
|
|
189
|
+
if (params.by_uuids?.length || params.by_uuids_ordered?.length) {
|
|
190
|
+
return fetchStories(params, opts);
|
|
191
|
+
}
|
|
192
|
+
const perPage = Math.min(params.per_page ?? MAX_PER_PAGE, MAX_PER_PAGE);
|
|
193
|
+
const stories = [];
|
|
194
|
+
let total = 0;
|
|
195
|
+
for (let page = params.page ?? 1;; page += 1) {
|
|
196
|
+
const res = await fetchStories({ ...params, per_page: perPage, page }, opts);
|
|
197
|
+
stories.push(...res.stories);
|
|
198
|
+
total = res.total;
|
|
199
|
+
// Stop on a short page rather than trusting `total` alone — a story
|
|
200
|
+
// unpublished mid-walk would otherwise loop forever.
|
|
201
|
+
if (res.stories.length < perPage || stories.length >= total)
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
return { stories, total: total || stories.length };
|
|
205
|
+
}
|
|
36
206
|
function isNotFound(err) {
|
|
37
207
|
const status = err?.status ??
|
|
38
208
|
err?.response?.status;
|
package/dist/config.d.ts
CHANGED
|
@@ -10,6 +10,11 @@ export interface StoryblokConfig {
|
|
|
10
10
|
region?: 'eu' | 'us' | 'ap' | 'ca' | 'cn';
|
|
11
11
|
/** Fallback version when no versionGetter is supplied. Defaults to 'published'. */
|
|
12
12
|
defaultVersion?: StoryblokVersion;
|
|
13
|
+
/**
|
|
14
|
+
* Cache lifetime in seconds for PUBLISHED reads. Draft is never cached.
|
|
15
|
+
* Omit to leave caching to the framework's default.
|
|
16
|
+
*/
|
|
17
|
+
revalidate?: number;
|
|
13
18
|
/**
|
|
14
19
|
* Per-request version resolver supplied by the app (reads Next.js draftMode).
|
|
15
20
|
* Kept here so the framework-agnostic package never imports next/headers.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { storyblokAdapter } from './adapter';
|
|
2
2
|
export { setConfig, getConfig } from './config';
|
|
3
3
|
export type { StoryblokConfig, StoryblokVersion } from './config';
|
|
4
|
-
export { blockCatalog, type BlockDefinition } from './blocks/catalog';
|
|
5
4
|
export { inertStoryblokAdapter } from './inert';
|
|
5
|
+
export { getStoryblokClient, resolveVersion, fetchStory, fetchStories, fetchAllStories, mapContext, fetchOptionsFor, toStoriesParams, toStoryParams, UUID_CHUNK_SIZE, resetClients, type FetchOptions, type FetchStoryOptions, } from './client';
|
|
6
|
+
export type { FetchStoriesParams, ResolveParams, StoryblokAsset, StoryblokBlok, StoryblokLink, StoryblokPageContent, StoryblokStoriesResult, StoryblokStory, } from './types';
|
|
7
|
+
export { mapStory } from './mappers/story';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export { storyblokAdapter } from './adapter';
|
|
2
2
|
export { setConfig, getConfig } from './config';
|
|
3
|
-
export { blockCatalog } from './blocks/catalog';
|
|
4
3
|
export { inertStoryblokAdapter } from './inert';
|
|
4
|
+
// ── Transport ─────────────────────────────────────────────────────────────
|
|
5
|
+
// The configured client and the raw fetches, for consumers that render their
|
|
6
|
+
// own components. Do NOT build your own StoryblokClient — token-per-version,
|
|
7
|
+
// region and cache policy live here.
|
|
8
|
+
export { getStoryblokClient, resolveVersion, fetchStory, fetchStories, fetchAllStories, mapContext, fetchOptionsFor, toStoriesParams, toStoryParams, UUID_CHUNK_SIZE, resetClients, } from './client';
|
|
9
|
+
// ── Normalisation (opt-in) ────────────────────────────────────────────────
|
|
10
|
+
// Map a raw story into cobrastyle's CmsPage/CmsBlockNode. Only needed by
|
|
11
|
+
// consumers using the shared block components.
|
|
12
|
+
export { mapStory } from './mappers/story';
|
package/dist/types.d.ts
CHANGED
|
@@ -35,3 +35,49 @@ export interface StoryblokStory {
|
|
|
35
35
|
export interface StoryblokStoryResponse {
|
|
36
36
|
story: StoryblokStory;
|
|
37
37
|
}
|
|
38
|
+
export interface StoryblokStoriesResponse {
|
|
39
|
+
stories: StoryblokStory[];
|
|
40
|
+
}
|
|
41
|
+
/** A page of stories plus the total the CDN reports. */
|
|
42
|
+
export interface StoryblokStoriesResult {
|
|
43
|
+
stories: StoryblokStory[];
|
|
44
|
+
total: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Relation and link expansion, shared by single-story and list fetches.
|
|
48
|
+
*
|
|
49
|
+
* `resolve_relations` is how you avoid hand-rolling a relation resolver:
|
|
50
|
+
* Storyblok substitutes the referenced stories into the response instead of
|
|
51
|
+
* leaving bare uuids, so a consumer does not have to batch-fetch them itself.
|
|
52
|
+
*/
|
|
53
|
+
export interface ResolveParams {
|
|
54
|
+
/** Dot paths to expand, e.g. ['recipe.ingredients', 'page.author']. */
|
|
55
|
+
resolve_relations?: string[];
|
|
56
|
+
/** How story links in multilink/richtext fields are expanded. */
|
|
57
|
+
resolve_links?: 'url' | 'story' | 'link';
|
|
58
|
+
/** Depth for `resolve_links`. */
|
|
59
|
+
resolve_links_level?: 1 | 2;
|
|
60
|
+
/** Space language, for translated content. */
|
|
61
|
+
language?: string;
|
|
62
|
+
/** Fallback language when a translation is missing. */
|
|
63
|
+
fallback_lang?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The Content Delivery query surface, in the shapes a consumer thinks in —
|
|
67
|
+
* uuid lists are arrays here and joined internally, and chunked past 100.
|
|
68
|
+
*/
|
|
69
|
+
export interface FetchStoriesParams extends ResolveParams {
|
|
70
|
+
content_type?: string;
|
|
71
|
+
starts_with?: string;
|
|
72
|
+
by_uuids?: string[];
|
|
73
|
+
/** Same as `by_uuids`, but the response keeps this order. */
|
|
74
|
+
by_uuids_ordered?: string[];
|
|
75
|
+
/** e.g. `{ tags: { in_array: 'vegan' } }` */
|
|
76
|
+
filter_query?: Record<string, unknown>;
|
|
77
|
+
sort_by?: string;
|
|
78
|
+
search_term?: string;
|
|
79
|
+
excluding_slugs?: string;
|
|
80
|
+
/** Storyblok caps this at 100. */
|
|
81
|
+
per_page?: number;
|
|
82
|
+
page?: number;
|
|
83
|
+
}
|