storyblok / gatsby-source-storyblok

Gatsby source plugin for building websites using the Storyblok headless CMS as a data source.
MIT License
43 stars 35 forks source link

Build error #443

Closed adamwaern closed 11 months ago

adamwaern commented 1 year ago

Describe the issue you're facing

When running npm run buildi get a build error and it seems to be related to the includeLinks option which is set to truein this case.

Reproduction

localhost

Steps to reproduce

Set includeLinks: true in options and run npm run build

System Info

System:
    OS: macOS 11.6
    CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
    Memory: 103.37 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 18.16.0 - ~/.nvm/versions/node/v18.16.0/bin/node
    npm: 9.5.1 - ~/.nvm/versions/node/v18.16.0/bin/npm
  Browsers:
    Chrome: 116.0.5845.187
    Safari: 14.1.2

Used Package Manager

npm

Error logs (Optional)

ERROR #11321 API.NODE.EXECUTION

"gatsby-source-storyblok" threw an error while running the sourceNodes lifecycle:

res.data[type].forEach is not a function

62 | 63 | if (options.includeLinks === true) {

64 | await Sync.getAll('links', { | ^ 65 | node: 'StoryblokLink', 66 | params: getStoryParams('', options), 67 | });

File: node_modules/gatsby-source-storyblok/gatsby-node.js:64:5

TypeError: res.data[type].forEach is not a function

not finished source and transform nodes - 2.611s

Validations

tim-c-refactored commented 1 year ago

Also had this error happen on a site today. The space was a clone of an existing Gatsby 4 site that still works but the cloned site throws this error.

kile-lindgren commented 1 year ago

This seems to be related to change on how newer access tokens are treated by the links API endpoint. It use to not be paginated, but it seems like on newer API tokens, its paginated by default. This results in the while loop being executed, when it wasn't use to.

I adjusted locally clone to convert the response into an array in the while loop which appears to have resolved the issue.

Here is the updated function:

  async getAll(type, options) {
    if(type == "links"){
      options.params["paginated"] = 1;
    }

    let page = 1;
    let res = await this.getPage(type, page, options);
    let all =
      res.data[type].constructor === Object ? Object.values(res.data[type]) : res.data[type];
    let lastPage = Math.ceil(res.total / 25);

    while (page < lastPage) {
      page++;
      res = await this.getPage(type, page, options);

      if(res.data[type].constructor === Object){
        Object.values(res.data[type]).forEach((item) => {
          all.push(item);
        });
      }
      else{
        res.data[type].forEach((item) => {
          all.push(item);
        });
      }
    }

    all.forEach((item) => {
      if (options.process) {
        options.process(item);
      }
      this.createNode(options.node, item, options.typePrefix);
    });

    return all;
  },
Patrickodey360coder commented 12 months ago

Hi, thanks for reporting this. We responded on Discord and here is the solution we proposed

schabibi1 commented 11 months ago

@kile-lindgren @adamwaern Please feel free to re-open this issue when you still see the similar case you experienced from what you reported after you try the approach we suggested.

kile-lindgren commented 11 months ago

This issues still exists in your code.

https://github.com/storyblok/gatsby-source-storyblok/blob/master/lib/src/sync.js

On line 86 when you instantiate the variable all and initially assign it to the first page of results, you correctly check to see if it's an object (links API) or an array (stories API). However on line 93 in the while loop you fail to check to see if the next page of results is an array or an object and just blindly call forEach. Since objects don't have a forEach method an error gets thrown.

In my posted code, I correctly handle the difference types being returned:

if(res.data[type].constructor === Object){ Object.values(res.data[type]).forEach((item) => { all.push(item); }); } else{ res.data[type].forEach((item) => { all.push(item); }); }

You need to still do something similar.

schabibi1 commented 11 months ago

@kile-lindgren Can you help us to reproduce by sending reproduction links? We tested your code and we get your point from what you proposed above. But it'll help us to investigate quicker and more efficiently if you can give us reproduction as we don't know so far if what we're testing is the same as what you experienced.