Skip to content
This repository was archived by the owner on Jun 24, 2025. It is now read-only.

Commit 3adfcb5

Browse files
authored
Merge pull request #984 from storyblok/fix/resolve-more-than-50-relations
fix: add all relations back to the response when resolving more than 50
2 parents f0d9969 + 60f4794 commit 3adfcb5

File tree

4 files changed

+124
-4
lines changed

4 files changed

+124
-4
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "storyblok-js-client",
3-
"version": "6.10.6",
4-
"packageManager": "pnpm@10.2.0",
3+
"version": "6.10.11",
4+
"packageManager": "pnpm@10.10.0",
55
"description": "Universal JavaScript SDK for Storyblok's API",
66
"author": "Alexander Feiglstorfer <[email protected]>",
77
"license": "MIT",

src/index.test.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,119 @@ describe('storyblokClient', () => {
660660
});
661661

662662
describe('relation resolution', () => {
663+
it('should resolve more than 50 relations correctly', async () => {
664+
// Create 60 UUIDs to exceed the 50 relation limit
665+
const TEST_UUIDS = Array.from({ length: 60 }, (_, i) => `test-uuid-${i}`);
666+
667+
// Mock story with multiple relation fields
668+
const mockResponse = {
669+
data: {
670+
story: {
671+
content: {
672+
_uid: 'root-uid',
673+
component: 'page',
674+
items: TEST_UUIDS.slice(0, 30), // First 30 UUIDs
675+
otherItems: TEST_UUIDS.slice(30), // Next 30 UUIDs
676+
},
677+
},
678+
// Include rel_uuids but not rels to simulate API behavior
679+
rel_uuids: TEST_UUIDS,
680+
},
681+
headers: {},
682+
status: 200,
683+
statusText: 'OK',
684+
};
685+
686+
// Create first chunk response (first 50 relations)
687+
const mockFirstChunkResponse = {
688+
data: {
689+
stories: TEST_UUIDS.slice(0, 50).map(uuid => ({
690+
uuid,
691+
name: `Story ${uuid}`,
692+
content: { component: 'test-component', _uid: uuid },
693+
full_slug: `stories/${uuid}`,
694+
})),
695+
},
696+
headers: {},
697+
status: 200,
698+
statusText: 'OK',
699+
};
700+
701+
// Create second chunk response (remaining relations)
702+
const mockSecondChunkResponse = {
703+
data: {
704+
stories: TEST_UUIDS.slice(50).map(uuid => ({
705+
uuid,
706+
name: `Story ${uuid}`,
707+
content: { component: 'test-component', _uid: uuid },
708+
full_slug: `stories/${uuid}`,
709+
})),
710+
},
711+
headers: {},
712+
status: 200,
713+
statusText: 'OK',
714+
};
715+
716+
// Setup the mock client's get method
717+
const mockGet = vi.fn()
718+
.mockImplementationOnce(() => Promise.resolve(mockResponse))
719+
.mockImplementationOnce(() => Promise.resolve(mockFirstChunkResponse))
720+
.mockImplementationOnce(() => Promise.resolve(mockSecondChunkResponse));
721+
722+
// Replace the client's fetch instance
723+
client.client = {
724+
get: mockGet,
725+
post: vi.fn(),
726+
setFetchOptions: vi.fn(),
727+
};
728+
729+
const result = await client.get('cdn/stories/test', {
730+
resolve_relations: ['page.items', 'page.otherItems'],
731+
});
732+
733+
// Ensure all relations were resolved
734+
const story = result.data.story;
735+
expect(story.content.items).toBeInstanceOf(Array);
736+
expect(story.content.items.length).toBe(30);
737+
expect(story.content.otherItems).toBeInstanceOf(Array);
738+
expect(story.content.otherItems.length).toBe(30);
739+
740+
// Check that first and last items from each array were properly resolved
741+
// First array items should be objects, not UUIDs
742+
expect(typeof story.content.items[0]).toBe('object');
743+
expect(story.content.items[0].uuid).toBe('test-uuid-0');
744+
expect(story.content.items[0].name).toBe('Story test-uuid-0');
745+
expect(story.content.items[0].content.component).toBe('test-component');
746+
747+
// Last item in first array
748+
expect(typeof story.content.items[29]).toBe('object');
749+
expect(story.content.items[29].uuid).toBe('test-uuid-29');
750+
751+
// First item in second array
752+
expect(typeof story.content.otherItems[0]).toBe('object');
753+
expect(story.content.otherItems[0].uuid).toBe('test-uuid-30');
754+
755+
// Last item in second array
756+
expect(typeof story.content.otherItems[29]).toBe('object');
757+
expect(story.content.otherItems[29].uuid).toBe('test-uuid-59');
758+
759+
// Ensure rel_uuids was removed after resolution
760+
expect(result.data.rel_uuids).toBeUndefined();
761+
762+
// Verify the API was called correctly for chunking
763+
expect(mockGet).toHaveBeenCalledTimes(3);
764+
765+
// Check the parameters in second call (first chunk)
766+
const firstChunkParams = mockGet.mock.calls[1][1];
767+
expect(firstChunkParams).toHaveProperty('by_uuids');
768+
expect(firstChunkParams.by_uuids).toContain('test-uuid-0');
769+
770+
// Check the parameters in third call (second chunk)
771+
const secondChunkParams = mockGet.mock.calls[2][1];
772+
expect(secondChunkParams).toHaveProperty('by_uuids');
773+
expect(secondChunkParams.by_uuids).toContain('test-uuid-50');
774+
});
775+
663776
it('should resolve nested relations within content blocks', async () => {
664777
const TEST_UUID = 'this-is-a-test-uuid';
665778

src/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
ICacheProvider,
1010
IMemoryType,
1111
ISbCache,
12+
ISbComponentType,
1213
ISbConfig,
1314
ISbContentMangmntAPI,
1415
ISbCustomFetch,
@@ -567,7 +568,7 @@ class Storyblok {
567568
params: ISbStoriesParams,
568569
resolveId: string,
569570
): Promise<void> {
570-
let relations = [];
571+
let relations: ISbStoryData<ISbComponentType<string> & { [index: string]: any }>[] = [];
571572

572573
if (responseData.rel_uuids) {
573574
const relSize = responseData.rel_uuids.length;
@@ -593,6 +594,12 @@ class Storyblok {
593594
relations.push(rel);
594595
});
595596
}
597+
598+
// Replace rel_uuids with the fully resolved stories and clear it
599+
if (relations.length > 0) {
600+
responseData.rels = relations;
601+
delete responseData.rel_uuids;
602+
}
596603
}
597604
else {
598605
relations = responseData.rels;

src/interfaces.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ export interface Queue<T> {
389389
export interface ISbResponseData {
390390
link_uuids: string[];
391391
links: string[];
392-
rel_uuids: string[];
392+
rel_uuids?: string[];
393393
rels: any;
394394
story: ISbStoryData;
395395
stories: Array<ISbStoryData>;

0 commit comments

Comments
 (0)